Merge pull request #58 from Fenrock/felix6337

[FELIX-6337] Maven Bundle Plugin generates incorrect Provide-Capability
diff --git a/.gitignore b/.gitignore
index 3f1f936..7692143 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@
 .DS_Store
 /.metadata/
 /workspace/
+.vscode
diff --git a/cm.json/pom.xml b/cm.json/pom.xml
index f706c55..09e324e 100644
--- a/cm.json/pom.xml
+++ b/cm.json/pom.xml
@@ -33,13 +33,13 @@
     <description>
         Support for OSGi configurations specified in JSON documents.
     </description>
-    <version>1.0.3-SNAPSHOT</version>
+    <version>1.0.7-SNAPSHOT</version>
 
     <scm>
         <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
         <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
         <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git;f=cm.json</url>
-    <tag>HEAD</tag>
+    <tag>org.apache.felix.cm.json-1.0.6</tag>
   </scm>
 
     <properties>
@@ -60,6 +60,14 @@
                         </Bundle-SymbolicName>
                     </instructions>
                 </configuration>
+                <executions>
+		    <execution>
+		        <id>baseline</id>
+		        <goals>
+		            <goal>baseline</goal>
+		        </goals>
+		    </execution>
+		</executions>
             </plugin>
             <plugin>
                 <groupId>org.apache.rat</groupId>
diff --git a/cm.json/src/main/java/org/apache/felix/cm/json/Configurations.java b/cm.json/src/main/java/org/apache/felix/cm/json/Configurations.java
index 8bdd1bd..ba66b31 100644
--- a/cm.json/src/main/java/org/apache/felix/cm/json/Configurations.java
+++ b/cm.json/src/main/java/org/apache/felix/cm/json/Configurations.java
@@ -72,7 +72,7 @@
 
     /**
      * Create a new map for configuration properties The returned map keeps the
-     * order of properties added.
+     * order of properties added and is using case-insensitive keys.
      *
      * @return A new map
      */
diff --git a/cm.json/src/main/java/org/apache/felix/cm/json/impl/ConfigurationReaderImpl.java b/cm.json/src/main/java/org/apache/felix/cm/json/impl/ConfigurationReaderImpl.java
index 286e93e..91a0848 100644
--- a/cm.json/src/main/java/org/apache/felix/cm/json/impl/ConfigurationReaderImpl.java
+++ b/cm.json/src/main/java/org/apache/felix/cm/json/impl/ConfigurationReaderImpl.java
@@ -269,7 +269,11 @@
             if ( keyInfo.isInternal ) {
                 final Object value = JsonSupport.convertToObject(propEntry.getValue());
                 if ( propertyHandler == null ) {
-                    properties.put(keyInfo.propertyKey, value);
+                    if ( properties.put(keyInfo.propertyKey, value) != null ) {
+                        throwIOException("PID ".concat(pid)
+                        .concat(" : Duplicate property (properties are case-insensitive) : ")
+                        .concat(keyInfo.propertyKey));
+                    }
                 } else {
                     propertyHandler.handleConfiguratorProperty(pid, keyInfo.propertyKey, value);
                 }
@@ -310,7 +314,11 @@
                 if ( convertedVal == null ) {
                     valid = false;
                 } else {
-                    properties.put(keyInfo.propertyKey, convertedVal);
+                    if ( properties.put(keyInfo.propertyKey, convertedVal) != null ) {
+                        throwIOException("PID ".concat(pid)
+                        .concat(" : Duplicate property (properties are case-insensitive) : ")
+                        .concat(keyInfo.propertyKey));
+                    }
                 }
             }
         }
diff --git a/cm.json/src/main/java/org/apache/felix/cm/json/impl/OrderedDictionary.java b/cm.json/src/main/java/org/apache/felix/cm/json/impl/OrderedDictionary.java
index 5c3f8b4..f2cc16a 100644
--- a/cm.json/src/main/java/org/apache/felix/cm/json/impl/OrderedDictionary.java
+++ b/cm.json/src/main/java/org/apache/felix/cm/json/impl/OrderedDictionary.java
@@ -19,6 +19,7 @@
 package org.apache.felix.cm.json.impl;
 
 import java.io.Serializable;
+import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -26,6 +27,7 @@
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -38,25 +40,7 @@
 
     private static final long serialVersionUID = -525111601546803041L;
 
-    private static class EnumarationImpl<E> implements Enumeration<E> {
-        private final Iterator<E> iterator;
-
-        public EnumarationImpl(Iterator<E> iterator) {
-            this.iterator = iterator;
-        }
-
-        @Override
-        public boolean hasMoreElements() {
-            return iterator.hasNext();
-        }
-
-        @Override
-        public E nextElement() {
-            return iterator.next();
-        }
-    }
-
-    private Map<String, Object> map = Collections.synchronizedMap(new LinkedHashMap<String, Object>());
+    private Map<CaseInsensitiveKey, Object> map = Collections.synchronizedMap(new LinkedHashMap<>());
 
     @Override
     public int size() {
@@ -69,48 +53,58 @@
     }
 
     @Override
-    public boolean containsKey(Object key) {
-        return map.containsKey(key);
+    public boolean containsKey(final Object key) {
+        if ( key == null ) {
+            return false;
+        }
+        return map.containsKey(new CaseInsensitiveKey(key.toString()));
     }
 
     @Override
-    public boolean containsValue(Object value) {
+    public boolean containsValue(final Object value) {
         return map.containsValue(value);
     }
 
     @Override
     public Enumeration<String> keys() {
-        return new EnumarationImpl<>(map.keySet().iterator());
+        return new KeyEnumeration(map.keySet().iterator());
     }
 
     @Override
     public Enumeration<Object> elements() {
-        return new EnumarationImpl<>(map.values().iterator());
+        return Collections.enumeration(map.values());
     }
 
     @Override
-    public Object get(Object key) {
-        return map.get(key);
+    public Object get(final Object key) {
+        if ( key == null ) {
+            return null;
+        }
+        return map.get(new CaseInsensitiveKey(key.toString()));
     }
 
     @Override
-    public Object put(String key, Object value) {
+    public Object put(final String key, final Object value) {
         // Make sure the value is not null
         if (value == null) {
             throw new NullPointerException();
         }
-
-        return map.put(key, value);
+        final CaseInsensitiveKey k = new CaseInsensitiveKey(key);
+        final Object oldValue = this.map.remove(k);
+        this.map.put(k, value);
+        return oldValue;
     }
 
     @Override
-    public Object remove(Object key) {
-        return map.remove(key);
+    public Object remove(final Object key) {
+        return map.remove(new CaseInsensitiveKey(key.toString()));
     }
 
     @Override
-    public void putAll(Map<? extends String, ? extends Object> m) {
-        map.putAll(m);
+    public void putAll(final Map<? extends String, ? extends Object> m) {
+        for(final Map.Entry<? extends String, ? extends Object> e : m.entrySet()) {
+            this.put(e.getKey(), e.getValue());
+        }
     }
 
     @Override
@@ -120,21 +114,21 @@
 
     @Override
     public Set<String> keySet() {
-        return map.keySet();
+        return new KeySet();
     }
 
     @Override
     public Collection<Object> values() {
-        return map.values();
+        return this.map.values();
     }
 
     @Override
     public Set<java.util.Map.Entry<String, Object>> entrySet() {
-        return map.entrySet();
+        return new EntrySet();
     }
 
     @Override
-    public boolean equals(Object o) {
+    public boolean equals(final Object o) {
         return map.equals(o);
     }
 
@@ -142,4 +136,210 @@
     public int hashCode() {
         return map.hashCode();
     }
+
+    private static final class CaseInsensitiveKey implements Serializable {
+
+        private static final long serialVersionUID = 7040882564605268453L;
+
+        private final String value;
+
+        private final int hashCode;
+
+        CaseInsensitiveKey(final String v) {
+            this.value = v;
+            this.hashCode = v.toUpperCase().hashCode();
+        }
+
+		@Override
+		public int hashCode() {
+			return this.hashCode;
+		}
+
+		@Override
+		public boolean equals(final Object obj) {
+			if (this == obj) {
+                return true;
+            }
+			if (!(obj instanceof CaseInsensitiveKey)) {
+				return false;
+            }
+            final CaseInsensitiveKey other = (CaseInsensitiveKey) obj;
+            if ( value == null ) {
+                if ( other.value == null ) {
+                    return true;
+                }
+                return false;
+            }
+            if ( other.value == null ) {
+                return false;
+            }
+            return value.equalsIgnoreCase(other.value);
+		}
+    }
+
+    private static class KeyEnumeration implements Enumeration<String> {
+
+        private final Iterator<CaseInsensitiveKey> iterator;
+
+        KeyEnumeration(final Iterator<CaseInsensitiveKey> iterator) {
+            this.iterator = iterator;
+        }
+
+        @Override
+        public boolean hasMoreElements() {
+            return iterator.hasNext();
+        }
+
+        @Override
+        public String nextElement() {
+            return iterator.next().value;
+        }
+    }
+
+
+    private final class KeySet extends AbstractSet<String> {
+
+		@Override
+		public int size() {
+			return OrderedDictionary.this.size();
+		}
+
+		@Override
+		public boolean isEmpty() {
+			return OrderedDictionary.this.isEmpty();
+		}
+
+		@Override
+		public boolean contains(final Object o) {
+			return OrderedDictionary.this.containsKey(o);
+		}
+
+		@Override
+		public Iterator<String> iterator() {
+			return new KeyIterator(OrderedDictionary.this.map.keySet());
+		}
+
+		@Override
+		public boolean remove(final Object o) {
+			return OrderedDictionary.this.remove(o) != null;
+		}
+
+		@Override
+		public void clear() {
+			OrderedDictionary.this.clear();
+		}
+	}
+
+	private static final class KeyIterator implements Iterator<String> {
+
+        private final Iterator<CaseInsensitiveKey> i;
+
+		KeyIterator(final Collection<CaseInsensitiveKey> c) {
+			this.i = c.iterator();
+		}
+
+		@Override
+		public boolean hasNext() {
+			return i.hasNext();
+		}
+
+		@Override
+		public String next() {
+			final CaseInsensitiveKey k = i.next();
+			return k.value;
+		}
+
+		@Override
+		public void remove() {
+			i.remove();
+		}
+	}
+
+	private final class EntrySet extends AbstractSet<Map.Entry<String, Object>> {
+
+		@Override
+		public int size() {
+			return OrderedDictionary.this.size();
+		}
+
+		@Override
+		public boolean isEmpty() {
+			return OrderedDictionary.this.isEmpty();
+		}
+
+		@Override
+		public Iterator<Map.Entry<String, Object>> iterator() {
+			return new EntryIterator(OrderedDictionary.this.map.entrySet());
+		}
+
+		@Override
+		public void clear() {
+			OrderedDictionary.this.clear();
+		}
+	}
+
+	private static final class EntryIterator implements Iterator<Map.Entry<String, Object>> {
+
+        private final Iterator<Map.Entry<CaseInsensitiveKey, Object>> i;
+
+		EntryIterator(final Collection<Map.Entry<CaseInsensitiveKey, Object>> c) {
+			this.i = c.iterator();
+		}
+
+		@Override
+		public boolean hasNext() {
+			return i.hasNext();
+		}
+
+		@Override
+		public Map.Entry<String, Object> next() {
+			return new CaseInsentiveEntry(i.next());
+		}
+
+		@Override
+		public void remove() {
+			i.remove();
+		}
+	}
+
+	private static final class CaseInsentiveEntry implements Map.Entry<String, Object> {
+
+        private final Map.Entry<CaseInsensitiveKey, Object> entry;
+
+		CaseInsentiveEntry(final Map.Entry<CaseInsensitiveKey, Object> entry) {
+			this.entry = entry;
+		}
+
+		@Override
+		public String getKey() {
+			return entry.getKey().value;
+		}
+
+		@Override
+		public Object getValue() {
+			return entry.getValue();
+		}
+
+		@Override
+		public Object setValue(final Object value) {
+			return entry.setValue(value);
+		}
+
+		@Override
+		public int hashCode() {
+            return entry.hashCode();
+		}
+
+		@Override
+		public boolean equals(final Object obj) {
+			if (obj instanceof CaseInsentiveEntry) {
+                final CaseInsentiveEntry other = (CaseInsentiveEntry) obj;
+                return Objects.equals(other.entry.getKey(), this.entry.getKey()) && Objects.equals(other.entry.getValue(), this.entry.getValue());
+			} else if ( obj instanceof Map.Entry ) {
+                final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
+                return Objects.equals(other.getKey(), this.entry.getKey()) && Objects.equals(other.getValue(), this.entry.getValue());
+            }
+			return false;
+		}
+	}
 }
diff --git a/cm.json/src/main/java/org/apache/felix/cm/json/package-info.java b/cm.json/src/main/java/org/apache/felix/cm/json/package-info.java
index 4f9f76a..92e5b56 100644
--- a/cm.json/src/main/java/org/apache/felix/cm/json/package-info.java
+++ b/cm.json/src/main/java/org/apache/felix/cm/json/package-info.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-@Version("1.0.0")
+@Version("1.0.2")
 package org.apache.felix.cm.json;
 
 import org.osgi.annotation.versioning.Version;
\ No newline at end of file
diff --git a/cm.json/src/test/java/org/apache/felix/cm/json/impl/ConfigurationReaderImplTest.java b/cm.json/src/test/java/org/apache/felix/cm/json/impl/ConfigurationReaderImplTest.java
index 91162b3..37e8f8d 100644
--- a/cm.json/src/test/java/org/apache/felix/cm/json/impl/ConfigurationReaderImplTest.java
+++ b/cm.json/src/test/java/org/apache/felix/cm/json/impl/ConfigurationReaderImplTest.java
@@ -106,4 +106,13 @@
             assertTrue(ioe.getCause() instanceof JsonException);
         }
     }
+
+    @Test(expected = IOException.class)
+    public void testReadSingleConfigurationDuplicateKeys() throws IOException {
+        final ConfigurationReaderImpl cfgReader = new ConfigurationReaderImpl();
+        try (final InputStream jsonStream = this.getClass().getResourceAsStream("/configs/single-duplicatekeys.json");
+                final Reader jsonReader = new InputStreamReader(jsonStream, StandardCharsets.UTF_8)) {
+            cfgReader.build(jsonReader).readConfiguration();
+        }
+    }
 }
diff --git a/cm.json/src/test/java/org/apache/felix/cm/json/impl/OrderedDictionaryTest.java b/cm.json/src/test/java/org/apache/felix/cm/json/impl/OrderedDictionaryTest.java
new file mode 100644
index 0000000..4085ed8
--- /dev/null
+++ b/cm.json/src/test/java/org/apache/felix/cm/json/impl/OrderedDictionaryTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.felix.cm.json.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.file.Files;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Test;
+
+public class OrderedDictionaryTest {
+
+    @Test public void testKeys() {
+        final Map<String, Object> map = new OrderedDictionary();
+        assertNull(map.put("hello", "helloV"));
+        assertNull(map.put("world", "worldV"));
+
+        assertEquals(2, map.size());
+        assertEquals(2, map.values().size());
+        assertTrue(map.values().contains("helloV"));
+        assertTrue(map.values().contains("worldV"));
+
+        assertEquals(2, map.entrySet().size());
+        final Map<String, Object> m = map.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
+        assertEquals("helloV", m.get("hello"));
+        assertEquals("worldV", m.get("world"));
+
+        Set<String> keys = new HashSet<>(map.keySet());
+        assertEquals(2, keys.size());
+        assertTrue(keys.contains("hello"));
+        assertTrue(keys.contains("world"));
+
+        assertEquals("helloV", map.get("hello"));
+        assertEquals("worldV", map.get("world"));
+        assertNull(map.get("foo"));
+
+        assertEquals("helloV", map.get("HELLO"));
+        assertEquals("worldV", map.get("WORLD"));
+
+        assertEquals("helloV", map.put("heLLo", "bar"));
+        assertEquals(2, map.size());
+
+        keys = new HashSet<>(map.keySet());
+        assertEquals(2, keys.size());
+        assertTrue(keys.contains("heLLo"));
+        assertTrue(keys.contains("world"));
+
+        assertEquals("bar", map.get("hello"));
+        assertEquals("worldV", map.get("world"));
+
+        assertEquals("bar", map.remove("HellO"));
+        assertEquals("worldV", map.remove("WoRlD"));
+        assertTrue(map.isEmpty());
+    }
+
+    @Test public void testClear() {
+        final Map<String, Object> map = new OrderedDictionary();
+        map.put("hello", "hello");
+        map.put("world", "world");
+
+        map.clear();
+        assertTrue(map.isEmpty());
+        assertEquals(0, map.size());
+        assertTrue(map.values().isEmpty());
+        assertTrue(map.keySet().isEmpty());
+        assertTrue(map.entrySet().isEmpty());
+    }
+
+    @Test public void testContains() {
+        final Map<String, Object> map = new OrderedDictionary();
+        map.put("hello", "helloV");
+
+        assertTrue(map.containsKey("hello"));
+        assertTrue(map.containsKey("heLLo"));
+        assertFalse(map.containsKey("hell o"));
+
+        assertTrue(map.containsValue("helloV"));
+        assertFalse(map.containsValue("heLLoV"));
+        assertFalse(map.containsValue("hello"));
+    }
+
+    @Test public void testSerialization() throws IOException, ClassNotFoundException {
+        final Map<String, Object> map = new OrderedDictionary();
+        map.put("hello", "helloV");
+
+        // write to file
+        final File f = Files.createTempFile("dictionary", "ser").toFile();
+        try {
+
+            try (final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f)) ) {
+                oos.writeObject(map);
+            }
+
+            // read from file
+            try(final ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {
+                @SuppressWarnings("unchecked")
+                final Map<String, Object> readMap = (Map<String, Object>) ois.readObject();
+                assertEquals(1, readMap.size());
+                assertEquals("helloV", readMap.get("hello"));
+            }
+        } finally {
+            if ( f.exists() ) {
+                f.delete();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/cm.json/src/test/resources/configs/single-duplicatekeys.json b/cm.json/src/test/resources/configs/single-duplicatekeys.json
new file mode 100644
index 0000000..44f4625
--- /dev/null
+++ b/cm.json/src/test/resources/configs/single-duplicatekeys.json
@@ -0,0 +1,4 @@
+{
+    "text" : "Hello World",
+    "teXT" : "hello WORLD"
+}
\ No newline at end of file
diff --git a/configadmin-plugins/interpolation/README.md b/configadmin-plugins/interpolation/README.md
index d1a7f10..868ea0f 100644
--- a/configadmin-plugins/interpolation/README.md
+++ b/configadmin-plugins/interpolation/README.md
@@ -61,10 +61,13 @@
 
 ```
 "port" : "$[env:PORT;default=8080]"
+"label" : "$[env:LABEL;default=]"
 ```
 
 Without a default, the placeholder is left in the value if no value can be found. With a default, the default is used instead.
 
+The default value may contain all alphanumeric and punctuation characters and space except for a `;`. It may even be left out which leads to replacing the placeholder with the empty string.
+
 ## Type Support
 
 A placeholder can contain additional information like the type the value should be converted to.
diff --git a/configadmin-plugins/interpolation/pom.xml b/configadmin-plugins/interpolation/pom.xml
index c379cd8..a8f15e3 100644
--- a/configadmin-plugins/interpolation/pom.xml
+++ b/configadmin-plugins/interpolation/pom.xml
@@ -22,13 +22,13 @@
     <parent>
         <groupId>org.apache.felix</groupId>
         <artifactId>felix-parent</artifactId>
-        <version>6</version>
+        <version>7</version>
         <relativePath>../../../pom/pom.xml</relativePath>
     </parent>
 
     <artifactId>org.apache.felix.configadmin.plugin.interpolation</artifactId>
     <packaging>jar</packaging>
-    <version>1.1.1-SNAPSHOT</version>
+    <version>1.1.3-SNAPSHOT</version>
 
     <name>Apache Felix Configuration Admin Values Interpolation Plugin</name>
     <description>
@@ -121,7 +121,7 @@
         <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.converter</artifactId>
-            <version>1.0.12</version>
+            <version>1.0.14</version>
             <scope>provided</scope>
         </dependency>
 
diff --git a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Interpolator.java b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Interpolator.java
index cb98fd6..ceddb92 100755
--- a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Interpolator.java
+++ b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Interpolator.java
@@ -114,9 +114,10 @@
                 directives = new HashMap<>();
 
                 for (String dir : postfix.substring(dirPos + 1).split(";")) {
-                    String[] kv = dir.split("=");
-                    if (kv.length == 2) {
-                        directives.put(kv[0], kv[1]);
+                    String[] kv = dir.split("=", 2);
+                    if (kv.length > 0) {
+                        final String directiveValue = kv.length == 2 ? kv[1] : "";
+                        directives.put(kv[0], directiveValue);
                     }
                 }
             }
diff --git a/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
index bdbf173..7a38573 100644
--- a/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
+++ b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
@@ -138,10 +138,19 @@
 
         Dictionary<String, Object> dict = new Hashtable<>();
         dict.put("defaulted", "$[env:notset;default=foo]");
-
+        dict.put("defaulted2", "$[env:notset;default=]");
+        dict.put("defaulted3", "$[env:notset;default=foo=bar]");
+        dict.put("defaulted4", "$[env:notset;default=foo;=bar]");
+        dict.put("defaulted5", "$[env:notset;default= ]");
+        dict.put("defaulted6", "$[env:notset;default");
         plugin.modifyConfiguration(null, dict);
 
         assertEquals("foo", dict.get("defaulted"));
+        assertEquals("", dict.get("defaulted2"));
+        assertEquals("foo=bar", dict.get("defaulted3"));
+        assertEquals("foo", dict.get("defaulted4")); // semicolon is not supported in values
+        assertEquals(" ", dict.get("defaulted5"));
+        assertEquals("$[env:notset;default", dict.get("defaulted6"));
     }
 
     @Test
diff --git a/configadmin/README.md b/configadmin/README.md
index f4a4145..43e63cb 100644
--- a/configadmin/README.md
+++ b/configadmin/README.md
@@ -1,6 +1,6 @@
 # Apache Felix Configuration Admin Service
 
-The OSGi Componendium Configuration Admin Service specifies a service, which allows for easy management of configuration data for configurable components. Basically a configuration is a list of name-value pairs. A cnfiguration is managed by management applications by asking the Configuration Admin Service for such configuration. After updating the configuration, it is sent back to the Configuration Admin Service. The Configuration Admin Service is like a central hub, which cares for persisting this configuration and also for distributing the configuration to interested parties. One class of such parties are the components to be configured. These are registered as `ManagedService` services. There is also a notion of `ManagedServiceFactory`, which allows for multiple configurations of the same kind to be applied.
+The OSGi Componendium Configuration Admin Service specifies a service, which allows for easy management of configuration data for configurable components. Basically a configuration is a list of name-value pairs. A configuration is managed by management applications by asking the Configuration Admin Service for such configuration. After updating the configuration, it is sent back to the Configuration Admin Service. The Configuration Admin Service is like a central hub, which cares for persisting this configuration and also for distributing the configuration to interested parties. One class of such parties are the components to be configured. These are registered as `ManagedService` services. There is also a notion of `ManagedServiceFactory`, which allows for multiple configurations of the same kind to be applied.
 
 For more information, its suggested you read [Chapter 104, Configuration Admin Service Specification](https://osgi.org/specification/osgi.cmpn/7.0.0/service.cm.html), of the OSGi Compendium Services Specification book. 
 
diff --git a/configadmin/changelog.txt b/configadmin/changelog.txt
index 9ecf1d6..bbd927e 100644
--- a/configadmin/changelog.txt
+++ b/configadmin/changelog.txt
@@ -2,7 +2,6 @@
 -----------------
 ** Bug
     * [FELIX-6354] : IllegalStateException on shutdown
-    * [FELIX-6308] : Bad File Descriptor while persisting service configuration
     * [FELIX-5690] : ConfigurationHandler should support ignoring whitespace between property key/equal sign & equal sign/property value
 
 
diff --git a/configadmin/pom.xml b/configadmin/pom.xml
index c94e97b..91c3eff 100644
--- a/configadmin/pom.xml
+++ b/configadmin/pom.xml
@@ -27,7 +27,7 @@
     </parent>
 
     <artifactId>org.apache.felix.configadmin</artifactId>
-    <version>1.9.19-SNAPSHOT</version>
+    <version>1.9.21-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Felix Configuration Admin Service</name>
diff --git a/configadmin/src/main/java/org/apache/felix/cm/file/FilePersistenceManager.java b/configadmin/src/main/java/org/apache/felix/cm/file/FilePersistenceManager.java
index bffffc5..9ae602d 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/file/FilePersistenceManager.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/file/FilePersistenceManager.java
@@ -728,17 +728,17 @@
             File cfgDir = cfgFile.getParentFile();
             cfgDir.mkdirs();
 
+            // write the configuration to a temporary file
+            tmpFile = File.createTempFile( cfgFile.getName(), TMP_EXT, cfgDir );
+            try(OutputStream out = new FileOutputStream( tmpFile )) {
+                ConfigurationHandler.write( out, props );
+            }
+
             // after writing the file, rename it but ensure, that no other
             // might at the same time open the new file
             // see load(File)
             synchronized ( this )
             {
-                // write the configuration to a temporary file
-                tmpFile = File.createTempFile( cfgFile.getName(), TMP_EXT, cfgDir );
-                try(OutputStream out = new FileOutputStream( tmpFile )) {
-                    ConfigurationHandler.write( out, props );
-                }
-
                 // make sure the cfg file does not exists (just for sanity)
                 if ( cfgFile.exists() )
                 {
diff --git a/configadmin/src/test/java/org/apache/felix/cm/file/ConfigurationHandlerTest.java b/configadmin/src/test/java/org/apache/felix/cm/file/ConfigurationHandlerTest.java
index d24bb8b..831b225 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/file/ConfigurationHandlerTest.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/file/ConfigurationHandlerTest.java
@@ -104,6 +104,16 @@
     }
 
     @Test
+    public void test_writeStringWithSpaces() throws IOException {
+        OutputStream out = new ByteArrayOutputStream();
+        Dictionary< String, String> properties = new Hashtable<>();
+        properties.put("prop", "Hello World");
+        ConfigurationHandler.write(out, properties);
+        String entry = new String(((ByteArrayOutputStream)out).toByteArray(),"UTF-8");
+        Assert.assertEquals("prop=\"Hello\\ World\"\r\n", entry);
+    }
+
+    @Test
     public void test_writeInteger() throws IOException {
         OutputStream out = new ByteArrayOutputStream();
         Dictionary< String, Integer> properties = new Hashtable<>();
@@ -237,6 +247,16 @@
     }
 
     @Test
+    public void test_readStringWithSpaces() throws IOException {
+        String entry = "prop=\"Hello\\ World\"\r\n";
+        InputStream stream = new ByteArrayInputStream(entry.getBytes(StandardCharsets.UTF_8));
+        @SuppressWarnings("unchecked")
+        Dictionary<String, Object> dictionary = ConfigurationHandler.read(stream);
+        Assert.assertEquals(1, dictionary.size());
+        Assert.assertEquals( "Hello World", dictionary.get("prop"));
+    }
+
+    @Test
     public void test_readSimpleStrings() throws IOException {
         String entry = "service.pid=\"com.adobe.granite.foo.Bar\"\r\nfoo.bar=\"com.adobe.granite.foo.Baz\"\r\n";
         InputStream stream = new ByteArrayInputStream(entry.getBytes(StandardCharsets.UTF_8));
diff --git a/configurator/pom.xml b/configurator/pom.xml
index da59ea0..b657443 100644
--- a/configurator/pom.xml
+++ b/configurator/pom.xml
@@ -33,7 +33,7 @@
     <description>
         Implementation of the OSGi Configurator Service Specification 1.0
     </description>
-    <version>1.0.13-SNAPSHOT</version>
+    <version>1.0.15-SNAPSHOT</version>
 
     <scm>
         <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
@@ -111,7 +111,7 @@
         <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.cm.json</artifactId>
-            <version>1.0.0</version>
+            <version>1.0.6</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/configurator/src/main/java/org/apache/felix/configurator/impl/model/Config.java b/configurator/src/main/java/org/apache/felix/configurator/impl/model/Config.java
index 30fa956..2e8c634 100644
--- a/configurator/src/main/java/org/apache/felix/configurator/impl/model/Config.java
+++ b/configurator/src/main/java/org/apache/felix/configurator/impl/model/Config.java
@@ -22,6 +22,8 @@
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
 import java.util.List;
 
 public class Config implements Serializable, Comparable<Config> {
@@ -62,7 +64,7 @@
         this.pid = pid;
         this.ranking = ranking;
         this.bundleId = bundleId;
-        this.properties = properties;
+        this.properties = this.getPrivateCopyOf(properties);
         this.policy = policy;
     }
 
@@ -87,6 +89,22 @@
     }
 
     /**
+     * Copy given Dictionary
+     */
+    private Dictionary<String, Object> getPrivateCopyOf(final Dictionary<String, Object> input) {
+        if ( input == null ) {
+            return null;
+        }
+
+        final Dictionary<String, Object> result = new Hashtable<>();
+        final Enumeration<String> e = input.keys();
+        while(e.hasMoreElements()) {
+            final String key = e.nextElement();
+            result.put(key, input.get(key));
+        }
+        return result;
+    }
+    /**
      * Deserialize the object
      * - read version id
      * - deserialize fields
diff --git a/dependencymanager/.gradle-wrapper/gradle-wrapper.properties b/dependencymanager/.gradle-wrapper/gradle-wrapper.properties
index d110595..e65df49 100644
--- a/dependencymanager/.gradle-wrapper/gradle-wrapper.properties
+++ b/dependencymanager/.gradle-wrapper/gradle-wrapper.properties
@@ -20,4 +20,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
diff --git a/dependencymanager/changelog.txt b/dependencymanager/changelog.txt
index 6bd3550..2672e66 100644
--- a/dependencymanager/changelog.txt
+++ b/dependencymanager/changelog.txt
@@ -1,3 +1,19 @@
+Release Notes - Felix - Version org.apache.felix.dependencymanager-r16
+======================================================================
+
+** List of bundles being part of the release:
+    * org.apache.felix.dependencymanager; version=4.6.1
+    * org.apache.felix.dependencymanager.shell; version=4.0.9
+    * org.apache.felix.dependencymanager.runtime; version=4.0.8
+    * org.apache.felix.dependencymanager.annotation; version=5.0.2
+    * org.apache.felix.dependencymanager.lambda; version=1.2.2
+
+** Bug
+   * [FELIX-6180] - Component initialization error message get's printed to sysout instead of logged to LogService
+
+** Improvement
+   * [FELIX-6278] - Update Dependency Manager with latest bndtools version
+
 Release Notes - Felix - Version org.apache.felix.dependencymanager-r15
 ======================================================================
 
diff --git a/dependencymanager/cnf/build.bnd b/dependencymanager/cnf/build.bnd
index c9832ce..b5144dc 100644
--- a/dependencymanager/cnf/build.bnd
+++ b/dependencymanager/cnf/build.bnd
@@ -46,6 +46,11 @@
 -pom: groupid = org.apache.felix
 
 #
+# do not include pom dependencies
+#
+-maven-dependencies:
+
+#
 # Don't include sources in generated bundles
 #
 -sources: true
@@ -60,3 +65,11 @@
 # Removes some headers in order to reduce binary diff between same bundles that are not changed between subsequent releases.
 #
 -removeheaders: Bnd-LastModified,Tool,Created-By,Include-Resource
+
+#
+# Add pom scm section in generated poms
+#
+Bundle-SCM: \
+    url='https://gitbox.apache.org/repos/asf?p=felix-dev.git',\
+    connection='scm:git:https://github.com/apache/felix-dev.git',\
+    developerConnection='scm:git:https://github.com/apache/felix-dev.git'
diff --git a/dependencymanager/cnf/ext/libraries.bnd b/dependencymanager/cnf/ext/libraries.bnd
index dc86ca7..9148780 100644
--- a/dependencymanager/cnf/ext/libraries.bnd
+++ b/dependencymanager/cnf/ext/libraries.bnd
@@ -53,7 +53,7 @@
 		
 ##
 # bndlib 
-bndlib=biz.aQute.bndlib;version=5.0.1
+bndlib=biz.aQute.bndlib;version=5.2.0
 
 ##
 # mockito
diff --git a/dependencymanager/cnf/repository.mvn b/dependencymanager/cnf/repository.mvn
index e003e74..46d73cb 100644
--- a/dependencymanager/cnf/repository.mvn
+++ b/dependencymanager/cnf/repository.mvn
@@ -16,8 +16,8 @@
 #
 
 ant:ant:1.5
-biz.aQute.bnd:biz.aQute.bnd.gradle:5.0.1
-biz.aQute.bnd:biz.aQute.bndlib:5.0.1
+biz.aQute.bnd:biz.aQute.bnd.gradle:5.2.0
+biz.aQute.bnd:biz.aQute.bndlib:5.2.0
 org.apache.felix:org.apache.felix.framework:5.6.10
 org.apache.felix:org.apache.felix.eventadmin:1.4.4
 org.apache.felix:org.apache.felix.gogo.command:1.0.2
@@ -31,11 +31,11 @@
 org.apache.felix:org.apache.felix.metatype:1.1.2
 org.apache.felix:org.apache.felix.http.jetty:3.4.8
 org.apache.felix:org.apache.felix.webconsole:4.3.4
-org.apache.felix:org.apache.felix.dependencymanager:4.6.0
-org.apache.felix:org.apache.felix.dependencymanager.annotation:5.0.1
-org.apache.felix:org.apache.felix.dependencymanager.lambda:1.2.1
-org.apache.felix:org.apache.felix.dependencymanager.runtime:4.0.7
-org.apache.felix:org.apache.felix.dependencymanager.shell:4.0.8
+org.apache.felix:org.apache.felix.dependencymanager:4.6.1
+org.apache.felix:org.apache.felix.dependencymanager.annotation:5.0.2
+org.apache.felix:org.apache.felix.dependencymanager.lambda:1.2.2
+org.apache.felix:org.apache.felix.dependencymanager.runtime:4.0.8
+org.apache.felix:org.apache.felix.dependencymanager.shell:4.0.9
 org.jline:jline-builtins:3.3.0
 org.apache.servicemix.bundles:org.apache.servicemix.bundles.junit:4.12_1
 org.mockito:mockito-core:1.10.19
diff --git a/dependencymanager/gradle.properties b/dependencymanager/gradle.properties
index 701550b..35354fb 100644
--- a/dependencymanager/gradle.properties
+++ b/dependencymanager/gradle.properties
@@ -17,9 +17,9 @@
  * under the License.
  */
 
-bnd_version=5.0.1
+bnd_version=5.2.0
 # bnd_plugin is the dependency declaration for the bnd gradle plugin
-bnd_plugin=biz.aQute.bnd:biz.aQute.bnd.gradle:5.0.1
+bnd_plugin=biz.aQute.bnd:biz.aQute.bnd.gradle:5.2.0
 
 org.gradle.jvmargs=-Xmx2g
 
diff --git a/dependencymanager/org.apache.felix.dependencymanager.annotation/bnd.bnd b/dependencymanager/org.apache.felix.dependencymanager.annotation/bnd.bnd
index f448335..9d04b26 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.annotation/bnd.bnd
+++ b/dependencymanager/org.apache.felix.dependencymanager.annotation/bnd.bnd
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-Bundle-Version: 5.0.2
+Bundle-Version: 5.0.3
 -buildpath: \
 	osgi.core;version=6.0,\
 	osgi.cmpn;version=6.0,\
diff --git a/dependencymanager/org.apache.felix.dependencymanager.annotation/changelog.txt b/dependencymanager/org.apache.felix.dependencymanager.annotation/changelog.txt
index 0857a40..0dfd0db 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.annotation/changelog.txt
+++ b/dependencymanager/org.apache.felix.dependencymanager.annotation/changelog.txt
@@ -1,3 +1,16 @@
+Release Notes - Felix - Version org.apache.felix.dependencymanager-r16
+======================================================================
+
+** List of bundles being part of the release:
+    * org.apache.felix.dependencymanager; version=4.6.1
+    * org.apache.felix.dependencymanager.shell; version=4.0.9
+    * org.apache.felix.dependencymanager.runtime; version=4.0.8
+    * org.apache.felix.dependencymanager.annotation; version=5.0.2
+    * org.apache.felix.dependencymanager.lambda; version=1.2.2
+
+** Improvement
+   * [FELIX-6278] - Update Dependency Manager with latest bndtools version
+
 Release Notes - Felix - Version org.apache.felix.dependencymanager-r14
 ======================================================================
 
diff --git a/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/DEPENDENCIES b/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/DEPENDENCIES
index 4a8833f..95f26f5 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/DEPENDENCIES
+++ b/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/DEPENDENCIES
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Annotation
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This software was developed at the Apache Software Foundation
 (http://www.apache.org) and may have dependencies on other
diff --git a/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/NOTICE b/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/NOTICE
index 3bbc09a..f844568 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/NOTICE
+++ b/dependencymanager/org.apache.felix.dependencymanager.annotation/resources/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Annotation
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/bnd.bnd b/dependencymanager/org.apache.felix.dependencymanager.lambda/bnd.bnd
index 3e26cb2..604546b 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.lambda/bnd.bnd
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/bnd.bnd
@@ -16,7 +16,7 @@
 #
 javac.source:          1.8
 javac.target:          1.8
-Bundle-Version: 1.2.2
+Bundle-Version: 1.2.3
 -buildpath: \
 	org.apache.felix.dependencymanager;version=latest,\
 	osgi.core;version=6.0,\
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/changelog.txt b/dependencymanager/org.apache.felix.dependencymanager.lambda/changelog.txt
index f1c45b1..7072771 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.lambda/changelog.txt
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/changelog.txt
@@ -1,3 +1,16 @@
+Release Notes - Felix - Version org.apache.felix.dependencymanager-r16
+======================================================================
+
+** List of bundles being part of the release:
+    * org.apache.felix.dependencymanager; version=4.6.1
+    * org.apache.felix.dependencymanager.shell; version=4.0.9
+    * org.apache.felix.dependencymanager.runtime; version=4.0.8
+    * org.apache.felix.dependencymanager.annotation; version=5.0.2
+    * org.apache.felix.dependencymanager.lambda; version=1.2.2
+
+** Improvement
+   * [FELIX-6278] - Update Dependency Manager with latest bndtools version
+
 Release Notes - Felix - Version org.apache.felix.dependencymanager-r15
 ======================================================================
 
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/DEPENDENCIES b/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/DEPENDENCIES
index 9126cc8..b19819e 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/DEPENDENCIES
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/DEPENDENCIES
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Lambda
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This software was developed at the Apache Software Foundation
 (http://www.apache.org) and may have dependencies on other
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/NOTICE b/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/NOTICE
index 092e158..bf4172c 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/NOTICE
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/resources/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Lambda
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 
 This product includes software developed at
diff --git a/dependencymanager/org.apache.felix.dependencymanager.runtime/.settings/org.eclipse.jdt.core.prefs b/dependencymanager/org.apache.felix.dependencymanager.runtime/.settings/org.eclipse.jdt.core.prefs
index c85c742..27da04a 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.runtime/.settings/org.eclipse.jdt.core.prefs
+++ b/dependencymanager/org.apache.felix.dependencymanager.runtime/.settings/org.eclipse.jdt.core.prefs
@@ -1,6 +1,7 @@
 eclipse.preferences.version=1
 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
@@ -8,20 +9,23 @@
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_assignment=0
-org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
 org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
 org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
@@ -111,11 +115,12 @@
 org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
 org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
 org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
 org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
 org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
 org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
@@ -146,6 +151,8 @@
 org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
 org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
 org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
@@ -170,13 +177,17 @@
 org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
 org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
 org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
 org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
 org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
@@ -224,6 +235,8 @@
 org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
@@ -260,9 +273,12 @@
 org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
 org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
 org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
@@ -298,9 +314,13 @@
 org.eclipse.jdt.core.formatter.tabulation.size=4
 org.eclipse.jdt.core.formatter.use_on_off_tags=false
 org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
 org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
 org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
 org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
 org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
 org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/dependencymanager/org.apache.felix.dependencymanager.runtime/bnd.bnd b/dependencymanager/org.apache.felix.dependencymanager.runtime/bnd.bnd
index 8edcb70..7236438 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.runtime/bnd.bnd
+++ b/dependencymanager/org.apache.felix.dependencymanager.runtime/bnd.bnd
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-Bundle-Version: 4.0.8
+Bundle-Version: 4.0.9
 -buildpath: \
 	osgi.core;version=4.2,\
 	osgi.cmpn;version=4.2,\
diff --git a/dependencymanager/org.apache.felix.dependencymanager.runtime/changelog.txt b/dependencymanager/org.apache.felix.dependencymanager.runtime/changelog.txt
index f1c45b1..7072771 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.runtime/changelog.txt
+++ b/dependencymanager/org.apache.felix.dependencymanager.runtime/changelog.txt
@@ -1,3 +1,16 @@
+Release Notes - Felix - Version org.apache.felix.dependencymanager-r16
+======================================================================
+
+** List of bundles being part of the release:
+    * org.apache.felix.dependencymanager; version=4.6.1
+    * org.apache.felix.dependencymanager.shell; version=4.0.9
+    * org.apache.felix.dependencymanager.runtime; version=4.0.8
+    * org.apache.felix.dependencymanager.annotation; version=5.0.2
+    * org.apache.felix.dependencymanager.lambda; version=1.2.2
+
+** Improvement
+   * [FELIX-6278] - Update Dependency Manager with latest bndtools version
+
 Release Notes - Felix - Version org.apache.felix.dependencymanager-r15
 ======================================================================
 
diff --git a/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/DEPENDENCIES b/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/DEPENDENCIES
index aa7306b..22d92dc 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/DEPENDENCIES
+++ b/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/DEPENDENCIES
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Runtime
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This software was developed at the Apache Software Foundation
 (http://www.apache.org) and may have dependencies on other
diff --git a/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/NOTICE b/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/NOTICE
index 42cae55..d7f248c 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/NOTICE
+++ b/dependencymanager/org.apache.felix.dependencymanager.runtime/resources/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Runtime
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/dependencymanager/org.apache.felix.dependencymanager.shell/bnd.bnd b/dependencymanager/org.apache.felix.dependencymanager.shell/bnd.bnd
index ceb86ed..957d03b 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.shell/bnd.bnd
+++ b/dependencymanager/org.apache.felix.dependencymanager.shell/bnd.bnd
@@ -24,7 +24,7 @@
 Private-Package: \
 	org.apache.felix.dm.shell
 Bundle-Activator:org.apache.felix.dm.shell.Activator
-Bundle-Version: 4.0.9
+Bundle-Version: 4.0.10
 Include-Resource: META-INF/=resources/,META-INF/changelog.txt=changelog.txt
 Bundle-Name: Apache Felix Dependency Manager Shell
 Bundle-Description: Gogo Shell commands for Apache Felix Dependency Manager
diff --git a/dependencymanager/org.apache.felix.dependencymanager.shell/changelog.txt b/dependencymanager/org.apache.felix.dependencymanager.shell/changelog.txt
index f1c45b1..7072771 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.shell/changelog.txt
+++ b/dependencymanager/org.apache.felix.dependencymanager.shell/changelog.txt
@@ -1,3 +1,16 @@
+Release Notes - Felix - Version org.apache.felix.dependencymanager-r16
+======================================================================
+
+** List of bundles being part of the release:
+    * org.apache.felix.dependencymanager; version=4.6.1
+    * org.apache.felix.dependencymanager.shell; version=4.0.9
+    * org.apache.felix.dependencymanager.runtime; version=4.0.8
+    * org.apache.felix.dependencymanager.annotation; version=5.0.2
+    * org.apache.felix.dependencymanager.lambda; version=1.2.2
+
+** Improvement
+   * [FELIX-6278] - Update Dependency Manager with latest bndtools version
+
 Release Notes - Felix - Version org.apache.felix.dependencymanager-r15
 ======================================================================
 
diff --git a/dependencymanager/org.apache.felix.dependencymanager.shell/resources/DEPENDENCIES b/dependencymanager/org.apache.felix.dependencymanager.shell/resources/DEPENDENCIES
index 9bd2fd9..8f36a23 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.shell/resources/DEPENDENCIES
+++ b/dependencymanager/org.apache.felix.dependencymanager.shell/resources/DEPENDENCIES
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Shell
-Copyright 2011-2016 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This software was developed at the Apache Software Foundation
 (http://www.apache.org) and may have dependencies on other
diff --git a/dependencymanager/org.apache.felix.dependencymanager.shell/resources/NOTICE b/dependencymanager/org.apache.felix.dependencymanager.shell/resources/NOTICE
index 4946dbc..926fb56 100644
--- a/dependencymanager/org.apache.felix.dependencymanager.shell/resources/NOTICE
+++ b/dependencymanager/org.apache.felix.dependencymanager.shell/resources/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager Shell
-Copyright 2011-2016 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 
 This product includes software developed at
diff --git a/dependencymanager/org.apache.felix.dependencymanager/bnd.bnd b/dependencymanager/org.apache.felix.dependencymanager/bnd.bnd
index 133bfbb..26ec2d9 100644
--- a/dependencymanager/org.apache.felix.dependencymanager/bnd.bnd
+++ b/dependencymanager/org.apache.felix.dependencymanager/bnd.bnd
@@ -34,7 +34,7 @@
 Include-Resource: META-INF/=resources/,META-INF/changelog.txt=changelog.txt
 Import-Package: !org.junit,!org.mockito.*,org.osgi.framework;version="[1.8, 2)",*
 Bundle-Activator: org.apache.felix.dm.impl.Activator
-Bundle-Version: 4.6.1
+Bundle-Version: 4.6.2
 Bundle-Name: Apache Felix Dependency Manager
 Bundle-Description: Provides dynamic service and component dependency management
 Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
diff --git a/dependencymanager/org.apache.felix.dependencymanager/changelog.txt b/dependencymanager/org.apache.felix.dependencymanager/changelog.txt
index 0d1d19a..79be51a 100644
--- a/dependencymanager/org.apache.felix.dependencymanager/changelog.txt
+++ b/dependencymanager/org.apache.felix.dependencymanager/changelog.txt
@@ -3,13 +3,16 @@
 
 ** List of bundles being part of the release:
     * org.apache.felix.dependencymanager; version=4.6.1
-    * org.apache.felix.dependencymanager.shell; version=4.0.8
-    * org.apache.felix.dependencymanager.runtime; version=4.0.7
-    * org.apache.felix.dependencymanager.annotation; version=5.0.1
-    * org.apache.felix.dependencymanager.lambda; version=1.2.1
+    * org.apache.felix.dependencymanager.shell; version=4.0.9
+    * org.apache.felix.dependencymanager.runtime; version=4.0.8
+    * org.apache.felix.dependencymanager.annotation; version=5.0.2
+    * org.apache.felix.dependencymanager.lambda; version=1.2.2
 
 ** Bug
-   * [FELIX-6180] Component initialization error message get's printed to sysout instead of logged to LogService
+   * [FELIX-6180] - Component initialization error message get's printed to sysout instead of logged to LogService
+
+** Improvement
+   * [FELIX-6278] - Update Dependency Manager with latest bndtools version
 
 Release Notes - Felix - Version org.apache.felix.dependencymanager-r15
 ======================================================================
diff --git a/dependencymanager/org.apache.felix.dependencymanager/resources/DEPENDENCIES b/dependencymanager/org.apache.felix.dependencymanager/resources/DEPENDENCIES
index 9fdadf3..53294b8 100644
--- a/dependencymanager/org.apache.felix.dependencymanager/resources/DEPENDENCIES
+++ b/dependencymanager/org.apache.felix.dependencymanager/resources/DEPENDENCIES
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This software was developed at the Apache Software Foundation
 (http://www.apache.org) and may have dependencies on other
diff --git a/dependencymanager/org.apache.felix.dependencymanager/resources/NOTICE b/dependencymanager/org.apache.felix.dependencymanager/resources/NOTICE
index 195d532..f8d1dc5 100644
--- a/dependencymanager/org.apache.felix.dependencymanager/resources/NOTICE
+++ b/dependencymanager/org.apache.felix.dependencymanager/resources/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager
-Copyright 2011-2017 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 
 This product includes software developed at
diff --git a/dependencymanager/release/README.release b/dependencymanager/release/README.release
index 2545e81..7d52f40 100644
--- a/dependencymanager/release/README.release
+++ b/dependencymanager/release/README.release
@@ -33,21 +33,22 @@
 
 Creating a tagged version of the sources can be done directly through svn (replace r<n> by the actual release number, like "r1"):
 
-svn copy https://svn.apache.org/repos/asf/felix/trunk/dependencymanager https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.dependencymanager-r<n> -m "Release of Apache Felix Dependency Manager r<n>"
+git tag -a org.apache.felix.dependencymanager-r<n> -m "Release of Apache Felix Dependency Manager r<n>"
+git push origin org.apache.felix.dependencymanager-r<n>
 
 Staging a release candidate
 ===========================
 
 Staging a release starts by checking out a tagged version of the sources (replace r<n> by the actual release number, like "r1"):
 
-svn co https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.dependencymanager-r<n>
+git clone -–depth 1 -b org.apache.felix.dependencymanager-r<n> http://gitbox.apache.org/repos/asf/felix-dev.git felix-dev-org.apache.felix.dependencymanager-r<n>
 
 The next step is to build/test the software and create the release/staging/ directory (where the source/jars will be packaged):
 (replace r<n> by the actual release number, like "r1")
 
 Use a Java8 JDK
 
-$ cd org.apache.felix.dependencymanager-r<n>
+$ cd felix-dev-org.apache.felix.dependencymanager-r<n>/dependencymanager
 $ ./gradlew rat 
 $ ./gradlew org.apache.felix.dependencymanager.annotation:jar
 $ ./gradlew jar
@@ -81,7 +82,7 @@
 To: "Felix Developers List" <dev@felix.apache.org>
 Subject: [VOTE] Release of Apache Felix Dependency Manager release r<n>
 
-Hi,
+I would like to call for a vote on the Dependency Manager top level release r<n>
 
 We solved N issues in this release:
 http://issues.apache.org/jira/...
@@ -93,16 +94,23 @@
 https://dist.apache.org/repos/dist/dev/felix/apache-felix-dependencymanager-r<n>/
 
 You can use this UNIX script to download the release and verify the signatures:
-http://svn.apache.org/repos/asf/felix/trunk/dependencymanager/release/check_staged_release.sh
+
+https://github.com/apache/felix-dev/blob/master/dependencymanager/release/check_staged_release.sh
 
 Usage:
-sh check_staged_release.sh r<n> /tmp/felix-staging
 
-This script, unlike the original Felix check_stage_release.sh, will download staging from https://dist.apache.org/repos/dist/dev/felix instead of 
-http://repository.apache.org/content/repositories.
+      sh check_staged_release.sh r<n> /tmp/felix-staging
 
+This script, unlike the original Felix check_stage_release.sh, is specific
+to the Dependency Manager release process (see FELIX-4818) and will
+download staging from https://dist.apache.org/repos/dist/dev/felix instead
+of http://repository.apache.org/content/repositories.
 
-Please vote to approve this release:
+To rebuild the DM binaries from the source, jdk8 must be used, and you can refer to:
+
+https://github.com/apache/felix-dev/blob/master/dependencymanager/release/resources/src/README.src
+
+Please cast your votes to approve this release:
 
 [ ] +1 Approve the release
 [ ] -1 Veto the release (please provide specific comments)
diff --git a/dependencymanager/release/build.gradle b/dependencymanager/release/build.gradle
index d168524..db781b0 100644
--- a/dependencymanager/release/build.gradle
+++ b/dependencymanager/release/build.gradle
@@ -33,7 +33,7 @@
 }
 
 // Our release number, which has to be monotonically incremented each time we make a new release.
-ext.dmRelease = "r16"
+ext.dmRelease = "r17"
 
 // Our Apache svn Staging repo
 ext.svnStagingPath = "https://dist.apache.org/repos/dist/dev/felix"
@@ -214,10 +214,15 @@
 task commitToStaging {
   doLast {
     description = 'Commits the local staging to the Apache svn staging repository.'
-    getProject().exec { 
+    ant.input(message: 'Enter SVN user:', addproperty: 'user')
+    ant.input(message: 'Enter SVN password:', addproperty: 'password')
+    def user = ant.properties.user
+    def password = ant.properties.password
+
+    getProject().exec {
     	commandLine 'svn', 
 		'import', 'staging', svnStagingPath + "/org.apache.felix.dependencymanager-" + dmRelease + "/", 
-		'-m', "Staging Apache Felix Dependency Manager release " + dmRelease + ".", "--force-interactive"
+		'-m', "Staging Apache Felix Dependency Manager release " + dmRelease + ".", "--username", user, "--password", password
     }
   }
 }
@@ -226,6 +231,10 @@
 task promoteToRelease {
   doLast {
     description = 'Moves the staging repository to the Apache release repository.'
+    ant.input(message: 'Enter SVN user:', addproperty: 'user')
+    ant.input(message: 'Enter SVN password:', addproperty: 'password')
+    def user = ant.properties.user
+    def password = ant.properties.password
 
     // Move all artifacts from the staging repo to the release repo
     new ByteArrayOutputStream().withStream { os ->
@@ -241,7 +250,8 @@
 	    	getProject().exec { 
 				commandLine 'svn',
 				'move', svnStagingPath+"/org.apache.felix.dependencymanager-" + dmRelease + "/" + artifact , 
-				svnReleasePath, '-m', "Releasing Apache Felix Dependency Manager release " + dmRelease + ".", "--force-interactive"
+				svnReleasePath, '-m', "Releasing Apache Felix Dependency Manager release " + dmRelease + ".",
+				"--username", user, "--password", password
 	    	}
 		}
     }
@@ -251,7 +261,8 @@
     getProject().exec { 
     	commandLine 'svn',
 		'rm', svnStagingPath+"/org.apache.felix.dependencymanager-" + dmRelease, "-m", 
-		"Releasing Apache Felix Dependency Manager release " + dmRelease + "."
+		"Releasing Apache Felix Dependency Manager release " + dmRelease + ".",
+		"--username", user, "--password", password
     }
   }
 }
@@ -260,10 +271,16 @@
 task deleteFromStaging {
   doLast {
     description = 'Cancels the staged distribution from the Apache staging repository.'
+    ant.input(message: 'Enter SVN user:', addproperty: 'user')
+    ant.input(message: 'Enter SVN password:', addproperty: 'password')
+    def user = ant.properties.user
+    def password = ant.properties.password
+
     getProject().exec { 
     	commandLine 'svn',
 		'delete', svnStagingPath+"/org.apache.felix.dependencymanager-" + dmRelease + "/",
-		"-m", "Removing Apache Felix Dependency Manager release " + dmRelease + " from staging."
+		"-m", "Removing Apache Felix Dependency Manager release " + dmRelease + " from staging.",
+		"--username", user, "--password", password		
     }
   }
 }
diff --git a/dependencymanager/release/resources/bin/NOTICE b/dependencymanager/release/resources/bin/NOTICE
index 75032fe..bdcdd85 100644
--- a/dependencymanager/release/resources/bin/NOTICE
+++ b/dependencymanager/release/resources/bin/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager
-Copyright 2011-2018 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/dependencymanager/release/resources/bin/README.bin b/dependencymanager/release/resources/bin/README.bin
index adf8b2c..9196034 100644
--- a/dependencymanager/release/resources/bin/README.bin
+++ b/dependencymanager/release/resources/bin/README.bin
@@ -25,12 +25,29 @@
 ===============
 
 To start using Apache Felix Dependency Manager, please go to our website and read the
-getting started guide for users:
+various guides for users:
+
+- For a quick jump start (using either maven, gradle, the DM api, the DM annotations, or the new DM lambda-api), 
+then please go to:
+
+  http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/tutorials/sample-code.html
+
+There are three ways to use Dependency Manager: you can use the original java API, the new lambda API, or the 
+DM annotations.
+
+- For the Dependency Manager java API documentation, please go to the general Getting-Started documentation here:
 
   http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager.html
 
-You can also find examples from ./org.apache.felix.dependencymanager.samples/README
+- For new Dependency Manager Lambda API, you can go to:
+
+http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.html
+
+- And for Dependency Manager Annotations API, you can refer directly to:
+
+  http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/dm-annotations.html
 
 Many thanks for using Apache Felix Dependency Manager.
 
 The Felix Team
+
diff --git a/dependencymanager/release/resources/src/NOTICE b/dependencymanager/release/resources/src/NOTICE
index 75032fe..bdcdd85 100644
--- a/dependencymanager/release/resources/src/NOTICE
+++ b/dependencymanager/release/resources/src/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Dependency Manager
-Copyright 2011-2018 The Apache Software Foundation
+Copyright 2011-2021 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/dependencymanager/release/resources/src/README.src b/dependencymanager/release/resources/src/README.src
index ce9628e..9fbae39 100644
--- a/dependencymanager/release/resources/src/README.src
+++ b/dependencymanager/release/resources/src/README.src
@@ -82,12 +82,27 @@
 ===============
 
 To start using Apache Felix Dependency Manager, please go to our website and read the
-getting started guide for users:
+various guides for users:
+
+- For a quick jump start (using either maven, gradle, the DM api, the DM annotations, or the new DM lambda-api), 
+then please go to:
+
+  http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/tutorials/sample-code.html
+
+There are three ways to use Dependency Manager: you can use the original java API, the new lambda API, or the 
+DM annotations.
+
+- For the Dependency Manager java API documentation, please go to the general Getting-Started documentation here:
 
   http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager.html
 
-Many examples are also available from the dependency manager samples module.
-See ./org.apache.felix.dependencymanager.samples/README.samples
+- For new Dependency Manager Lambda API, you can go to:
+
+http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/guides/dm-lambda.html
+
+- And for Dependency Manager Annotations API, you can refer directly to:
+
+  http://felix.apache.org/documentation/subprojects/apache-felix-dependency-manager/reference/dm-annotations.html
 
 Many thanks for using Apache Felix Dependency Manager.
 
diff --git a/eventadmin/impl/changelog.txt b/eventadmin/impl/changelog.txt
index 570d04b..5c80e7a 100644
--- a/eventadmin/impl/changelog.txt
+++ b/eventadmin/impl/changelog.txt
@@ -1,3 +1,9 @@
+Changes in 1.6.2
+----------------
+** Bug
+    * [FELIX-6373] - Wrong provide capability header
+
+
 Changes in 1.6.0
 ----------------
 ** Improvement
diff --git a/eventadmin/impl/pom.xml b/eventadmin/impl/pom.xml
index 9e2378f..e80594e 100644
--- a/eventadmin/impl/pom.xml
+++ b/eventadmin/impl/pom.xml
@@ -29,13 +29,14 @@
     <description>
 	    This bundle provides an implementation of the OSGi R7 EventAdmin service.
     </description>
-    <version>1.6.0-SNAPSHOT</version>
+    <version>1.6.3-SNAPSHOT</version>
     <artifactId>org.apache.felix.eventadmin</artifactId>
     <scm>
       <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
       <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
       <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
-    </scm>
+      <tag>HEAD</tag>
+  </scm>
     
     <properties>
         <bundle.build.name>
@@ -152,7 +153,7 @@
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
-                <version>5.1.1</version>
+                <version>4.2.1</version>
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java
index 53fdfaa..c9be4c1 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Activator.java
@@ -24,7 +24,7 @@
 
 /**
  * The activator of the EventAdmin bundle. This class registers an implementation of
- * the OSGi R4 <tt>EventAdmin</tt> service (see the Compendium 113) with the
+ * the OSGi R4 {@code EventAdmin} service (see the Compendium 113) with the
  * framework. It features timeout-based denying of event-handlers for both,
  * asynchronous and synchronous event-dispatching (as a spec conform optional
  * extension).
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java
index e0faaf9..25b21fc 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/Configuration.java
@@ -50,38 +50,38 @@
  * The service knows about the following properties which are read at bundle startup:
  * <p>
  * <p>
- *      <tt>org.apache.felix.eventadmin.ThreadPoolSize</tt> - The size of the thread
+ *      {@code org.apache.felix.eventadmin.ThreadPoolSize} - The size of the thread
  *          pool.
  * </p>
  * The default value is 10. Increase in case of a large amount of synchronous events
- * where the <tt>EventHandler</tt> services in turn send new synchronous events in
+ * where the {@code EventHandler} services in turn send new synchronous events in
  * the event dispatching thread or a lot of timeouts are to be expected. A value of
  * less then 2 triggers the default value. A value of 2 effectively disables thread
  * pooling.
  * </p>
  * <p>
  * <p>
- *      <tt>org.apache.felix.eventadmin.Timeout</tt> - The deny-listing timeout in
+ *      {@code org.apache.felix.eventadmin.Timeout} - The deny-listing timeout in
  *          milliseconds
  * </p>
  * The default value is 5000. Increase or decrease at own discretion. A value of less
  * then 100 turns timeouts off. Any other value is the time in milliseconds granted
- * to each <tt>EventHandler</tt> before it gets put on the denylist.
+ * to each {@code EventHandler} before it gets put on the denylist.
  * </p>
  * <p>
  * <p>
- *      <tt>org.apache.felix.eventadmin.RequireTopic</tt> - Are <tt>EventHandler</tt>
+ *      {@code org.apache.felix.eventadmin.RequireTopic} - Are {@code EventHandler}
  *          required to be registered with a topic?
  * </p>
- * The default is <tt>true</tt>. The specification says that <tt>EventHandler</tt>
+ * The default is {@code true}. The specification says that {@code EventHandler}
  * must register with a list of topics they are interested in. Setting this value to
- * <tt>false</tt> will enable that handlers without a topic are receiving all events
+ * {@code false} will enable that handlers without a topic are receiving all events
  * (i.e., they are treated the same as with a topic=*).
  * </p>
  * <p>
  * <p>
- *      <tt>org.apache.felix.eventadmin.IgnoreTimeout</tt> - Configure
- *         <tt>EventHandler</tt>s to be called without a timeout.
+ *      {@code org.apache.felix.eventadmin.IgnoreTimeout} - Configure
+ *         {@code EventHandler}s to be called without a timeout.
  * </p>
  * <p>
  * If a timeout is configured by default all event handlers are called using the timeout.
@@ -99,7 +99,7 @@
  * </p>
  * <p>
  * <p>
- *      <tt>org.apache.felix.eventadmin.IgnoreTopic</tt> - Configure
+ *      {@code org.apache.felix.eventadmin.IgnoreTopic} - Configure
  *         topics to be ignore and not delivered to registered handlers.
  * </p>
  * <p>
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java
index 8a687d4..ce8e1eb 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/AbstractAdapter.java
@@ -34,7 +34,7 @@
     /**
      * The constructor of the adapter.
      *
-     * @param admin The <tt>EventAdmin</tt> to use for posting events.
+     * @param admin The {@code EventAdmin} to use for posting events.
      */
     public AbstractAdapter(final EventAdmin admin)
     {
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java
index 5719999..0a5f380b 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/BundleEventAdapter.java
@@ -38,11 +38,11 @@
 {
     /**
      * The constructor of the adapter. This will register the adapter with the given
-     * context as a <tt>BundleListener</tt> and subsequently, will post received
+     * context as a {@code BundleListener} and subsequently, will post received
      * events via the given EventAdmin.
      *
      * @param context The bundle context with which to register as a listener.
-     * @param admin The <tt>EventAdmin</tt> to use for posting events.
+     * @param admin The {@code EventAdmin} to use for posting events.
      */
     public BundleEventAdapter(final BundleContext context, final EventAdmin admin)
     {
@@ -57,7 +57,7 @@
 
     /**
      * Once a bundle event is received this method assembles and posts an event via
-     * the <tt>EventAdmin</tt> as specified in 113.6.4 OSGi R4 compendium.
+     * the {@code EventAdmin} as specified in 113.6.4 OSGi R4 compendium.
      *
      * @param event The event to adapt.
      */
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java
index 9a971d3..5edfe0c 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/FrameworkEventAdapter.java
@@ -39,11 +39,11 @@
 {
     /**
      * The constructor of the adapter. This will register the adapter with the
-     * given context as a <tt>FrameworkListener</tt> and subsequently, will
+     * given context as a {@code FrameworkListener} and subsequently, will
      * post received events via the given EventAdmin.
      *
      * @param context The bundle context with which to register as a listener.
-     * @param admin The <tt>EventAdmin</tt> to use for posting events.
+     * @param admin The {@code EventAdmin} to use for posting events.
      */
     public FrameworkEventAdapter(final BundleContext context, final EventAdmin admin)
     {
@@ -59,7 +59,7 @@
 
     /**
      * Once a framework event is received this method assembles and posts an event
-     * via the <tt>EventAdmin</tt> as specified in 113.6.3 OSGi R4 compendium.
+     * via the {@code EventAdmin} as specified in 113.6.3 OSGi R4 compendium.
      *
      * @param event The event to adapt.
      */
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java
index 84dcd70..8a11a93 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/LogEventAdapter.java
@@ -33,9 +33,9 @@
 import org.osgi.service.event.EventConstants;
 
 /**
- * This class registers itself as a listener for <tt>LogReaderService</tt> services
- * with the framework and subsequently, a <tt>LogListener</tt> callback with any
- * currently available <tt>LogReaderService</tt>. Any received log event is then
+ * This class registers itself as a listener for {@code LogReaderService} services
+ * with the framework and subsequently, a {@code LogListener} callback with any
+ * currently available {@code LogReaderService}. Any received log event is then
  * posted via the EventAdmin as specified in 113.6.6 OSGi R4 compendium.
  * Note that this class does not create a hard dependency on the org.osgi.service.log
  * packages. The adaption only takes place if it is present or once it becomes
@@ -56,13 +56,13 @@
 
     /**
      * The constructor of the adapter. This will register the adapter with the
-     * given context as a listener for <tt>LogReaderService</tt> services and
-     * subsequently, a <tt>LogListener</tt> callback with any currently available
-     * <tt>LogReaderService</tt>. Any received log event is then posted via the given
+     * given context as a listener for {@code LogReaderService} services and
+     * subsequently, a {@code LogListener} callback with any currently available
+     * {@code LogReaderService}. Any received log event is then posted via the given
      * EventAdmin.
      *
      * @param context The bundle context with which to register as a listener.
-     * @param admin The <tt>EventAdmin</tt> to use for posting events.
+     * @param admin The {@code EventAdmin} to use for posting events.
      */
     public LogEventAdapter(final BundleContext context, final EventAdmin admin)
     {
@@ -106,9 +106,9 @@
     }
 
     /**
-     * Once a <tt>LogReaderService</tt> register event is received this method
-     * registers a <tt>LogListener</tt> with the received service that assembles
-     * and posts any log event via the <tt>EventAdmin</tt> as specified in
+     * Once a {@code LogReaderService} register event is received this method
+     * registers a {@code LogListener} with the received service that assembles
+     * and posts any log event via the {@code EventAdmin} as specified in
      * 113.6.6 OSGi R4 compendium.
      *
      * @param event The event to adapt.
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java
index 74ab293..3dfff93 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/adapter/ServiceEventAdapter.java
@@ -39,11 +39,11 @@
 {
     /**
      * The constructor of the adapter. This will register the adapter with the
-     * given context as a <tt>ServiceListener</tt> and subsequently, will
+     * given context as a {@code ServiceListener} and subsequently, will
      * post received events via the given EventAdmin.
      *
      * @param context The bundle context with which to register as a listener.
-     * @param admin The <tt>EventAdmin</tt> to use for posting events.
+     * @param admin The {@code EventAdmin} to use for posting events.
      */
     public ServiceEventAdapter(final BundleContext context, final EventAdmin admin)
     {
@@ -59,7 +59,7 @@
 
     /**
      * Once a Service event is received this method assembles and posts an event
-     * via the <tt>EventAdmin</tt> as specified in 113.6.5 OSGi R4 compendium.
+     * via the {@code EventAdmin} as specified in 113.6.5 OSGi R4 compendium.
      *
      * @param event The event to adapt.
      */
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventAdminImpl.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventAdminImpl.java
index 05977c0..6f2d235 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventAdminImpl.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventAdminImpl.java
@@ -31,13 +31,13 @@
 
 /**
  * This is the actual implementation of the OSGi R4 Event Admin Service (see the
- * Compendium 113 for details). The implementation uses a <tt>HandlerTasks</tt>
- * in order to determine applicable <tt>EventHandler</tt> for a specific event and
- * subsequently dispatches the event to the handlers via <tt>DeliverTasks</tt>.
- * To do this, it uses two different <tt>DeliverTasks</tt> one for asynchronous and
- * one for synchronous event delivery depending on whether its <tt>post()</tt> or
- * its <tt>send()</tt> method is called. Note that the actual work is done in the
- * implementations of the <tt>DeliverTasks</tt>. Additionally, a stop method is
+ * Compendium 113 for details). The implementation uses a {@code HandlerTasks}
+ * in order to determine applicable {@code EventHandler} for a specific event and
+ * subsequently dispatches the event to the handlers via {@code DeliverTasks}.
+ * To do this, it uses two different {@code DeliverTasks} one for asynchronous and
+ * one for synchronous event delivery depending on whether its {@code post()} or
+ * its {@code send()} method is called. Note that the actual work is done in the
+ * implementations of the {@code DeliverTasks}. Additionally, a stop method is
  * provided that prevents subsequent events to be delivered.
  *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
@@ -57,10 +57,15 @@
     private Matchers.Matcher[] m_ignoreTopics;
 
     /**
-     * The constructor of the <tt>EventAdmin</tt> implementation.
+     * The constructor of the {@code EventAdmin} implementation.
      *
+     * @param bundleContext The event admin bundle context
      * @param syncPool The synchronous thread pool
      * @param asyncPool The asynchronous thread pool
+     * @param timeout The timeout
+     * @param ignoreTimeout The configuration for ignoring timeouts
+     * @param requireTopic Are topics required?
+     * @param ignoreTopics The configuration to ignore topics
      */
     public EventAdminImpl(
                     final BundleContext bundleContext,
@@ -162,6 +167,10 @@
 
     /**
      * Update the event admin with new configuration.
+     * @param timeout The timeout
+     * @param ignoreTimeout The configuration for ignoring timeouts
+     * @param requireTopic Are topics required?
+     * @param ignoreTopics The configuration to ignore topics
      */
     public void update(final int timeout,
                     final String[] ignoreTimeout,
@@ -176,7 +185,7 @@
     }
 
     /**
-     * This is a utility method that will throw a <tt>NullPointerException</tt>
+     * This is a utility method that will throw a {@code NullPointerException}
      * in case that the given object is null. The message will be of the form
      * "${name} + may not be null".
      */
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerProxy.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerProxy.java
index 5ff9938..30a1d79 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerProxy.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerProxy.java
@@ -269,6 +269,7 @@
 
     /**
      * Get some info about the event handler
+     * @return Handler info
      */
     public String getInfo() {
         return this.reference.toString() + " [Bundle " + this.reference.getBundle() + "]";
@@ -284,6 +285,7 @@
 
     /**
      * Get the event handler.
+     * @return The event handler or {@code null}
      */
     private synchronized EventHandler obtain() {
         if (this.handler == null)
@@ -325,7 +327,8 @@
 
     /**
      * Get the topics of this handler.
-     * If this handler matches all topics <code>null</code> is returned
+     * If this handler matches all topics {@code null} is returned
+     * @return The topics of this handler or {@code null}
      */
     public String[] getTopics()
     {
@@ -337,6 +340,8 @@
      * - denied
      * - check filter
      * - check permission
+     * @param event The event
+     * @return {@code true} if the event can be delivered
      */
     public boolean canDeliver(final Event event)
     {
@@ -370,6 +375,7 @@
 
     /**
      * Should a timeout be used for this handler?
+     * @return {@code true} if a timeout should be used
      */
     public boolean useTimeout()
     {
@@ -378,6 +384,7 @@
 
     /**
      * Should async events be delivered in order?
+     * @return {@code true} if async events should be delivered in order
      */
     public boolean isAsyncOrderedDelivery()
     {
@@ -386,6 +393,7 @@
 
     /**
      * Check the timeout configuration for this handler.
+     * @param className Handler name
      */
     private void checkTimeout(final String className)
     {
@@ -408,6 +416,7 @@
 
     /**
      * Send the event.
+     * @param event The event
      */
     public void sendEvent(final Event event)
     {
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerTracker.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerTracker.java
index 7c3c5fd..2e33f56 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerTracker.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/handler/EventHandlerTracker.java
@@ -68,7 +68,8 @@
 
     /**
      * Update the timeout configuration.
-     * @param ignoreTimeout
+     * @param ignoreTimeout The configuration for ignoring timeout
+     * @param requireTopic Is a topic required
      */
     public void update(final String[] ignoreTimeout, final boolean requireTopic) {
         final Matchers.Matcher[] ignoreTimeoutMatcher = Matchers.createPackageMatchers(ignoreTimeout);
@@ -227,7 +228,6 @@
 	   /**
      * Get all handlers for this event
      *
-     * @param event The event topic
      * @return All handlers for the event
      */
     public Collection<EventHandlerProxy> getDeniedHandlers() {
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java
index a1c0e19..9cf8c6f 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/EventAdminSecurityDecorator.java
@@ -25,10 +25,10 @@
 import org.osgi.service.event.EventAdmin;
 
 /**
- * This class is a decorator for an <tt>EventAdmin</tt> service. It secures the
+ * This class is a decorator for an {@code EventAdmin} service. It secures the
  * service by checking any call from a given bundle (i.e., the caller) to the admins
  * post or send methods for the appropriate permissions based on a given permission
- * factory. This methods then in turn throw a <tt>SecurityException</tt> in case
+ * factory. This methods then in turn throw a {@code SecurityException} in case
  * the given bundle doesn't pass the check or delegate the call to decorated service
  * instance, respectively.
  *
@@ -45,8 +45,8 @@
     /**
      * The constructor of this decorator. The given bundle and permission factory
      * will be used to determine appropriate permissions for any call to
-     * <tt>postEvent()</tt> or <tt>sendEvent()</tt>, respectively. This method then
-     * in turn throw a <tt>SecurityException</tt> in case the given bundle doesn't
+     * {@code postEvent()} or {@code sendEvent()}, respectively. This method then
+     * in turn throw a {@code SecurityException} in case the given bundle doesn't
      * pass the check.
      *
      * @param bundle The calling bundle used to determine appropriate permissions
@@ -65,7 +65,7 @@
     /**
      * This method checks whether the given (i.e., calling) bundle has
      * appropriate permissions to post an event to the targeted topic. A
-     * <tt>SecurityException</tt> is thrown in case it has not. Otherwise, the
+     * {@code SecurityException} is thrown in case it has not. Otherwise, the
      * event is posted using this decorator's service instance.
      *
      * @param event The event that should be posted
@@ -82,7 +82,7 @@
     /**
      * This method checks whether the given (i.e., calling) bundle has
      * appropriate permissions to send an event to the targeted topic. A
-     * <tt>SecurityException</tt> is thrown in case it has not. Otherwise,
+     * {@code SecurityException} is thrown in case it has not. Otherwise,
      * the event is posted using this decorator's service instance.
      *
      * @param event The event that should be send
@@ -97,7 +97,7 @@
     }
 
     /**
-     * Overrides <tt>hashCode()</tt> and returns the hash code of the decorated
+     * Overrides {@code hashCode()} and returns the hash code of the decorated
      * service instance.
      *
      * @return The hash code of the decorated service instance
@@ -111,7 +111,7 @@
     }
 
     /**
-     * Overrides <tt>equals()</tt> and delegates the call to the decorated service
+     * Overrides {@code equals()} and delegates the call to the decorated service
      * instance. In case that o is an instance of this class it passes o's service
      * instance instead of o.
      *
@@ -131,7 +131,7 @@
     }
 
     /**
-     * This is a utility method that will throw a <tt>SecurityExcepiton</tt> in case
+     * This is a utility method that will throw a {@code SecurityExcepiton} in case
      * that the given bundle (i.e, the caller) has not appropriate permissions to
      * publish to this topic. This method uses Bundle.hasPermission() and the given
      * permission factory to determine this.
@@ -147,7 +147,7 @@
     }
 
     /*
-     * This is a utility method that will throw a <tt>NullPointerException</tt>
+     * This is a utility method that will throw a {@code NullPointerException}
      * in case that the given object is null. The message will be of the form name +
      * may not be null.
      */
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java
index 3bcccd7..da2eef9 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/PermissionsUtil.java
@@ -33,11 +33,11 @@
     private static volatile boolean createPermissions = true;
 
     /**
-     * Creates a <tt>TopicPermission</tt> for the given topic and the type PUBLISH
+     * Creates a {@code TopicPermission} for the given topic and the type PUBLISH
      *
      * @param topic The target topic
      *
-     * @return The created permission or <tt>null</tt> in case the
+     * @return The created permission or {@code null} in case the
      *         permission could not be created.
      *
      * @see org.osgi.service.event.TopicPermission
@@ -60,12 +60,12 @@
     }
 
     /**
-     * Creates a <tt>TopicPermission</tt> for the given topic and the type SUBSCRIBE
+     * Creates a {@code TopicPermission} for the given topic and the type SUBSCRIBE
      * Note that a
      *
      * @param topic The target topic
      *
-     * @return The created permission or a <tt>null</tt> in case the
+     * @return The created permission or a {@code null} in case the
      *      permission could not be created.
      *
      * @see org.osgi.service.event.TopicPermission
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.java
index e3a8e46..71c0c7f 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/security/SecureEventAdminFactory.java
@@ -24,11 +24,11 @@
 import org.osgi.service.event.EventAdmin;
 
 /**
- * This class is a factory that secures a given <tt>EventAdmin</tt> service by
- * wrapping it with a new instance of an <tt>EventAdminSecurityDecorator</tt> on
- * any call to its <tt>getService()</tt> method. The decorator will determine the
+ * This class is a factory that secures a given {@code EventAdmin} service by
+ * wrapping it with a new instance of an {@code EventAdminSecurityDecorator} on
+ * any call to its {@code getService()} method. The decorator will determine the
  * appropriate permissions by using the given permission factory and the bundle
- * parameter passed to the <tt>getService()</tt> method.
+ * parameter passed to the {@code getService()} method.
  *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
@@ -39,10 +39,10 @@
 
     /**
      * The constructor of the factory. The factory will use the given event admin and
-     * permission factory to create a new <tt>EventAdminSecurityDecorator</tt>
-     * on any call to <tt>getService()</tt>.
+     * permission factory to create a new {@code EventAdminSecurityDecorator}
+     * on any call to {@code getService()}.
      *
-     * @param admin The <tt>EventAdmin</tt> service to secure.
+     * @param admin The {@code EventAdmin} service to secure.
      */
     public SecureEventAdminFactory(final EventAdmin admin)
     {
@@ -52,14 +52,14 @@
     }
 
     /**
-     * Returns a new <tt>EventAdminSecurityDecorator</tt> initialized with the
-     * given <tt>EventAdmin</tt>. That in turn will check any call to post or
+     * Returns a new {@code EventAdminSecurityDecorator} initialized with the
+     * given {@code EventAdmin}. That in turn will check any call to post or
      * send for the appropriate permissions based on the bundle parameter.
      *
      * @param bundle The bundle used to determine the permissions of the caller
      * @param registration The ServiceRegistration that is not used
      *
-     * @return The given service instance wrapped by an <tt>EventAdminSecuriryDecorator</tt>
+     * @return The given service instance wrapped by an {@code EventAdminSecuriryDecorator}
      *
      * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle,
      *      org.osgi.framework.ServiceRegistration)
@@ -91,7 +91,7 @@
     }
 
     /*
-     * This is a utility method that will throw a <tt>NullPointerException</tt>
+     * This is a utility method that will throw a {@code NullPointerException}
      * in case that the given object is null. The message will be of the form name +
      * may not be null.
      */
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java
index 651160c..22efdcb 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/AsyncDeliverTasks.java
@@ -62,6 +62,7 @@
      * This does not block an unrelated thread used to send a synchronous event.
      *
      * @param tasks The event handler dispatch tasks to execute
+     * @param event The event
      *
      */
     public void execute(final Collection<EventHandlerProxy> tasks, final Event event)
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DefaultThreadPool.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DefaultThreadPool.java
index b71f51b..baf8b89 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DefaultThreadPool.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DefaultThreadPool.java
@@ -44,6 +44,8 @@
 
     /**
      * Create a new pool.
+     * @param poolSize The size of the pool
+     * @param syncThreads Sync or async pool
      */
     public DefaultThreadPool(final int poolSize, final boolean syncThreads)
     {
@@ -86,6 +88,7 @@
 
     /**
      * Configure a new pool size.
+     * @param poolSize The pool size
      */
     public synchronized void configure(final int poolSize)
     {
@@ -103,6 +106,7 @@
 
     /**
      * Returns current pool size.
+     * @return The pool size
      */
     public int getPoolSize()
     {
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DenylistLatch.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DenylistLatch.java
index 4d5d1b4..3a11ac3 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DenylistLatch.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/DenylistLatch.java
@@ -68,7 +68,7 @@
 	 *
 	 * Adds a handler task to the timeout based deny list checking.
 	 *
-	 * @param task
+	 * @param task The handler task
 	 */
 	public void addToDenylistCheck(final HandlerTask task)
 	{
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTask.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTask.java
index bf9b0d4..7d4c889 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTask.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/HandlerTask.java
@@ -86,6 +86,7 @@
     /**
      * This method defines if a timeout handling should be used for the
      * task.
+     * @return Use timeout?
      */
     public boolean useTimeout()
     {
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
index abec088..8abe392 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncDeliverTasks.java
@@ -35,7 +35,7 @@
  * thread pool and this thread is used to deliver the event.
  * The calling thread is blocked until either the deliver is finished
  * or the timeout occurs.
- * <p><tt>
+ * <p>
  * Note that in case of a timeout while a task is disabled the thread
  * is released and we spin-off a new thread that resumes the disabled
  * task hence, this is the only place were we break the semantics of
@@ -44,7 +44,6 @@
  * blocked the dispatch for to long) but since it will not receive
  * events anymore it will not notice this semantic difference except
  * that it might not see events it already sent before.
- * </tt></pre>
  *
  * If during an event delivery a new event should be delivered from
  * within the event handler, the timeout handler is stopped for the
@@ -63,6 +62,7 @@
     /**
      * Construct a new sync deliver tasks.
      * @param pool The thread pool used to spin-off new threads.
+     * @param timeout The timeout configuration
      */
     public SyncDeliverTasks(final DefaultThreadPool pool, final long timeout)
     {
@@ -72,6 +72,7 @@
 
     /**
      * Update the timeout configuration
+     * @param timeout The timeout configuration
      */
     public void update(final long timeout)
     {
@@ -83,6 +84,8 @@
      * event is send (or a timeout occurs).
      *
      * @param tasks The event handler dispatch tasks to execute
+     * @param event The event
+     * @param filterAsyncUnordered async handling
      *
      */
     public void execute(final Collection<EventHandlerProxy> tasks, final Event event, final boolean filterAsyncUnordered)
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java
index 3ce23b6..34b71b5 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/tasks/SyncThread.java
@@ -30,6 +30,7 @@
 
     /**
      * Constructor used by the thread pool.
+     * @param target The target
      */
     public SyncThread(Runnable target)
     {
diff --git a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/LogWrapper.java b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/LogWrapper.java
index 9b0b22e..b4f1a97 100644
--- a/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/LogWrapper.java
+++ b/eventadmin/impl/src/main/java/org/apache/felix/eventadmin/impl/util/LogWrapper.java
@@ -31,17 +31,17 @@
 import org.osgi.framework.ServiceReference;
 
 /**
- * This class mimics the standard OSGi <tt>LogService</tt> interface. An
+ * This class mimics the standard OSGi {@code LogService} interface. An
  * instance of this class will be used by the EventAdmin for all logging. The
  * implementation of this class sends log messages to standard output, if no
- * <tt>LogService</tt> is present; it uses a log service if one is
+ * {@code LogService} is present; it uses a log service if one is
  * installed in the framework. To do that without creating a hard dependency on the
  * package it uses fully qualified class names and registers a listener with the
- * framework hence, it does not need access to the <tt>LogService</tt> class but will
+ * framework hence, it does not need access to the {@code LogService} class but will
  * use it if the listener is informed about an available service. By using a
  * DynamicImport-Package dependency we don't need the package but
  * use it if present. Additionally, all log methods prefix the log message with
- * <tt>EventAdmin: </tt>.
+ * {@code EventAdmin: }.
  *
  * There is one difference in behavior from the standard OSGi LogService.
  * This logger has a {@link #m_logLevel} property which decides what messages
@@ -122,7 +122,7 @@
     }
 
     /**
-     * Set the <tt>BundleContext</tt> of the bundle. This method registers a service
+     * Set the {@code BundleContext} of the bundle. This method registers a service
      * listener for LogServices with the framework that are subsequently used to
      * log messages.
      * <p>
@@ -234,7 +234,7 @@
 
     /**
      * Log a message with the given log level. Note that this will prefix the message
-     * with <tt>EventAdmin: </tt>.
+     * with {@code EventAdmin: }.
      *
      * @param level The log level with which to log the msg.
      * @param msg The message to log.
@@ -285,7 +285,7 @@
 
     /**
      * Log a message with the given log level and the associated exception. Note that
-     * this will prefix the message with <tt>EventAdmin: </tt>.
+     * this will prefix the message with {@code EventAdmin: }.
      *
      * @param level The log level with which to log the msg.
      * @param msg The message to log.
@@ -337,7 +337,7 @@
 
     /**
      * Log a message with the given log level together with the associated service
-     * reference. Note that this will prefix the message with <tt>EventAdmin: </tt>.
+     * reference. Note that this will prefix the message with {@code EventAdmin: }.
      *
      * @param sr The reference of the service associated with this message.
      * @param level The log level with which to log the msg.
@@ -389,7 +389,7 @@
 
     /**
      * Log a message with the given log level, the associated service reference and
-     * exception. Note that this will prefix the message with <tt>EventAdmin: </tt>.
+     * exception. Note that this will prefix the message with {@code EventAdmin: }.
      *
      * @param sr The reference of the service associated with this message.
      * @param level The log level with which to log the msg.
diff --git a/framework.security/doc/changelog.txt b/framework.security/doc/changelog.txt
index 1f77704..d8e012b 100644
--- a/framework.security/doc/changelog.txt
+++ b/framework.security/doc/changelog.txt
@@ -1,3 +1,9 @@
+Changes from 2.6.1 to 2.8.0
+---------------------------
+
+** Improvement
+    * [FELIX-6369] - Implement R8 core spec
+
 Changes from 2.6.0 to 2.6.1
 ---------------------------
 
diff --git a/framework.security/pom.xml b/framework.security/pom.xml
index 11e58dc..0aff375 100644
--- a/framework.security/pom.xml
+++ b/framework.security/pom.xml
@@ -27,7 +27,7 @@
   <packaging>bundle</packaging>
   <name>Apache Felix Security Provider</name>
   <artifactId>org.apache.felix.framework.security</artifactId>
-  <version>2.7.0-SNAPSHOT</version>
+  <version>2.9.0-SNAPSHOT</version>
   <description>
     This bundle provides an implementation of the OSGi security for Apache Felix.
   </description>
@@ -35,7 +35,8 @@
       <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
       <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
       <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
-    </scm>
+      <tag>HEAD</tag>
+  </scm>
   <dependencies>
      <dependency>
       <groupId>org.osgi</groupId>
@@ -45,7 +46,7 @@
     <dependency>
       <groupId>${pom.groupId}</groupId>
       <artifactId>org.apache.felix.framework</artifactId>
-      <version>6.1.0-SNAPSHOT</version>
+      <version>7.1.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
   <build>
diff --git a/framework.security/src/main/java/org/apache/felix/framework/FakeBundle.java b/framework.security/src/main/java/org/apache/felix/framework/FakeBundle.java
index f7b3d9b..19a0506 100644
--- a/framework.security/src/main/java/org/apache/felix/framework/FakeBundle.java
+++ b/framework.security/src/main/java/org/apache/felix/framework/FakeBundle.java
@@ -185,11 +185,6 @@
         return System.identityHashCode(this);
     }
 
-    public int compareTo(Bundle o) {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
     public Object adapt(Class arg0) {
         // TODO Auto-generated method stub
         return null;
@@ -199,9 +194,4 @@
         // TODO Auto-generated method stub
         return null;
     }
-
-    public int compareTo(Object t)
-    {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
 }
diff --git a/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java b/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java
index 4df53f2..801182e 100644
--- a/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java
+++ b/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java
@@ -34,12 +34,16 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.PropertyPermission;
 
 import org.apache.felix.framework.util.SecureAction;
 import org.osgi.framework.AdminPermission;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.CapabilityPermission;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.PackagePermission;
+import org.osgi.framework.ServicePermission;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.packageadmin.ExportedPackage;
 import org.osgi.service.packageadmin.PackageAdmin;
@@ -107,12 +111,15 @@
     {
         return new PermissionInfo[] {
             IMPLICIT[0],
-            new PermissionInfo(AdminPermission.class.getName(), "(id="
-                + bundle.getBundleId() + ")", AdminPermission.METADATA),
-            new PermissionInfo(AdminPermission.class.getName(), "(id="
-                + bundle.getBundleId() + ")", AdminPermission.RESOURCE),
-            new PermissionInfo(AdminPermission.class.getName(), "(id="
-                + bundle.getBundleId() + ")", AdminPermission.CONTEXT) };
+            new PermissionInfo(PropertyPermission.class.getName(), "org.osgi.framework.*", "read"),
+            new PermissionInfo(
+                AdminPermission.class.getName(),
+                "(id=" + bundle.getBundleId() + ")",
+                AdminPermission.CLASS + "," + AdminPermission.METADATA + "," + AdminPermission.RESOURCE + "," + AdminPermission.CONTEXT),
+            new PermissionInfo(CapabilityPermission.class.getName(), "(|(capability.namespace=osgi.ee)(capability.namespace=osgi.native))", CapabilityPermission.REQUIRE),
+            new PermissionInfo(PackagePermission.class.getName(),"(package.name=java.*)",PackagePermission.IMPORT),
+            new PermissionInfo(ServicePermission.class.getName(),"org.osgi.service.condition.Condition", ServicePermission.GET)
+        };
     }
 
     public Permissions getPermissions(PermissionInfo[] permissionInfos)
diff --git a/framework/doc/changelog.txt b/framework/doc/changelog.txt
index 4da82c6..b333393 100644
--- a/framework/doc/changelog.txt
+++ b/framework/doc/changelog.txt
@@ -1,3 +1,27 @@
+Changes from 6.0.4 to 7.0.0
+---------------------------
+
+** Improvement
+    * [FELIX-6369] - Implement R8 core spec
+    * [FELIX-6175] - default.properties resource file would conflict with other libraries
+
+** Bug
+    * [FELIX-5975] - URLHandlersStreamHandlerProxy - OPEN_CONNECTION_PROXY null
+    * [FELIX-6163] - ServiceTracker should not use System.currentTimeMillis() to check timeouts
+    * [FELIX-6184] - NoClassDefFoundError: jdk/internal/reflect/ConstructorAccessorImpl with Oracle JDK 11.0.3
+    * [FELIX-6294] - Missing trailing slash with Bundle.getResource() for directory entry
+
+Changes from 6.0.3 to 6.0.4
+---------------------------
+
+** Bug
+    * [FELIX-6178] - org.osgi.framework.Bundle#getServicesInUse returns services with usage count = 0
+    * [FELIX-6222] - Support for os.name Capability is missing for Windows Server 2019
+    * [FELIX-6297] - unclosed InputStream on Bundle.start
+    * [FELIX-6318] - Tiny thread-safety bug in BundleWiringImpl
+    * [FELIX-6326] - Cannot read bundled resources with hash in the filename
+    * [FELIX-6331] - Race condition in unget service from service factory
+
 Changes from 6.0.2 to 6.0.3
 ---------------------------
 
diff --git a/framework/pom.xml b/framework/pom.xml
index d83ac02..a0894ff 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -21,35 +21,91 @@
     <groupId>org.apache.felix</groupId>
     <artifactId>felix-parent</artifactId>
     <version>6</version>
-    <relativePath>../../pom/pom.xml</relativePath>
+    <relativePath>../pom/pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <packaging>bundle</packaging>
   <name>Apache Felix Framework</name>
   <artifactId>org.apache.felix.framework</artifactId>
-  <version>6.1.0-SNAPSHOT</version>
+  <version>7.1.0-SNAPSHOT</version>
   <properties>
     <dollar>$</dollar>
-    <felix.java.version>6</felix.java.version>
+    <felix.java.version>8</felix.java.version>
   </properties>
   <scm>
-      <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
-      <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
-      <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
+    <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
+    <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
+    <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
+    <tag>HEAD</tag>
   </scm>
 
   <build>
     <plugins>
       <plugin>
+        <groupId>org.moditect</groupId>
+        <artifactId>moditect-maven-plugin</artifactId>
+        <version>1.0.0.RC1</version>
+        <executions>
+          <execution>
+            <id>add-module-infos</id>
+            <phase>package</phase>
+            <goals>
+              <goal>add-module-info</goal>
+            </goals>
+            <configuration>
+              <module>
+              <moduleInfoSource>
+                open module org.apache.felix.framework {
+                    requires jdk.unsupported;
+
+                    exports org.apache.felix.framework.ext;
+                    exports org.osgi.dto;
+                    exports org.osgi.framework;
+                    exports org.osgi.framework.connect;
+                    exports org.osgi.framework.dto;
+                    exports org.osgi.framework.hooks.bundle;
+                    exports org.osgi.framework.hooks.resolver;
+                    exports org.osgi.framework.hooks.service;
+                    exports org.osgi.framework.hooks.weaving;
+                    exports org.osgi.framework.launch;
+                    exports org.osgi.framework.namespace;
+                    exports org.osgi.framework.startlevel;
+                    exports org.osgi.framework.startlevel.dto;
+                    exports org.osgi.framework.wiring;
+                    exports org.osgi.framework.wiring.dto;
+                    exports org.osgi.resource;
+                    exports org.osgi.resource.dto;
+                    exports org.osgi.service.condition;
+                    exports org.osgi.service.packageadmin;
+                    exports org.osgi.service.resolver;
+                    exports org.osgi.service.startlevel;
+                    exports org.osgi.service.url;
+                    exports org.osgi.util.tracker;
+                    provides org.osgi.framework.launch.FrameworkFactory with
+                      org.apache.felix.framework.FrameworkFactory;
+                    provides org.osgi.framework.connect.ConnectFrameworkFactory with
+                      org.apache.felix.framework.FrameworkFactory;
+
+                    uses org.apache.felix.framework.ext.ClassPathExtenderFactory;
+                    uses org.osgi.framework.connect.FrameworkUtilHelper;
+                    }
+                </moduleInfoSource>
+              </module>
+              <overwriteExistingFiles>true</overwriteExistingFiles>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>4.1.0</version>
+        <version>5.1.1</version>
         <extensions>true</extensions>
         <configuration>
           <instructions>
             <Bundle-SymbolicName>org.apache.felix.framework</Bundle-SymbolicName>
             <Bundle-Name>Apache Felix Framework</Bundle-Name>
-            <Bundle-Description>OSGi R7 framework implementation.</Bundle-Description>
+            <Bundle-Description>OSGi R8 framework implementation.</Bundle-Description>
             <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
             <Export-Package>
                 org.osgi.framework.*;-split-package:=first,
@@ -60,7 +116,8 @@
                 org.osgi.service.url;-split-package:=first,
                 org.osgi.service.resolver,
                 org.osgi.util.tracker;-split-package:=first,
-                org.osgi.dto;-split-package:=first
+                org.osgi.dto;-split-package:=first,
+                org.osgi.service.condition;-split-package:=first
             </Export-Package>
             <Private-Package>org.apache.felix.framework.*, org.apache.felix.resolver.*</Private-Package>
             <Import-Package>!*</Import-Package>
@@ -89,7 +146,7 @@
               <excludes>
                   <exclude>src/main/appended-resources/**</exclude>
                   <exclude>src/**/packageinfo</exclude>
-                  <exclude>src/main/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactory</exclude>
+                  <exclude>src/main/resources/META-INF/**</exclude>
                   <exclude>src/main/resources/org/apache/felix/framework/Felix.properties</exclude>
               </excludes>
             </configuration>
@@ -118,18 +175,19 @@
       <resource>
         <directory>src/main/resources</directory>
         <filtering>true</filtering>
+        <excludes>
+        <exclude>**/*.bytes</exclude>
+        </excludes>
+      </resource>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>false</filtering>
+        <includes>
+          <include>**/*.bytes</include>
+        </includes>
       </resource>
     </resources>
   </build>
-  <dependencyManagement>
-      <dependencies>
-          <dependency>
-              <groupId>org.hamcrest</groupId>
-              <artifactId>hamcrest-core</artifactId>
-              <version>1.3</version>
-          </dependency>
-      </dependencies>
-  </dependencyManagement>
   <dependencies>
     <dependency>
        <groupId>org.osgi</groupId>
@@ -140,7 +198,7 @@
     <dependency>
        <groupId>org.apache.felix</groupId>
        <artifactId>org.apache.felix.resolver</artifactId>
-       <version>2.1.0-SNAPSHOT</version>
+       <version>2.0.2</version>
        <scope>provided</scope>
         <exclusions>
             <exclusion>
@@ -152,7 +210,7 @@
     <dependency>
         <groupId>org.ow2.asm</groupId>
         <artifactId>asm-all</artifactId>
-        <version>4.2</version>
+        <version>5.2</version>
         <scope>test</scope>
     </dependency>
     <dependency>
@@ -163,7 +221,7 @@
     </dependency>
     <dependency>
         <groupId>org.mockito</groupId>
-        <artifactId>mockito-core</artifactId>
+        <artifactId>mockito-all</artifactId>
         <version>1.10.19</version>
         <scope>test</scope>
     </dependency>
diff --git a/framework/src/main/appended-resources/META-INF/NOTICE b/framework/src/main/appended-resources/META-INF/NOTICE
index d4d1ad8..246e269 100644
--- a/framework/src/main/appended-resources/META-INF/NOTICE
+++ b/framework/src/main/appended-resources/META-INF/NOTICE
@@ -1,4 +1,4 @@
 This product includes software developed at
 The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2015).
+Copyright (c) OSGi Alliance (2000, 2020).
 Licensed under the Apache License 2.0.
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index d3b6724..7dd59d0 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -67,6 +67,7 @@
 
     private final BundleArchive m_archive;
     private final List<BundleRevisionImpl> m_revisions = new ArrayList<BundleRevisionImpl>(0);
+    private volatile BundleRevisionImpl m_currentRevision = null;
     private volatile int m_state;
     private boolean m_useDeclaredActivationPolicy;
     private BundleActivator m_activator = null;
@@ -188,16 +189,24 @@
         {
             // Get current revision, since we can reuse it.
             BundleRevisionImpl current = adapt(BundleRevisionImpl.class);
-            // Close all existing revisions.
-            closeRevisions();
-            // Clear all revisions.
+
+            if (isRemovalPending()) {
+                closeRevisions();
+                // Purge all old archive revisions, only keeping the newest one.
+                m_archive.purge();
+
+                current.resetContent(m_archive.getCurrentRevision().getContent());
+            }
+            else {
+                // Remove the revision from the resolver state.
+                getFramework().getResolver().removeRevision(current);
+                current.resolve(null);
+                current.disposeContentPath();
+            }
+
             m_revisions.clear();
+            m_currentRevision = null;
 
-            // Purge all old archive revisions, only keeping the newest one.
-            m_archive.purge();
-
-            // Reset the content of the current bundle revision.
-            current.resetContent(m_archive.getCurrentRevision().getContent());
             // Re-add the revision to the bundle.
             addRevision(current);
 
@@ -1091,7 +1100,7 @@
     }
 
     @Override
-    public synchronized <A> A adapt(Class<A> type)
+    public <A> A adapt(Class<A> type)
     {
         checkAdapt(type);
         if (type == BundleContext.class)
@@ -1109,14 +1118,14 @@
             {
                 return null;
             }
-            return (A) m_revisions.get(0);
+            return (A) m_currentRevision;
         }
         // We need some way to get the current revision even if
         // the associated bundle is uninstalled, so we use the
         // impl revision class for this purpose.
         else if (type == BundleRevisionImpl.class)
         {
-            return (A) m_revisions.get(0);
+            return (A) m_currentRevision;
         }
         else if (type == BundleRevisions.class)
         {
@@ -1128,7 +1137,9 @@
             {
                 return null;
             }
-            return (A) m_revisions.get(0).getWiring();
+            BundleRevisionImpl revision = m_currentRevision;
+
+            return (A) (revision != null ? revision.getWiring() : null);
         }
         else if ( type == AccessControlContext.class)
         {
@@ -1229,6 +1240,8 @@
     synchronized boolean rollbackRevise() throws Exception
     {
         BundleRevision br = m_revisions.remove(0);
+        m_currentRevision = !m_revisions.isEmpty() ? m_revisions.get(0) : null;
+
         // Since revising a bundle adds a revision to the global
         // state, we must remove it from the global state on rollback.
         getFramework().getResolver().removeRevision(br);
@@ -1242,7 +1255,9 @@
     // which is the normal case.
     synchronized void addRevision(BundleRevisionImpl revision) throws Exception
     {
+        BundleRevisionImpl previous = m_currentRevision;
         m_revisions.add(0, revision);
+        m_currentRevision = revision;
 
         try
         {
@@ -1251,6 +1266,7 @@
         catch (Exception ex)
         {
             m_revisions.remove(0);
+            m_currentRevision = previous;
             throw ex;
         }
 
@@ -1332,7 +1348,7 @@
                     }
                 }
             }
-            if (!collisionCanditates.isEmpty())
+            if (!collisionCanditates.isEmpty() && m_installingBundle != null)
             {
                 throw new BundleException(
                     "Bundle symbolic name and version are not unique: "
@@ -1347,7 +1363,7 @@
     {
         ProtectionDomain pd = null;
 
-        for (int i = m_revisions.size() - 1; (i >= 0) && (pd == null); i--)
+        for (int i = 0; (i < m_revisions.size()) && (pd == null); i++)
         {
             pd = m_revisions.get(i).getProtectionDomain();
         }
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java b/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java
index ccd4807..9d51085 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java
@@ -21,13 +21,10 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
-import java.net.JarURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -45,16 +42,12 @@
 import java.util.Enumeration;
 import java.util.List;
 import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
 import java.util.jar.JarOutputStream;
 import org.apache.felix.framework.cache.Content;
 import org.apache.felix.framework.cache.JarContent;
 import org.apache.felix.framework.util.FelixConstants;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.PackagePermission;
 
-import org.osgi.framework.wiring.BundleRevision;
-
 public class BundleProtectionDomain extends ProtectionDomain
 {
     private static final class BundleInputStream extends InputStream
@@ -76,7 +69,7 @@
 
             int count = 0;
             String manifest = null;
-            for (Enumeration e = m_root.getEntries(); e.hasMoreElements();)
+            for (Enumeration e = m_root.getEntries(); e != null && e.hasMoreElements();)
             {
                 String entry = (String) e.nextElement();
                 if (entry.endsWith("/"))
@@ -264,12 +257,12 @@
                 {
                     target = Felix.m_secureAction.createTempFile("jar", null, null);
                     Felix.m_secureAction.deleteFileOnExit(target);
-                    FileOutputStream output = null;
+                    OutputStream output = null;
                     InputStream input = null;
                     IOException rethrow = null;
                     try
                     {
-                        output = new FileOutputStream(target);
+                        output = Felix.m_secureAction.getOutputStream(target);
                         input = new BundleInputStream(content);
                         byte[] buffer = new byte[64 * 1024];
                         for (int i = input.read(buffer);i != -1; i = input.read(buffer))
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
index 036732b..388e426 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleRevisionImpl.java
@@ -319,6 +319,15 @@
         }
     }
 
+    synchronized void disposeContentPath()
+    {
+        for (int i = 0; (m_contentPath != null) && (i < m_contentPath.size()); i++)
+        {
+            m_contentPath.get(i).close();
+        }
+        m_contentPath = null;
+    }
+
     public void setProtectionDomain(ProtectionDomain pd)
     {
         m_protectionDomain = pd;
@@ -505,6 +514,10 @@
         {
             if (contentPath.get(i).hasEntry(name))
             {
+                if (!name.endsWith("/") && contentPath.get(i).isDirectory(name))
+                {
+                    name += "/";
+                }
                 url = createURL(i + 1, name);
             }
         }
@@ -543,6 +556,10 @@
             {
                 if (contentPath.get(i).hasEntry(name))
                 {
+                    if (!name.endsWith("/") && contentPath.get(i).isDirectory(name))
+                    {
+                        name += "/";
+                    }
                     // Use the class path index + 1 for creating the path so
                     // that we can differentiate between module content URLs
                     // (where the path will start with 0) and module class
@@ -579,6 +596,10 @@
             // Check the module content.
             if (getContent().hasEntry(name))
             {
+                if (!name.endsWith("/") && getContent().isDirectory(name))
+                {
+                    name += "/";
+                }
                 // Module content URLs start with 0, whereas module
                 // class path URLs start with the index into the class
                 // path + 1.
@@ -616,6 +637,25 @@
         return getContentPath().get(index - 1).getEntryAsStream(urlPath);
     }
 
+
+    public long getContentTime(int index, String urlPath)
+    {
+        if (urlPath.startsWith("/"))
+        {
+            urlPath = urlPath.substring(1);
+        }
+        Content content;
+        if (index == 0)
+        {
+            content = getContent();
+        }
+        else {
+            content = getContentPath().get(index - 1);
+        }
+        long result = content.getContentTime(urlPath);
+        return result > 0 ? result : m_bundle.getLastModified();
+    }
+
     public URL getLocalURL(int index, String urlPath)
     {
         if (urlPath.startsWith("/"))
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index 437d962..0e970bc 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.framework;
 
+import org.apache.felix.framework.cache.ConnectContentContent;
 import org.apache.felix.framework.cache.Content;
 import org.apache.felix.framework.capabilityset.SimpleFilter;
 import org.apache.felix.framework.resolver.ResourceNotFoundException;
@@ -112,7 +113,7 @@
 
     private volatile List<BundleRequirement> m_wovenReqs = null;
 
-    private volatile BundleClassLoader m_classLoader;
+    private volatile ClassLoader m_classLoader;
 
     // Bundle-specific class loader for boot delegation.
     private final ClassLoader m_bootClassLoader;
@@ -726,16 +727,24 @@
         // is not disposed.
         if (!m_isDisposed && (m_classLoader == null))
         {
-            m_classLoader = BundleRevisionImpl.getSecureAction().run(
-                new PrivilegedAction<BundleClassLoader>()
-                {
-                    @Override
-                    public BundleClassLoader run()
+            if (m_revision.getContent() instanceof ConnectContentContent)
+            {
+                m_classLoader = ((ConnectContentContent) m_revision.getContent()).getClassLoader();
+            }
+
+            if (m_classLoader == null)
+            {
+                m_classLoader = BundleRevisionImpl.getSecureAction().run(
+                    new PrivilegedAction<BundleClassLoader>()
                     {
-                        return new BundleClassLoader(BundleWiringImpl.this, determineParentClassLoader(), m_logger);
+                        @Override
+                        public BundleClassLoader run()
+                        {
+                            return new BundleClassLoader(BundleWiringImpl.this, determineParentClassLoader(), m_logger);
+                        }
                     }
-                }
-            );
+                );
+            }
         }
         return m_classLoader;
     }
@@ -1490,24 +1499,21 @@
 
                     try
                     {
-                        result = tryImplicitBootDelegation(name, isClass);
-                    }
-                    catch (Exception ex)
-                    {
-                        // Ignore, will throw using CNFE_CLASS_LOADER
-                    }
+                        // Get the appropriate class loader for delegation.
+                        ClassLoader bdcl = getBootDelegationClassLoader();
+                        result = (isClass) ? (Object) bdcl.loadClass(name) : (Object) bdcl.getResource(name);
 
-                    if (result != null)
-                    {
-                        m_accessorLookupCache.put(name, BundleRevisionImpl.getSecureAction()
-                                .getClassLoader(this.getClass()));
-                        return result;
+                        if (result != null)
+                        {
+                            m_accessorLookupCache.put(name, bdcl);
+                            return result;
+                        }
                     }
-                    else
+                    catch (ClassNotFoundException ex)
                     {
-                        m_accessorLookupCache.put(name, CNFE_CLASS_LOADER);
-                        CNFE_CLASS_LOADER.loadClass(name);
                     }
+                    m_accessorLookupCache.put(name, CNFE_CLASS_LOADER);
+                    CNFE_CLASS_LOADER.loadClass(name);
                 }
 
                 // Look in the revision's imports. Note that the search may
@@ -1518,25 +1524,39 @@
                 // If not found, try the revision's own class path.
                 if (result == null)
                 {
-                    if (isClass)
+                    ClassLoader cl = getClassLoaderInternal();
+                    if (cl == null)
                     {
-                        ClassLoader cl = getClassLoaderInternal();
-                        if (cl == null)
+                        if (isClass)
                         {
                             throw new ClassNotFoundException(
-                                    "Unable to load class '"
-                                            + name
-                                            + "' because the bundle wiring for "
-                                            + m_revision.getSymbolicName()
-                                            + " is no longer valid.");
+                                "Unable to load class '"
+                                    + name
+                                    + "' because the bundle wiring for "
+                                    + m_revision.getSymbolicName()
+                                    + " is no longer valid.");
                         }
-                        result = ((BundleClassLoader) cl).findClass(name);
+                        else
+                        {
+                            throw new ResourceNotFoundException("Unable to load resource '"
+                                + name
+                                + "' because the bundle wiring for "
+                                + m_revision.getSymbolicName()
+                                + " is no longer valid.");
+                        }
+                    }
+                    if (cl instanceof BundleClassLoader)
+                    {
+                        result = isClass ? ((BundleClassLoader) cl).findClass(name) :
+                            ((BundleClassLoader) cl).findResource(name);
                     }
                     else
                     {
-                        result = m_revision.getResourceLocal(name);
+                        result = isClass ? cl.loadClass(name) : !name.startsWith("/") ? cl.getResource(name) :
+                        cl.getResource(name.substring(1));
                     }
 
+
                     // If still not found, then try the revision's dynamic imports.
                     if (result == null)
                     {
@@ -2052,7 +2072,7 @@
                         catch (Error e)
                         {
                             // Mark the woven class as incomplete.
-                            wci.complete(null, null, null);
+                            wci.complete();
                             wci.setState(WovenClass.TRANSFORMING_FAILED);
                             callWovenClassListeners(felix, wovenClassListeners, wci);
                             throw e;
diff --git a/framework/src/main/java/org/apache/felix/framework/DTOFactory.java b/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
index 0abcf9c..7d38e40 100644
--- a/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
+++ b/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
@@ -120,6 +120,11 @@
         return null;
     }
 
+    static ServiceReferenceDTO createDTO(ServiceReference ref)
+    {
+        return createServiceReferenceDTO(ref);
+    }
+
     private static BundleDTO createBundleDTO(Bundle bundle)
     {
         BundleDTO dto = new BundleDTO();
diff --git a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
index a5c8664..5f0ee34 100644
--- a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
+++ b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.framework;
 
+import org.apache.felix.framework.cache.ConnectContentContent;
 import org.apache.felix.framework.cache.Content;
 import org.apache.felix.framework.cache.DirectoryContent;
 import org.apache.felix.framework.cache.JarContent;
@@ -53,8 +54,6 @@
 import org.osgi.framework.wiring.BundleWiring;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -245,11 +244,23 @@
 
         String sysprops = felix._getProperty(Constants.FRAMEWORK_SYSTEMPACKAGES);
 
+
+        boolean subst = "true".equalsIgnoreCase(felix._getProperty(FelixConstants.USE_PROPERTY_SUBSTITUTION_IN_SYSTEMPACKAGES));
+
+        if (sysprops != null && sysprops.isEmpty())
+        {
+            if (felix.hasConnectFramework())
+            {
+                subst = true;
+                sysprops = "${osgi-exports}";
+                config.put(Constants.FRAMEWORK_SYSTEMPACKAGES, sysprops);
+            }
+        }
+
         final Map<String, Set<String>> exports = Util.initializeJPMS(defaultProperties);
 
         if (exports != null && (sysprops == null || "true".equalsIgnoreCase(felix._getProperty(FelixConstants.USE_PROPERTY_SUBSTITUTION_IN_SYSTEMPACKAGES))))
         {
-            java.nio.file.FileSystem fs = java.nio.file.FileSystems.getFileSystem(URI.create("jrt:/"));
             final ClassParser classParser = new ClassParser();
             final Set<String> imports = new HashSet<String>();
             for (Set<String> moduleImport : exports.values())
@@ -271,15 +282,16 @@
                     final SortedMap<String, SortedSet<String>> referred = new TreeMap<String, SortedSet<String>>();
                     if ("true".equalsIgnoreCase(felix._getProperty(FelixConstants.CALCULATE_SYSTEMPACKAGES_USES)))
                     {
+                        java.nio.file.FileSystem fs = java.nio.file.FileSystems.getFileSystem(URI.create("jrt:/"));
                         try
                         {
                             Properties cachedProps = new Properties();
                             File modulesDir = felix.getDataFile(felix, "modules");
-                            modulesDir.mkdirs();
+                            Felix.m_secureAction.mkdirs(modulesDir);
                             File cached = new File(modulesDir, moduleKey + ".properties");
-                            if (cached.isFile())
+                            if (Felix.m_secureAction.isFile(cached))
                             {
-                                FileInputStream input = new FileInputStream(cached);
+                                InputStream input = Felix.m_secureAction.getInputStream(cached);
                                 cachedProps.load(new InputStreamReader(input, "UTF-8"));
                                 input.close();
                                 for (Enumeration<?> keys = cachedProps.propertyNames(); keys.hasMoreElements();)
@@ -301,7 +313,7 @@
                                         cachedProps.setProperty(pkg, String.join(",", uses));
                                     }
                                 }
-                                OutputStream output = new FileOutputStream(cached);
+                                OutputStream output = Felix.m_secureAction.getOutputStream(cached);
                                 cachedProps.store(new OutputStreamWriter(output, "UTF-8"), null);
                                 output.close();
                             }
@@ -344,7 +356,7 @@
             }
         }
 
-        if(sysprops != null && "true".equalsIgnoreCase(felix._getProperty(FelixConstants.USE_PROPERTY_SUBSTITUTION_IN_SYSTEMPACKAGES)))
+        if(sysprops != null && subst)
         {
             config.put(Constants.FRAMEWORK_SYSTEMPACKAGES, Util.getPropertyWithSubs(Util.toProperties(config), Constants.FRAMEWORK_SYSTEMPACKAGES));
         }
@@ -414,23 +426,6 @@
             ((BundleRevisionImpl) bundle.adapt(BundleRevision.class))
                 .getHeaders().get(Constants.FRAGMENT_HOST));
 
-        if (!Constants.EXTENSION_FRAMEWORK.equals(directive))
-        {
-           throw new BundleException("Unsupported Extension Bundle type: " +
-                directive, new UnsupportedOperationException(
-                "Unsupported Extension Bundle type!"));
-        }
-        else if (m_extenderFramework == null)
-        {
-            // We don't support extensions
-            m_logger.log(bundle, Logger.LOG_WARNING,
-                "Unable to add extension bundle - Maybe ClassLoader is not supported " +
-                        "(on java9, try --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED)?");
-
-            throw new UnsupportedOperationException(
-                "Unable to add extension bundle.");
-        }
-
         Content content = bundle.adapt(BundleRevisionImpl.class).getContent();
         final File file;
         if (content instanceof JarContent)
@@ -445,14 +440,31 @@
         {
             file = null;
         }
-        if (file == null)
+        if (file == null && !(content instanceof ConnectContentContent))
         {
             // We don't support revision type for extension
             m_logger.log(bundle, Logger.LOG_WARNING,
-                    "Unable to add extension bundle - wrong revision type?");
+                "Unable to add extension bundle - wrong revision type?");
 
             throw new UnsupportedOperationException(
-                    "Unable to add extension bundle.");
+                "Unable to add extension bundle.");
+        }
+
+        if (!Constants.EXTENSION_FRAMEWORK.equals(directive))
+        {
+           throw new BundleException("Unsupported Extension Bundle type: " +
+                directive, new UnsupportedOperationException(
+                "Unsupported Extension Bundle type!"));
+        }
+        else if (m_extenderFramework == null && file != null)
+        {
+            // We don't support extensions
+            m_logger.log(bundle, Logger.LOG_WARNING,
+                "Unable to add extension bundle - Maybe ClassLoader is not supported " +
+                        "(on java9, try --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED)?");
+
+            throw new UnsupportedOperationException(
+                "Unable to add extension bundle.");
         }
 
         BundleRevisionImpl bri = bundle.adapt(BundleRevisionImpl.class);
@@ -559,25 +571,33 @@
             {
                 f = ((JarContent) revisionContent).getFile();
             }
-            else
+            else if (revisionContent instanceof DirectoryContent)
             {
                 f = ((DirectoryContent) revisionContent).getFile();
             }
-            try
+            else
             {
-                AccessController.doPrivileged(new PrivilegedExceptionAction<Void>()
-                {
-                    @Override
-                    public Void run() throws Exception {
-                        m_extenderFramework.add(f);
-                        return null;
-                    }
-                });
+                f = null;
             }
-            catch (Exception ex)
+            if (f != null)
             {
-                m_logger.log(revision.getBundle(), Logger.LOG_ERROR,
-                    "Error adding extension bundle to framework classloader: " + revision.getBundle(), ex);
+                try
+                {
+                    AccessController.doPrivileged(new PrivilegedExceptionAction<Void>()
+                    {
+                        @Override
+                        public Void run() throws Exception
+                        {
+                            m_extenderFramework.add(f);
+                            return null;
+                        }
+                    });
+                }
+                catch (Exception ex)
+                {
+                    m_logger.log(revision.getBundle(), Logger.LOG_ERROR,
+                        "Error adding extension bundle to framework classloader: " + revision.getBundle(), ex);
+                }
             }
 
             felix.setBundleStateAndNotify(revision.getBundle(), Bundle.RESOLVED);
@@ -849,7 +869,14 @@
         };
     }
 
-    public boolean hasEntry(String name) {
+    public boolean hasEntry(String name)
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isDirectory(String name)
+    {
         return false;
     }
 
@@ -878,6 +905,12 @@
         return null;
     }
 
+    @Override
+    public long getContentTime(String name)
+    {
+        return -1L;
+    }
+
     //
     // Utility methods.
     //
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 46792c5..ade90ee 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -58,6 +58,7 @@
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.Version;
+import org.osgi.framework.connect.ModuleConnector;
 import org.osgi.framework.launch.Framework;
 import org.osgi.framework.namespace.HostNamespace;
 import org.osgi.framework.startlevel.FrameworkStartLevel;
@@ -74,9 +75,7 @@
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -213,6 +212,8 @@
     // Do we need to consult the default java security policy if no security provider is present?
     private volatile boolean m_securityDefaultPolicy;
 
+    private final ModuleConnector m_connectFramework;
+
     /**
      * <p>
      * This constructor creates a framework instance with a specified <tt>Map</tt>
@@ -351,6 +352,11 @@
     **/
     public Felix(Map configMap)
     {
+        this(configMap, null);
+    }
+
+    public Felix(Map configMap, ModuleConnector connectFramework)
+    {
         super();
         // Copy the configuration properties; convert keys to strings.
         m_configMutableMap = new StringMap();
@@ -460,6 +466,8 @@
         m_fwkWiring = new FrameworkWiringImpl(this, m_registry);
         // Create framework start level object.
         m_fwkStartLevel = new FrameworkStartLevelImpl(this, m_registry);
+
+        m_connectFramework = connectFramework;
     }
 
     Logger getLogger()
@@ -634,12 +642,12 @@
         return true;
     }
 
-
     @Override
     public void init() throws BundleException
     {
-        init((FrameworkListener[]) null);
+        init(null);
     }
+
     /**
      * @see org.osgi.framework.launch.Framework#init(org.osgi.framework.FrameworkListener[])
      */
@@ -726,6 +734,10 @@
                             throw new BundleException("Unable to flush bundle cache.", ex);
                         }
                     }
+                    if (m_connectFramework != null)
+                    {
+                        m_connectFramework.initialize(m_cache.getCacheDir(), (Map) m_configMap);
+                    }
                 }
 
                 // Initialize installed bundle data structures.
@@ -774,7 +786,6 @@
                         "Unresolved constraint in System Bundle:"
                         + ex.getUnresolvedRequirements());
                 }
-
                 // Reload the cached bundles before creating and starting the
                 // system bundle, since we want all cached bundles to be reloaded
                 // when we activate the system bundle and any subsequent system
@@ -784,7 +795,7 @@
                 // First get cached bundle identifiers.
                 try
                 {
-                    archives = m_cache.getArchives();
+                    archives = m_cache.getArchives(m_connectFramework);
                 }
                 catch (Exception ex)
                 {
@@ -850,6 +861,12 @@
                     m_extensionManager.startExtensionBundle(this, (BundleImpl) extension);
                 }
 
+
+                if (m_connectFramework != null)
+                {
+                    m_connectFramework.newBundleActivator().ifPresent(m_activatorList::add);
+                }
+
                 // Now that we have loaded all cached bundles and have determined the
                 // max bundle ID of cached bundles, we need to try to load the next
                 // bundle ID from persistent storage. In case of failure, we should
@@ -884,7 +901,6 @@
                 }
                 catch (Throwable ex)
                 {
-                    m_dispatcher.stopDispatching();
                     m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
                     throw new RuntimeException("Unable to start system bundle.");
                 }
@@ -948,6 +964,17 @@
                 }
             }
         }
+        catch (Throwable t)
+        {
+            stopBundle(this, false);
+            if (m_cache != null)
+            {
+                m_cache.release();
+                m_cache = null;
+            }
+            __setState(Bundle.INSTALLED);
+            throw t;
+        }
         finally
         {
             releaseBundleLock(this);
@@ -987,7 +1014,7 @@
             BufferedReader input = null;
             try
             {
-                input = new BufferedReader(new InputStreamReader(new FileInputStream(dataFile), "UTF-8"));
+                input = new BufferedReader(new InputStreamReader(m_secureAction.getInputStream(dataFile), "UTF-8"));
                 lastVersion = Version.parseVersion(input.readLine()).getMajor();
             }
             catch (Exception ignore)
@@ -1020,7 +1047,7 @@
         try
         {
             output = new PrintWriter(new OutputStreamWriter(
-                new FileOutputStream(getDataFile(this, "last.java.version")), "UTF-8"));
+                m_secureAction.getOutputStream(getDataFile(this, "last.java.version")), "UTF-8"));
             output.println(Integer.toString(currentVersion));
             output.flush();
         }
@@ -3224,7 +3251,7 @@
                 try
                 {
                     // Add the bundle to the cache.
-                    ba = m_cache.create(id, getInitialBundleStartLevel(), location, is);
+                    ba = m_cache.create(id, getInitialBundleStartLevel(), location, is, m_connectFramework);
                 }
                 catch (Exception ex)
                 {
@@ -3760,8 +3787,11 @@
                 Class clazz = Util.loadClassUsingClass(svcObj.getClass(), classNames[i], m_secureAction);
                 if (clazz == null)
                 {
-                    throw new IllegalArgumentException(
-                        "Cannot cast service: " + classNames[i]);
+                    if (!Util.checkImplementsWithName(svcObj.getClass(), classNames[i]))
+                    {
+                        throw new IllegalArgumentException(
+                                "Cannot cast service: " + classNames[i]);
+                    }
                 }
                 else if (!clazz.isAssignableFrom(svcObj.getClass()))
                 {
@@ -5025,9 +5055,12 @@
             try
             {
                 File file = m_cache.getSystemBundleDataFile("bundle.id");
-                is = m_secureAction.getFileInputStream(file);
-                br = new BufferedReader(new InputStreamReader(is));
-                return Long.parseLong(br.readLine());
+                if (m_secureAction.isFile(file))
+                {
+                    is = m_secureAction.getInputStream(file);
+                    br = new BufferedReader(new InputStreamReader(is));
+                    return Long.parseLong(br.readLine());
+                }
             }
             catch (FileNotFoundException ex)
             {
@@ -5078,7 +5111,7 @@
             try
             {
                 File file = m_cache.getSystemBundleDataFile("bundle.id");
-                os = m_secureAction.getFileOutputStream(file);
+                os = m_secureAction.getOutputStream(file);
                 bw = new BufferedWriter(new OutputStreamWriter(os));
                 String s = Long.toString(m_nextId);
                 bw.write(s, 0, s.length());
@@ -5110,18 +5143,28 @@
         }
     }
 
+    public boolean hasConnectFramework()
+    {
+        return m_connectFramework != null;
+    }
+
     //
     // Miscellaneous inner classes.
     //
 
     class SystemBundleActivator implements BundleActivator
     {
+        private volatile ServiceRegistration<org.osgi.service.condition.Condition> m_reg;
         @Override
         public void start(BundleContext context) throws Exception
         {
             // Add the bundle activator for the url handler service.
             m_activatorList.add(0, new URLHandlersActivator(m_configMap, Felix.this));
 
+
+            m_reg = context.registerService(org.osgi.service.condition.Condition.class, org.osgi.service.condition.Condition.INSTANCE,
+                FrameworkUtil.asDictionary(Collections.singletonMap(org.osgi.service.condition.Condition.CONDITION_ID, org.osgi.service.condition.Condition.CONDITION_ID_TRUE)));
+
             // Start all activators.
             for (Iterator<BundleActivator> iter = m_activatorList.iterator(); iter.hasNext(); )
             {
@@ -5132,6 +5175,7 @@
                 }
                 catch (Throwable throwable)
                 {
+                    throwable.printStackTrace();
                     iter.remove();
                     fireFrameworkEvent(FrameworkEvent.ERROR, context.getBundle(),
                             new BundleException("Unable to start Bundle", throwable));
@@ -5141,6 +5185,7 @@
                         throwable);
                 }
             }
+
         }
 
         @Override
@@ -5163,6 +5208,8 @@
             // Stop framework start level thread.
             m_fwkStartLevel.stop();
 
+            m_resolver.stop();
+
             // Shutdown event dispatching queue.
             m_dispatcher.stopDispatching();
 
@@ -5234,6 +5281,8 @@
                         throwable);
                 }
             }
+            m_reg.unregister();
+            m_activatorList.clear();
             if (m_securityManager != null)
             {
                 System.setSecurityManager(null);
diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkFactory.java b/framework/src/main/java/org/apache/felix/framework/FrameworkFactory.java
index ce377ad..938845f 100644
--- a/framework/src/main/java/org/apache/felix/framework/FrameworkFactory.java
+++ b/framework/src/main/java/org/apache/felix/framework/FrameworkFactory.java
@@ -19,12 +19,20 @@
 package org.apache.felix.framework;
 
 import java.util.Map;
+
+import org.osgi.framework.connect.ModuleConnector;
 import org.osgi.framework.launch.Framework;
 
-public class FrameworkFactory implements org.osgi.framework.launch.FrameworkFactory
+public class FrameworkFactory implements org.osgi.framework.launch.FrameworkFactory, org.osgi.framework.connect.ConnectFrameworkFactory
 {
     public Framework newFramework(Map configuration)
     {
         return new Felix(configuration);
     }
+
+    @Override
+    public Framework newFramework(Map<String, String> configuration, ModuleConnector connectFramework)
+    {
+        return new Felix(configuration, connectFramework);
+    }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java
index 7bc42ce..f051ac0 100644
--- a/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/FrameworkWiringImpl.java
@@ -63,9 +63,6 @@
      * thread explicitly is required in the embedded case, where Felix may be
      * stopped without the Java VM being stopped. In this case the
      * FelixFrameworkWiring thread must be stopped explicitly.
-     * <p>
-     * This method is called by the
-     * {@link PackageAdminActivator#stop(BundleContext)} method.
      */
     void stop()
     {
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
index 9169900..614797a 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
@@ -42,6 +42,7 @@
 import org.osgi.framework.ServiceFactory;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.dto.ServiceReferenceDTO;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.framework.wiring.BundleWire;
@@ -363,9 +364,12 @@
                 {
                     if (clazz == null)
                     {
-                        throw new ServiceException(
-                            "Service cannot be cast due to missing class: " + m_classes[i],
-                            ServiceException.FACTORY_ERROR);
+                        if (!Util.checkImplementsWithName(svcObj.getClass(), m_classes[i]))
+                        {
+                            throw new ServiceException(
+                                    "Service cannot be cast due to missing class: " + m_classes[i],
+                                    ServiceException.FACTORY_ERROR);
+                        }
                     }
                     else
                     {
@@ -696,9 +700,20 @@
         }
 
         @Override
-        public Dictionary<String, Object> getProperties() {
+        public Dictionary<String, Object> getProperties()
+        {
             return new Hashtable<String, Object>(ServiceRegistrationImpl.this.m_propMap);
         }
+
+        @Override
+        public Object adapt(Class type)
+        {
+            if (type == ServiceReferenceDTO.class)
+            {
+                return DTOFactory.createDTO(this);
+            }
+            return null;
+        }
     }
 
     private class ServiceReferenceMap implements Map
diff --git a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
index 2d71eae..cca8544 100644
--- a/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
+++ b/framework/src/main/java/org/apache/felix/framework/StatefulResolver.java
@@ -31,7 +31,6 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -45,7 +44,6 @@
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.ShrinkableCollection;
 import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.NativeLibrary;
 import org.apache.felix.framework.wiring.BundleRequirementImpl;
 import org.apache.felix.framework.wiring.BundleWireImpl;
 import org.apache.felix.resolver.ResolverImpl;
@@ -57,6 +55,7 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.PackagePermission;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.hooks.resolver.ResolverHook;
 import org.osgi.framework.hooks.resolver.ResolverHookFactory;
 import org.osgi.framework.wiring.BundleCapability;
@@ -91,6 +90,7 @@
     private final Map<String, List<BundleRevision>> m_singletons;
     // Selected singleton bundle revisions.
     private final Set<BundleRevision> m_selectedSingletons;
+    private volatile ServiceRegistration<?> m_serviceRegistration;
 
     StatefulResolver(Felix felix, ServiceRegistry registry)
     {
@@ -168,12 +168,22 @@
 
     void start()
     {
-        m_registry.registerService(m_felix,
-                new String[] { Resolver.class.getName() },
+        m_serviceRegistration = m_registry.registerService(m_felix,
+                new String[]{Resolver.class.getName()},
                 new ResolverImpl(m_logger, 1),
                 null);
     }
 
+    void stop()
+    {
+        ServiceRegistration reg = m_serviceRegistration;
+        if (reg != null)
+        {
+            reg.unregister();
+            m_serviceRegistration = null;
+        }
+    }
+
     synchronized void addRevision(BundleRevision br)
     {
         // Always attempt to remove the revision, since
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
index 79b13ce..88b65e9 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
@@ -117,23 +117,34 @@
             ? DEFAULT_STREAM_HANDLER_PACKAGE
             : pkgs + "|" + DEFAULT_STREAM_HANDLER_PACKAGE;
         m_loaded = (null != URLHandlersStreamHandlerProxy.class) &&
-            (null != URLHandlersContentHandlerProxy.class) && (null != URLStreamHandlerService.class);
+            (null != URLHandlersContentHandlerProxy.class) && (null != URLStreamHandlerService.class) && new URLHandlersStreamHandlerProxy(null, null) != null;
     }
 
     private void init(String protocol, URLStreamHandlerFactory factory)
     {
         try
         {
-            URLStreamHandler handler = getBuiltInStreamHandler(protocol, factory);
-            if (handler != null)
-            {
-                URL url = new URL(protocol, null, -1, "", handler);
-                addToCache(m_protocolToURL, protocol, url);
-            }
+            // Try to get it directly from the URL class to if possible
+            Method getURLStreamHandler = m_secureAction.getDeclaredMethod(URL.class,"getURLStreamHandler", new Class[]{String.class});
+            URLStreamHandler handler = (URLStreamHandler) m_secureAction.invoke(getURLStreamHandler, null, new Object[]{protocol});
+            addToCache(m_builtIn, protocol, handler);
         }
         catch (Throwable ex)
         {
-            // Ignore, this is a best effort (maybe log it or something).
+            // Ignore, this is a best effort
+            try
+            {
+                URLStreamHandler handler = getBuiltInStreamHandler(protocol, factory);
+                if (handler != null)
+                {
+                    URL url = new URL(protocol, null, -1, "", handler);
+                    addToCache(m_protocolToURL, protocol, url);
+                }
+            }
+            catch (Throwable ex2)
+            {
+                // Ignore, this is a best effort (maybe log it or something).
+            }
         }
     }
 
@@ -165,14 +176,7 @@
             init("ftp", currentFactory);
             init("http", currentFactory);
             init("https", currentFactory);
-            try
-            {
-                getBuiltInStreamHandler("jar", currentFactory);
-            }
-            catch (Throwable ex)
-            {
-                // Ignore, this is a best effort (maybe log it or something)
-            }
+
 
             // Try to preload the jrt handler as we need it from the jvm on java > 8
             if (getFromCache(m_builtIn, "jrt") == null)
@@ -198,6 +202,30 @@
                 }
             }
 
+            // Try to preload the jrt handler as we need it from the jvm on java > 8
+            if (getFromCache(m_builtIn, "jar") == null)
+            {
+                try
+                {
+                    // Try to get it directly from the URL class to if possible
+                    Method getURLStreamHandler = m_secureAction.getDeclaredMethod(URL.class,"getURLStreamHandler", new Class[]{String.class});
+                    URLStreamHandler handler = (URLStreamHandler) m_secureAction.invoke(getURLStreamHandler, null, new Object[]{"jar"});
+                    addToCache(m_builtIn, "jar", handler);
+                }
+                catch (Throwable ex)
+                {
+                    // Ignore, this is a best effort
+                    try
+                    {
+                        getBuiltInStreamHandler("jar", currentFactory);
+                    }
+                    catch (Throwable ex2)
+                    {
+                        // Ignore, this is a best effort (maybe log it or something)
+                    }
+                }
+            }
+
             if (currentFactory != null)
             {
                 try
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
index 794af28..bbde321 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
@@ -35,7 +35,7 @@
     private Felix m_framework;
     private BundleRevision m_targetRevision;
     private int m_classPathIdx = -1;
-    private int m_contentLength;
+    private long m_contentLength;
     private long m_contentTime;
     private String m_contentType;
     private InputStream m_is;
@@ -87,7 +87,6 @@
         {
             throw new IOException("No bundle associated with resource: " + url);
         }
-        m_contentTime = bundle.getLastModified();
 
         // Get the bundle's revisions to find the target revision.
         BundleRevisions revisions = bundle.adapt(BundleRevisions.class);
@@ -149,6 +148,7 @@
             m_is = ((BundleRevisionImpl)
                 m_targetRevision).getInputStream(m_classPathIdx, m_path);
             m_contentLength = (m_is == null) ? 0 : m_is.available();
+            m_contentTime = ((BundleRevisionImpl) m_targetRevision).getContentTime(m_classPathIdx, m_path);
             m_contentType = URLConnection.guessContentTypeFromName(m_path);
             connected = true;
         }
@@ -164,6 +164,11 @@
 
     public int getContentLength()
     {
+        return (int) getContentLengthLong();
+    }
+
+    public long getContentLengthLong()
+    {
         try
         {
             connect();
@@ -176,11 +181,6 @@
         return m_contentLength;
     }
 
-    public long getContentLengthLong()
-    {
-        return getContentLength();
-    }
-
     public long getLastModified()
     {
         try
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java b/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
index ef577c6..7ad09da 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
@@ -22,7 +22,6 @@
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
 import java.net.InetAddress;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -138,7 +137,7 @@
         m_builtInURL = builtInURL;
     }
 
-    private URLHandlersStreamHandlerProxy(Object service, SecureAction action)
+    URLHandlersStreamHandlerProxy(Object service, SecureAction action)
     {
         m_protocol = null;
         m_service = service;
diff --git a/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java b/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
index 9459f2f..4e3a8c7 100644
--- a/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/WovenClassImpl.java
@@ -30,7 +30,6 @@
 import org.osgi.framework.AdminPermission;
 import org.osgi.framework.PackagePermission;
 import org.osgi.framework.hooks.weaving.WovenClass;
-import org.osgi.framework.wiring.BundleRequirement;
 import org.osgi.framework.wiring.BundleWiring;
 
 class WovenClassImpl implements WovenClass, List<String>
@@ -52,12 +51,10 @@
         m_state = TRANSFORMING;
     }
 
-    synchronized void complete(Class definedClass, byte[] bytes,
-            List<String> imports)
+    synchronized void complete()
     {
-        completeDefine(definedClass);
-        m_bytes = (bytes == null) ? m_bytes : bytes;
-        completeImports(imports);
+        completeDefine(null);
+        completeImports(null);
     }
 
     synchronized void completeImports(List<String> imports)
@@ -66,7 +63,7 @@
                 : Util.newImmutableList(imports);
     }
 
-    synchronized void completeDefine(Class definedClass)
+    synchronized void completeDefine(Class<?> definedClass)
     {
         m_definedClass = definedClass;
     }
@@ -191,14 +188,12 @@
         {
             try
             {
-                List<BundleRequirement> reqs = ManifestParser
+                ManifestParser
                         .parseDynamicImportHeader(null, null, s);
             } catch (Exception ex)
             {
-                RuntimeException re = new IllegalArgumentException(
-                        "Unable to parse dynamic import.");
-                re.initCause(ex);
-                throw re;
+                throw new IllegalArgumentException(
+                        "Unable to parse dynamic import.", ex);
             }
             checkImport(s);
             return m_imports.add(s);
@@ -244,14 +239,12 @@
         {
             try
             {
-                List<BundleRequirement> reqs = ManifestParser
+                ManifestParser
                         .parseDynamicImportHeader(null, null, s);
             } catch (Exception ex)
             {
-                RuntimeException re = new IllegalArgumentException(
-                        "Unable to parse dynamic import.");
-                re.initCause(ex);
-                throw re;
+                throw new IllegalArgumentException(
+                        "Unable to parse dynamic import.", ex);
             }
             checkImport(s);
         }
@@ -271,14 +264,12 @@
         {
             try
             {
-                List<BundleRequirement> reqs = ManifestParser
+                ManifestParser
                         .parseDynamicImportHeader(null, null, s);
             } catch (Exception ex)
             {
-                RuntimeException re = new IllegalArgumentException(
-                        "Unable to parse dynamic import.");
-                re.initCause(ex);
-                throw re;
+                throw new IllegalArgumentException(
+                        "Unable to parse dynamic import.", ex);
             }
             checkImport(s);
         }
@@ -333,14 +324,12 @@
         }
         try
         {
-            List<BundleRequirement> reqs = ManifestParser
+            ManifestParser
                     .parseDynamicImportHeader(null, null, s);
         } catch (Exception ex)
         {
-            RuntimeException re = new IllegalArgumentException(
-                    "Unable to parse dynamic import.");
-            re.initCause(ex);
-            throw re;
+            throw new IllegalArgumentException(
+                    "Unable to parse dynamic import.", ex);
         }
         checkImport(s);
         return m_imports.set(i, s);
@@ -356,14 +345,13 @@
         }
         try
         {
-            List<BundleRequirement> reqs = ManifestParser
+            ManifestParser
                     .parseDynamicImportHeader(null, null, s);
-        } catch (Exception ex)
+        }
+        catch (Exception ex)
         {
-            RuntimeException re = new IllegalArgumentException(
-                    "Unable to parse dynamic import.");
-            re.initCause(ex);
-            throw re;
+            throw new IllegalArgumentException(
+                    "Unable to parse dynamic import.", ex);
         }
         checkImport(s);
         m_imports.add(i, s);
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
index fc527bc..50e4d31 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
@@ -27,6 +27,8 @@
 import org.apache.felix.framework.util.WeakZipFileFactory;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
+import org.osgi.framework.connect.ModuleConnector;
+import org.osgi.framework.connect.ConnectModule;
 
 /**
  * <p>
@@ -100,6 +102,8 @@
     **/
     private long m_refreshCount = -1;
 
+    private final ModuleConnector m_connector;
+
     // Maps a Long revision number to a BundleRevision.
     private final SortedMap<Long, BundleArchiveRevision> m_revisions
         = new TreeMap<Long, BundleArchiveRevision>();
@@ -121,7 +125,8 @@
      * @param is input stream from which to read the bundle content.
      * @throws Exception if any error occurs.
     **/
-    public BundleArchive(Logger logger, Map configMap, WeakZipFileFactory zipFactory,
+    public BundleArchive(Logger logger, Map configMap, WeakZipFileFactory zipFactory, ModuleConnector
+        connectFactory,
         File archiveRootDir, long id, int startLevel, String location, InputStream is)
         throws Exception
     {
@@ -141,6 +146,8 @@
         m_lastModified = System.currentTimeMillis();
         m_refreshCount = 0;
 
+        m_connector = connectFactory;
+
         // Save state.
         initialize();
 
@@ -160,7 +167,7 @@
      * @param configMap configMap for BundleArchive
      * @throws Exception if any error occurs.
     **/
-    public BundleArchive(Logger logger, Map configMap, WeakZipFileFactory zipFactory,
+    public BundleArchive(Logger logger, Map configMap, WeakZipFileFactory zipFactory, ModuleConnector connectFactory,
         File archiveRootDir)
         throws Exception
     {
@@ -184,7 +191,7 @@
         for (File child : children)
         {
             if (child.getName().startsWith(REVISION_DIRECTORY)
-                && child.isDirectory())
+                && BundleCache.getSecureAction().isFileDirectory(child))
             {
                 // Determine the revision number and add it to the revision map.
                 int idx = child.getName().lastIndexOf('.');
@@ -211,8 +218,12 @@
         Long currentRevNum = m_revisions.lastKey();
         m_revisions.remove(currentRevNum);
 
+        String location = getRevisionLocation(currentRevNum);
+
+        m_connector = connectFactory;
+
         // Add the revision object for the most recent revision.
-        reviseInternal(true, currentRevNum, getRevisionLocation(currentRevNum), null);
+        reviseInternal(true, currentRevNum, location, null);
     }
 
     /**
@@ -542,7 +553,7 @@
         BufferedReader br = null;
         try
         {
-            is = BundleCache.getSecureAction().getFileInputStream(new File(
+            is = BundleCache.getSecureAction().getInputStream(new File(
                 new File(m_archiveRootDir, REVISION_DIRECTORY +
                 getRefreshCount() + "." + revNum.toString()), REVISION_LOCATION_FILE));
 
@@ -565,7 +576,7 @@
         try
         {
             os = BundleCache.getSecureAction()
-                .getFileOutputStream(new File(
+                .getOutputStream(new File(
                     new File(m_archiveRootDir, REVISION_DIRECTORY +
                     getRefreshCount() + "." + revNum.toString()), REVISION_LOCATION_FILE));
             bw = new BufferedWriter(new OutputStreamWriter(os));
@@ -795,9 +806,19 @@
             }
             else
             {
-                // Anything else is assumed to be a URL to a JAR file.
-                result = new JarRevision(m_logger, m_configMap,
-                    m_zipFactory, revisionRootDir, location, false, null);
+                ConnectModule module = m_connector != null ?
+                    m_connector.connect(location).orElse(null) : null;
+
+                if (module != null)
+                {
+                    result = new ConnectRevision(m_logger, m_configMap, m_zipFactory, revisionRootDir, location, module);
+                }
+                else
+                {
+                    // Anything else is assumed to be a URL to a JAR file.
+                    result = new JarRevision(m_logger, m_configMap,
+                        m_zipFactory, revisionRootDir, location, false, null);
+                }
             }
         }
         catch (Exception ex)
@@ -869,7 +890,7 @@
         try
         {
             is = BundleCache.getSecureAction()
-                .getFileInputStream(infoFile);
+                .getInputStream(infoFile);
             br = new BufferedReader(new InputStreamReader(is));
 
             // Read id.
@@ -900,7 +921,7 @@
         try
         {
             os = BundleCache.getSecureAction()
-                .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_INFO_FILE));
+                .getOutputStream(new File(m_archiveRootDir, BUNDLE_INFO_FILE));
             bw = new BufferedWriter(new OutputStreamWriter(os));
 
             // Write id.
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
index 8e63af9..ef544d0 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
@@ -22,9 +22,9 @@
 import org.apache.felix.framework.util.SecureAction;
 import org.apache.felix.framework.util.WeakZipFileFactory;
 import org.osgi.framework.Constants;
+import org.osgi.framework.connect.ModuleConnector;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -144,25 +144,14 @@
         {
             File lockFile = new File(cacheDir, CACHE_LOCK_NAME);
             FileChannel fc = null;
-            FileOutputStream fos = null;
             try
             {
-                if (!getSecureAction().fileExists(lockFile))
-                {
-                    fos = getSecureAction().getFileOutputStream(lockFile);
-                    fc = fos.getChannel();
-                }
-                else
-                {
-                    fos = getSecureAction().getFileOutputStream(lockFile);
-                    fc = fos.getChannel();
-                }
+                fc = getSecureAction().getFileChannel(lockFile);
             }
             catch (Exception ex)
             {
                 try
                 {
-                    if (fos != null) fos.close();
                     if (fc != null) fc.close();
                 }
                 catch (Exception ex2)
@@ -386,6 +375,11 @@
         }
     }
 
+    public File getCacheDir()
+    {
+        return determineCacheDir(m_configMap);
+    }
+
     /* package */ static SecureAction getSecureAction()
     {
         return m_secureAction;
@@ -398,7 +392,7 @@
         deleteDirectoryTree(cacheDir);
     }
 
-    public BundleArchive[] getArchives()
+    public BundleArchive[] getArchives(ModuleConnector connectFactory)
         throws Exception
     {
         // Get buffer size value.
@@ -431,7 +425,7 @@
                 {
                     archiveList.add(
                         new BundleArchive(
-                            m_logger, m_configMap, m_zipFactory, children[i]));
+                            m_logger, m_configMap, m_zipFactory, connectFactory, children[i]));
                 }
                 catch (Exception ex)
                 {
@@ -447,7 +441,7 @@
             archiveList.toArray(new BundleArchive[archiveList.size()]);
     }
 
-    public BundleArchive create(long id, int startLevel, String location, InputStream is)
+    public BundleArchive create(long id, int startLevel, String location, InputStream is, ModuleConnector connectFactory)
         throws Exception
     {
         File cacheDir = determineCacheDir(m_configMap);
@@ -461,7 +455,7 @@
             // Create the archive and add it to the list of archives.
             BundleArchive ba =
                 new BundleArchive(
-                    m_logger, m_configMap, m_zipFactory, archiveRootDir,
+                    m_logger, m_configMap, m_zipFactory, connectFactory, archiveRootDir,
                     id, startLevel, location, is);
             return ba;
         }
@@ -548,7 +542,7 @@
 
         try
         {
-            os = getSecureAction().getFileOutputStream(outputFile);
+            os = getSecureAction().getOutputStream(outputFile);
             for (int i = is.read(bytes);i != -1; i = is.read(bytes))
             {
                 os.write(bytes, 0, i);
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/ConnectContentContent.java b/framework/src/main/java/org/apache/felix/framework/cache/ConnectContentContent.java
new file mode 100644
index 0000000..a37c598
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/cache/ConnectContentContent.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.felix.framework.cache;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.WeakZipFileFactory;
+import org.osgi.framework.connect.ConnectContent;
+
+public class ConnectContentContent implements Content
+{
+    private static final transient String EMBEDDED_DIRECTORY = "-embedded";
+    private static final transient String LIBRARY_DIRECTORY = "-lib";
+
+    private final Logger m_logger;
+    private final WeakZipFileFactory m_zipFactory;
+    private final Map m_configMap;
+    private final String m_name;
+    private final File m_rootDir;
+    private final Object m_revisionLock;
+    private final ConnectContent m_content;
+
+    public ConnectContentContent(Logger logger, WeakZipFileFactory zipFactory, Map configMap, String name, File rootDir, Object revisionLock, ConnectContent content) throws IOException
+    {
+        m_logger = logger;
+        m_zipFactory = zipFactory;
+        m_configMap = configMap;
+        m_name = name;
+        m_rootDir = rootDir;
+        m_revisionLock = revisionLock;
+        m_content = content;
+    }
+
+    @Override
+    public void close()
+    {
+        // TODO: Connect
+    }
+
+    @Override
+    public boolean hasEntry(String name)
+    {
+        return m_content.getEntry(name).isPresent();
+    }
+
+    @Override
+    public boolean isDirectory(String name)
+    {
+        return m_content.getEntry(name).map(entry -> entry.getName().endsWith("/")).orElse(false);
+    }
+
+    @Override
+    public Enumeration<String> getEntries()
+    {
+        try
+        {
+            Iterator<String> entries = m_content.getEntries().iterator();
+            return new Enumeration<String>()
+            {
+                @Override
+                public boolean hasMoreElements()
+                {
+                    return entries.hasNext();
+                }
+
+                @Override
+                public String nextElement()
+                {
+                    return entries.next();
+                }
+            };
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public byte[] getEntryAsBytes(String name)
+    {
+        return m_content.getEntry(name).flatMap(entry ->
+        {
+            try
+            {
+                return Optional.of(entry.getBytes());
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+                return null;
+            }
+        }).orElse(null);
+    }
+
+    @Override
+    public InputStream getEntryAsStream(String name) throws IOException
+    {
+        return m_content.getEntry(name).flatMap(entry ->
+        {
+            try
+            {
+                return Optional.of(entry.getInputStream());
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+                return null;
+            }
+        }).orElse(null);
+    }
+
+    public ClassLoader getClassLoader() {
+        return m_content.getClassLoader().orElse(null);
+    }
+
+    @Override
+    public Content getEntryAsContent(String name)
+    {
+        if (".".equals(name) || "".equals(name))
+        {
+            return this;
+        }
+        String dir = name.endsWith("/") ? name : name + "/";
+
+        if (hasEntry(dir))
+        {
+            return new ContentDirectoryContent(this, name);
+        }
+
+        if (hasEntry(name) && name.endsWith(".jar"))
+        {
+            // Any embedded JAR files will be extracted to the embedded directory.
+            // Since embedded JAR file names may clash when extracting from multiple
+            // embedded JAR files, the embedded directory is per embedded JAR file.
+            File embedDir = new File(m_rootDir, m_name + EMBEDDED_DIRECTORY);
+
+            File extractJar = new File(embedDir, name);
+
+            try
+            {
+                if (!BundleCache.getSecureAction().fileExists(extractJar))
+                {
+                    // Extracting the embedded JAR file impacts all other existing
+                    // contents for this revision, so we have to grab the revision
+                    // lock first before trying to extract the embedded JAR file
+                    // to avoid a race condition.
+                    synchronized (m_revisionLock)
+                    {
+                        if (!BundleCache.getSecureAction().fileExists(extractJar))
+                        {
+                            // Make sure that the embedded JAR's parent directory exists;
+                            // it may be in a sub-directory.
+                            File jarDir = extractJar.getParentFile();
+                            if (!BundleCache.getSecureAction().fileExists(jarDir) && !BundleCache.getSecureAction().mkdirs(jarDir))
+                            {
+                                throw new IOException("Unable to create embedded JAR directory.");
+                            }
+
+                            // Extract embedded JAR into its directory.
+                            BundleCache.copyStreamToFile(m_content.getEntry(name).get().getInputStream(), extractJar);
+                        }
+                    }
+                }
+                return new JarContent(
+                    m_logger, m_configMap, m_zipFactory, m_revisionLock,
+                    extractJar.getParentFile(), extractJar, null);
+            }
+            catch (Exception ex)
+            {
+                m_logger.log(
+                    Logger.LOG_ERROR,
+                    "Unable to extract embedded JAR file.", ex);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public String getEntryAsNativeLibrary(String entryName)
+    {
+        // TODO: Connect
+        return null;
+    }
+
+    @Override
+    public URL getEntryAsURL(String name)
+    {
+        // TODO: Connect
+        return null;
+    }
+
+    @Override
+    public long getContentTime(String urlPath)
+    {
+        return m_content.getEntry(urlPath).flatMap(entry -> Optional.of(entry.getLastModified())).orElse(-1L);
+    }
+}
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/ConnectRevision.java b/framework/src/main/java/org/apache/felix/framework/cache/ConnectRevision.java
new file mode 100644
index 0000000..94b3284
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/cache/ConnectRevision.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.felix.framework.cache;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.StringMap;
+import org.apache.felix.framework.util.WeakZipFileFactory;
+import org.osgi.framework.connect.ConnectContent;
+import org.osgi.framework.connect.ConnectModule;
+
+public class ConnectRevision extends BundleArchiveRevision
+{
+    private final WeakZipFileFactory m_zipFactory;
+    private final ConnectContent m_module;
+
+    public ConnectRevision(Logger logger, Map configMap, WeakZipFileFactory zipFactory,
+        File revisionRootDir, String location, ConnectModule module) throws Exception
+    {
+        super(logger, configMap, revisionRootDir, location);
+        m_zipFactory = zipFactory;
+        m_module = module.getContent();
+        m_module.open();
+        // If the revision directory exists, then we don't
+        // need to initialize since it has already been done.
+        if (BundleCache.getSecureAction().fileExists(getRevisionRootDir()))
+        {
+            return;
+        }
+        // Create revision directory, we only need this to store the
+        // revision location, since nothing else needs to be extracted
+        // since we are referencing a read directory already.
+        if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir()))
+        {
+            getLogger().log(
+                Logger.LOG_ERROR,
+                getClass().getName() + ": Unable to create revision directory.");
+            throw new IOException("Unable to create archive directory.");
+        }
+    }
+
+    @Override
+    public Map<String, Object> getManifestHeader() throws Exception
+    {
+        return (Map) m_module.getHeaders().orElseGet(() -> m_module.getEntry("META-INF/MANIFEST.MF").flatMap(entry -> {
+                try
+                {
+                    byte[] manifest = entry.getBytes();
+
+                    return Optional.of((Map<String, String>) (Map) BundleCache.getMainAttributes(new StringMap(), new java.io.ByteArrayInputStream(manifest), manifest.length));
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalStateException(e);
+                }
+            }).orElse(null));
+    }
+
+    @Override
+    public Content getContent() throws Exception
+    {
+        return new ConnectContentContent(getLogger(), m_zipFactory, getConfig(), "connect", getRevisionRootDir(), this, m_module);
+    }
+
+    @Override
+    protected void close() throws Exception
+    {
+        m_module.close();
+    }
+}
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/Content.java b/framework/src/main/java/org/apache/felix/framework/cache/Content.java
index 09ace44..4ec2ecd 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/Content.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/Content.java
@@ -49,6 +49,18 @@
 
     /**
      * <p>
+     * This method determines if the specified named entry is contained in
+     * the associated content and is a directory. The entry name is a relative path with '/'
+     * separators.
+     * </p>
+     * @param name The name of the entry to find.
+     * @return <tt>true</tt> if a corresponding entry was found and is a directory, <tt>false</tt>
+     *         otherwise.
+     **/
+    boolean isDirectory(String name);
+
+    /**
+     * <p>
      * Returns an enumeration of entry names as <tt>String</tt> objects.
      * An entry name is a path constructed with '/' as path element
      * separators and is relative to the root of the content. Entry names
@@ -121,4 +133,6 @@
      *           or null if not possible.
      */
     URL getEntryAsURL(String name);
+
+    long getContentTime(String urlPath);
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java b/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java
index d268f32..1673270 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/ContentDirectoryContent.java
@@ -47,14 +47,19 @@
 
     public boolean hasEntry(String name) throws IllegalStateException
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         return m_content.hasEntry(m_rootPath + name);
     }
 
+    @Override
+    public boolean isDirectory(String name)
+    {
+        name = getName(name);
+
+        return m_content.isDirectory(m_rootPath + name);
+    }
+
     public Enumeration<String> getEntries()
     {
         Enumeration<String> result = new EntriesEnumeration(m_content.getEntries(), m_rootPath);
@@ -63,10 +68,7 @@
 
     public byte[] getEntryAsBytes(String name) throws IllegalStateException
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         return m_content.getEntryAsBytes(m_rootPath + name);
     }
@@ -74,35 +76,42 @@
     public InputStream getEntryAsStream(String name)
         throws IllegalStateException, IOException
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         return m_content.getEntryAsStream(m_rootPath + name);
     }
 
+    private String getName(String name)
+    {
+        if ((name.length() > 0) && (name.charAt(0) == '/')) {
+            name = name.substring(1);
+        }
+        return name;
+    }
+
     public URL getEntryAsURL(String name)
     {
         return m_content.getEntryAsURL(m_rootPath + name);
     }
 
+    @Override
+    public long getContentTime(String name)
+    {
+        name = getName(name);
+
+        return m_content.getContentTime(m_rootPath + name);
+    }
+
     public Content getEntryAsContent(String name)
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         return m_content.getEntryAsContent(m_rootPath + name);
     }
 
     public String getEntryAsNativeLibrary(String name)
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         return m_content.getEntryAsNativeLibrary(m_rootPath + name);
     }
@@ -143,14 +152,17 @@
 
         private String findNextEntry()
         {
-            // Find next entry that is inside the root directory.
-            while (m_enumeration.hasMoreElements())
+            if (m_enumeration != null)
             {
-                String next = (String) m_enumeration.nextElement();
-                if (next.startsWith(m_rootPath) && !next.equals(m_rootPath))
+                // Find next entry that is inside the root directory.
+                while (m_enumeration.hasMoreElements())
                 {
-                    // Strip off the root directory.
-                    return next.substring(m_rootPath.length());
+                    String next = (String) m_enumeration.nextElement();
+                    if (next.startsWith(m_rootPath) && !next.equals(m_rootPath))
+                    {
+                        // Strip off the root directory.
+                        return next.substring(m_rootPath.length());
+                    }
                 }
             }
             return null;
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
index 50da934..c462b55 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
@@ -72,10 +72,7 @@
 
     public boolean hasEntry(String name) throws IllegalStateException
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         // Return true if the file associated with the entry exists,
         // unless the entry name ends with "/", in which case only
@@ -86,6 +83,18 @@
                 ? BundleCache.getSecureAction().isFileDirectory(file) : true);
     }
 
+    @Override
+    public boolean isDirectory(String name)
+    {
+        name = getName(name);
+
+        // Return true if the file associated with the entry exists,
+        // unless the entry name ends with "/", in which case only
+        // return true if the file is really a directory.
+        File file = new File(m_dir, name);
+        return BundleCache.getSecureAction().isFileDirectory(file);
+    }
+
     public Enumeration<String> getEntries()
     {
         // Wrap entries enumeration to filter non-matching entries.
@@ -97,10 +106,7 @@
 
     public byte[] getEntryAsBytes(String name) throws IllegalStateException
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         // Get the embedded resource.
 
@@ -108,7 +114,7 @@
         try
         {
 
-            return BundleCache.getSecureAction().fileExists(file) ? BundleCache.read(BundleCache.getSecureAction().getFileInputStream(file), file.length()) : null;
+            return BundleCache.getSecureAction().fileExists(file) ? BundleCache.read(BundleCache.getSecureAction().getInputStream(file), file.length()) : null;
         }
         catch (Exception ex)
         {
@@ -122,15 +128,12 @@
     public InputStream getEntryAsStream(String name)
         throws IllegalStateException, IOException
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
-            name = name.substring(1);
-        }
+        name = getName(name);
 
         File file = new File(m_dir, name);
         try
         {
-            return BundleCache.getSecureAction().fileExists(file) ? BundleCache.getSecureAction().getFileInputStream(file) : null;
+            return BundleCache.getSecureAction().fileExists(file) ? BundleCache.getSecureAction().getInputStream(file) : null;
         }
         catch (Exception ex)
         {
@@ -141,12 +144,17 @@
         }
     }
 
-    public URL getEntryAsURL(String name)
+    private String getName(String name)
     {
-        if ((name.length() > 0) && (name.charAt(0) == '/'))
-        {
+        if ((name.length() > 0) && (name.charAt(0) == '/')) {
             name = name.substring(1);
         }
+        return name;
+    }
+
+    public URL getEntryAsURL(String name)
+    {
+        name = getName(name);
 
         if (hasEntry(name))
         {
@@ -165,6 +173,16 @@
         }
     }
 
+    @Override
+    public long getContentTime(String name)
+    {
+        name = getName(name);
+
+        File file = new File(m_dir, name);
+
+        return BundleCache.getSecureAction().getLastModified(file);
+    }
+
     public Content getEntryAsContent(String entryName)
     {
         // If the entry name refers to the content itself, then
@@ -278,7 +296,7 @@
 
                         try
                         {
-                            is = BundleCache.getSecureAction().getFileInputStream(entryFile);
+                            is = BundleCache.getSecureAction().getInputStream(entryFile);
 
                             // Create the file.
                             BundleCache.copyStreamToFile(is, libFile);
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
index a1cf608..f6d01a9 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
@@ -71,7 +71,7 @@
         throws Exception
     {
         File manifest = new File(m_refDir, "META-INF/MANIFEST.MF");
-        return manifest.isFile() ? BundleCache.getMainAttributes(new StringMap(), BundleCache.getSecureAction().getFileInputStream(manifest), manifest.length()) : null;
+        return BundleCache.getSecureAction().isFile(manifest) ? BundleCache.getMainAttributes(new StringMap(), BundleCache.getSecureAction().getInputStream(manifest), manifest.length()) : null;
     }
 
     public Content getContent() throws Exception
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java b/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
index 35afc9c..fd1dda0 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
@@ -101,7 +101,7 @@
         }
     }
 
-    public boolean hasEntry(String name) throws IllegalStateException
+    public boolean hasEntry(String name)
     {
         try
         {
@@ -112,8 +112,19 @@
         {
             return false;
         }
-        finally
+    }
+
+    @Override
+    public boolean isDirectory(String name)
+    {
+        try
         {
+            ZipEntry ze = m_zipFile.getEntry(name);
+            return ze != null && ze.isDirectory();
+        }
+        catch (Exception ex)
+        {
+            return false;
         }
     }
 
@@ -195,6 +206,20 @@
         }
     }
 
+    @Override
+    public long getContentTime(String urlPath)
+    {
+        try
+        {
+            ZipEntry ze = m_zipFile.getEntry(urlPath);
+            return ze.getTime();
+        }
+        catch (Exception ex)
+        {
+            return -1L;
+        }
+    }
+
     public Content getEntryAsContent(String entryName)
     {
         // If the entry name refers to the content itself, then
@@ -398,7 +423,7 @@
         return m_file;
     }
 
-    private static class DevNullRunnable implements Runnable
+    static class DevNullRunnable implements Runnable
     {
         private final InputStream m_in;
 
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java b/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
index ac5c1e8..4ff4e84 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
@@ -147,7 +147,7 @@
                             // set request properties such as proxy auth.
                             URL url = BundleCache.getSecureAction().createURL(
                                 null, getLocation(), null);
-                            conn = url.openConnection();
+                            conn = BundleCache.getSecureAction().openURLConnection(url);
 
                             // Support for http proxy authentication.
                             String auth = BundleCache.getSecureAction()
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
index 7116751..e887c3a 100644
--- a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
@@ -577,7 +577,7 @@
     {
         // If the LHS expects a string, then we can just return
         // the RHS since it is a string.
-        if (lhs.getClass() == rhsString.getClass())
+        if (lhs instanceof String)
         {
             return rhsString;
         }
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java
index 253c70d..6e56485 100644
--- a/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/SimpleFilter.java
@@ -18,7 +18,6 @@
  */
 package org.apache.felix.framework.capabilityset;
 
-import org.osgi.framework.Version;
 import org.osgi.framework.VersionRange;
 
 import java.util.ArrayList;
diff --git a/framework/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java b/framework/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java
index 26103b4..f83663c 100644
--- a/framework/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java
+++ b/framework/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java
@@ -23,6 +23,8 @@
 import java.net.URL;
 import java.net.URLClassLoader;
 
+import org.apache.felix.framework.util.SecureAction;
+
 public interface ClassPathExtenderFactory
 {
     interface ClassPathExtender
@@ -50,10 +52,10 @@
                 try
                 {
                     append = app.getClass().getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
-                    append.setAccessible(true);
+                    new SecureAction().setAccesssible(append);
                     break;
                 }
-                catch (Exception e)
+                catch (Throwable e)
                 {
                     append = null;
                     try
@@ -74,9 +76,9 @@
             try
             {
                 addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
-                addURL.setAccessible(true);
+                new SecureAction().setAccesssible(addURL);
             }
-            catch (Exception e)
+            catch (Throwable e)
             {
                 addURL = null;
             }
diff --git a/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java b/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java
index 53996dd..fa1b48d 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/MultiReleaseContent.java
@@ -18,23 +18,15 @@
  */
 package org.apache.felix.framework.util;
 
+import org.apache.felix.framework.cache.BundleCache;
 import org.apache.felix.framework.cache.Content;
 import org.osgi.framework.Version;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
+import java.util.*;
 
 public class MultiReleaseContent implements Content
 {
@@ -61,14 +53,16 @@
         }
         if (javaVersion > 8)
         {
-            InputStream manifestStream = null;
-
             try
             {
-                manifestStream = content.getEntryAsStream("META-INF/MANIFEST.MF");
-                if (manifestStream != null)
+                byte[] versionManifestInput = content.getEntryAsBytes("META-INF/MANIFEST.MF");
+
+                if (versionManifestInput != null)
                 {
-                    if ("true".equals(new Manifest(manifestStream).getMainAttributes().getValue("Multi-Release")))
+                    Map<String, Object> versionManifest = BundleCache.getMainAttributes(
+                            new StringMap(), new ByteArrayInputStream(versionManifestInput), versionManifestInput.length);
+
+                    if ("true".equals(versionManifest.get("Multi-Release")))
                     {
                         content = new MultiReleaseContent(javaVersion, content);
                     }
@@ -77,17 +71,6 @@
             catch (Exception ex)
             {
             }
-            finally
-            {
-                if (manifestStream != null)
-                {
-                    try
-                    {
-                        manifestStream.close();
-                    }
-                    catch (Exception ex){}
-                }
-            }
         }
         return content;
     }
@@ -105,6 +88,12 @@
     }
 
     @Override
+    public boolean isDirectory(String name)
+    {
+        return m_content.isDirectory(findPath(name));
+    }
+
+    @Override
     public Enumeration<String> getEntries()
     {
         Enumeration<String> entries = m_content.getEntries();
@@ -175,6 +164,12 @@
         return m_content.getEntryAsURL(findPath(name));
     }
 
+    @Override
+    public long getContentTime(String name)
+    {
+        return m_content.getContentTime(findPath(name));
+    }
+
     private String findPath(String path)
     {
         String internalPath = path;
diff --git a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
index 4a202a7..1e8024e 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
@@ -22,11 +22,15 @@
 import java.lang.reflect.*;
 import java.lang.reflect.Proxy;
 import java.net.*;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.StandardOpenOption;
 import java.security.*;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.function.Consumer;
 import java.util.jar.JarFile;
 import java.util.zip.ZipFile;
 
@@ -56,6 +60,32 @@
 **/
 public class SecureAction
 {
+    private static final byte[] accessor;
+
+    static
+    {
+        byte[] result;
+
+        try (ByteArrayOutputStream output = new ByteArrayOutputStream();
+             InputStream input = SecureAction.class.getResourceAsStream("accessor.bytes"))
+        {
+
+            byte[] buffer = new byte[input.available() > 0 ? input.available() : 1024];
+            for (int i = input.read(buffer); i != -1; i = input.read(buffer))
+            {
+                output.write(buffer, 0, i);
+            }
+            result = output.toByteArray();
+        }
+        catch (Throwable t)
+        {
+            t.printStackTrace();
+            result = new byte[0];
+        }
+        accessor = result;
+        getAccessor(URL.class);
+    }
+
     private static final ThreadLocal m_actions = new ThreadLocal()
     {
         public Object initialValue()
@@ -321,6 +351,28 @@
         }
     }
 
+    public boolean isFile(File file)
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                Actions actions = (Actions) m_actions.get();
+                actions.set(Actions.FILE_IS_FILE_ACTION, file);
+                return ((Boolean) AccessController.doPrivileged(actions, m_acc))
+                        .booleanValue();
+            }
+            catch (PrivilegedActionException ex)
+            {
+                throw (RuntimeException) ex.getException();
+            }
+        }
+        else
+        {
+            return file.isFile();
+        }
+    }
+
     public boolean isFileDirectory(File file)
     {
         if (System.getSecurityManager() != null)
@@ -430,6 +482,56 @@
         }
     }
 
+    public InputStream getInputStream(File file) throws IOException
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                Actions actions = (Actions) m_actions.get();
+                actions.set(Actions.GET_INPUT_ACTION, file);
+                return (InputStream) AccessController.doPrivileged(actions, m_acc);
+            }
+            catch (PrivilegedActionException ex)
+            {
+                if (ex.getException() instanceof IOException)
+                {
+                    throw (IOException) ex.getException();
+                }
+                throw (RuntimeException) ex.getException();
+            }
+        }
+        else
+        {
+            return Files.newInputStream(file.toPath());
+        }
+    }
+
+    public OutputStream getOutputStream(File file) throws IOException
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                Actions actions = (Actions) m_actions.get();
+                actions.set(Actions.GET_OUTPUT_ACTION, file);
+                return (OutputStream) AccessController.doPrivileged(actions, m_acc);
+            }
+            catch (PrivilegedActionException ex)
+            {
+                if (ex.getException() instanceof IOException)
+                {
+                    throw (IOException) ex.getException();
+                }
+                throw (RuntimeException) ex.getException();
+            }
+        }
+        else
+        {
+            return Files.newOutputStream(file.toPath());
+        }
+    }
+
     public FileInputStream getFileInputStream(File file) throws IOException
     {
         if (System.getSecurityManager() != null)
@@ -480,6 +582,31 @@
         }
     }
 
+    public FileChannel getFileChannel(File file) throws IOException
+    {
+        if (System.getSecurityManager() != null)
+        {
+            try
+            {
+                Actions actions = (Actions) m_actions.get();
+                actions.set(Actions.GET_FILE_CHANNEL_ACTION, file);
+                return (FileChannel) AccessController.doPrivileged(actions, m_acc);
+            }
+            catch (PrivilegedActionException ex)
+            {
+                if (ex.getException() instanceof IOException)
+                {
+                    throw (IOException) ex.getException();
+                }
+                throw (RuntimeException) ex.getException();
+            }
+        }
+        else
+        {
+            return FileChannel.open(file.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
+        }
+    }
+
     public URI toURI(File file)
     {
         if (System.getSecurityManager() != null)
@@ -762,7 +889,7 @@
             Method addURL =
                 URLClassLoader.class.getDeclaredMethod("addURL",
                 new Class[] {URL.class});
-            addURL.setAccessible(true);
+            getAccessor(URLClassLoader.class).accept(new AccessibleObject[]{addURL});
             addURL.invoke(loader, new Object[]{extension});
         }
     }
@@ -851,7 +978,7 @@
         }
     }
 
-    public void setAccesssible(AccessibleObject ao)
+    public void setAccesssible(Executable ao)
     {
         if (System.getSecurityManager() != null)
         {
@@ -868,7 +995,7 @@
         }
         else
         {
-            ao.setAccessible(true);
+            getAccessor(ao.getDeclaringClass()).accept(new AccessibleObject[]{ao});
         }
     }
 
@@ -889,7 +1016,8 @@
         }
         else
         {
-            method.setAccessible(true);
+            getAccessor(method.getDeclaringClass()).accept(new AccessibleObject[]{method});
+
             return method.invoke(target, params);
         }
     }
@@ -955,8 +1083,7 @@
         else
         {
             Field field = targetClass.getDeclaredField(name);
-            field.setAccessible(true);
-
+            getAccessor(targetClass).accept(new AccessibleObject[]{field});
             return field.get(target);
         }
     }
@@ -985,9 +1112,51 @@
         }
     }
 
+    private static volatile Consumer<AccessibleObject[]> m_accessorCache = null;
+
+    @SuppressWarnings("unchecked")
+    private static Consumer<AccessibleObject[]> getAccessor(Class clazz)
+    {
+        String packageName = clazz.getPackage().getName();
+        if ("java.net".equals(packageName) || "jdk.internal.loader".equals(packageName))
+        {
+            if (m_accessorCache == null)
+            {
+                try
+                {
+                    // Use reflection on Unsafe to avoid having to compile against it
+                    Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); //$NON-NLS-1$
+                    Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe"); //$NON-NLS-1$
+                    // NOTE: deep reflection is allowed on sun.misc package for java 9.
+                    theUnsafe.setAccessible(true);
+                    Object unsafe = theUnsafe.get(null);
+                    // using defineAnonymousClass here because it seems more simple to get what we need
+                    Method defineAnonymousClass = unsafeClass.getMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class); //$NON-NLS-1$
+                    // The bytes stored in a resource to avoid real loading of it (see accessible.src for source).
+
+                    Class<Consumer<AccessibleObject[]>> result =
+                        (Class<Consumer<AccessibleObject[]>>)
+                            defineAnonymousClass.invoke(unsafe, URL.class, accessor , null);
+                    m_accessorCache = result.getConstructor().newInstance();
+                }
+                catch (Throwable t)
+                {
+                    t.printStackTrace();
+                    m_accessorCache = objects -> AccessibleObject.setAccessible(objects, true);
+                }
+            }
+            return m_accessorCache;
+        }
+        else
+        {
+            return objects -> AccessibleObject.setAccessible(objects, true);
+        }
+    }
+
     private static Object _swapStaticFieldIfNotClass(Class targetClazz,
         Class targetType, Class condition, String lockName) throws Exception
     {
+
         Object lock = null;
         if (lockName != null)
         {
@@ -995,7 +1164,7 @@
             {
                 Field lockField =
                     targetClazz.getDeclaredField(lockName);
-                lockField.setAccessible(true);
+                getAccessor(targetClazz).accept(new AccessibleObject[]{lockField});
                 lock = lockField.get(null);
             }
             catch (NoSuchFieldException ex)
@@ -1010,14 +1179,14 @@
         {
             Field[] fields = targetClazz.getDeclaredFields();
 
+            getAccessor(targetClazz).accept(fields);
+
             Object result = null;
             for (int i = 0; (i < fields.length) && (result == null); i++)
             {
                 if (Modifier.isStatic(fields[i].getModifiers()) &&
                     (fields[i].getType() == targetType))
                 {
-                    fields[i].setAccessible(true);
-
                     result = fields[i].get(null);
 
                     if (result != null)
@@ -1040,7 +1209,6 @@
                         if (Modifier.isStatic(fields[i].getModifiers()) &&
                             (fields[i].getType() == Hashtable.class))
                         {
-                            fields[i].setAccessible(true);
                             Hashtable cache = (Hashtable) fields[i].get(null);
                             if (cache != null)
                             {
@@ -1081,13 +1249,13 @@
         synchronized (lock)
         {
             Field[] fields = targetClazz.getDeclaredFields();
+            getAccessor(targetClazz).accept(fields);
             // reset cache
             for (int i = 0; i < fields.length; i++)
             {
                 if (Modifier.isStatic(fields[i].getModifiers()) &&
                     ((fields[i].getType() == Hashtable.class) || (fields[i].getType() == HashMap.class)))
                 {
-                    fields[i].setAccessible(true);
                     if (fields[i].getType() == Hashtable.class)
                     {
                         Hashtable cache = (Hashtable) fields[i].get(null);
@@ -1548,6 +1716,27 @@
         }
     }
 
+    public long getLastModified(File file)
+    {
+        if (System.getSecurityManager() != null)
+        {
+            Actions actions = (Actions) m_actions.get();
+            actions.set(Actions.LAST_MODIFIED, file);
+            try
+            {
+                return (Long) AccessController.doPrivileged(actions, m_acc);
+            }
+            catch (PrivilegedActionException e)
+            {
+                throw (RuntimeException) e.getException();
+            }
+        }
+        else
+        {
+            return file.lastModified();
+        }
+    }
+
     private static class Actions implements PrivilegedExceptionAction
     {
         public static final int INITIALIZE_CONTEXT_ACTION = 0;
@@ -1609,6 +1798,11 @@
         public static final int INVOKE_WOVEN_CLASS_LISTENER = 56;
         public static final int GET_CANONICAL_PATH = 57;
         public static final int CREATE_PROXY = 58;
+        public static final int LAST_MODIFIED = 59;
+        public static final int FILE_IS_FILE_ACTION = 60;
+        public static final int GET_FILE_CHANNEL_ACTION = 61;
+        private static final int GET_INPUT_ACTION = 62;
+        private static final int GET_OUTPUT_ACTION = 63;
 
         private int m_action = -1;
         private Object m_arg1 = null;
@@ -1708,7 +1902,7 @@
                     Method addURL =
                         URLClassLoader.class.getDeclaredMethod("addURL",
                         new Class[] {URL.class});
-                    addURL.setAccessible(true);
+                    getAccessor(URLClassLoader.class).accept(new AccessibleObject[]{addURL});
                     addURL.invoke(arg2, new Object[]{arg1});
                     return null;
                 case CREATE_TMPFILE_ACTION:
@@ -1740,7 +1934,7 @@
                     return ((Class) arg1).getDeclaredMethod((String) arg2, (Class[]) arg3);
                 case GET_FIELD_ACTION:
                     Field field = ((Class) arg1).getDeclaredField((String) arg2);
-                    field.setAccessible(true);
+                    getAccessor((Class) arg1).accept(new AccessibleObject[]{field});
                     return field.get(arg3);
                 case GET_FILE_INPUT_ACTION:
                     return new FileInputStream((File) arg1);
@@ -1765,7 +1959,7 @@
                 case INVOKE_DIRECTMETHOD_ACTION:
                     return ((Method) arg1).invoke(arg2, (Object[]) arg3);
                 case INVOKE_METHOD_ACTION:
-                    ((Method) arg1).setAccessible(true);
+                    getAccessor(((Method) arg1).getDeclaringClass()).accept(new AccessibleObject[]{(Method) arg1});
                     return ((Method) arg1).invoke(arg2, (Object[]) arg3);
                 case LIST_DIRECTORY_ACTION:
                     return ((File) arg1).listFiles();
@@ -1780,7 +1974,7 @@
                 case RENAME_FILE_ACTION:
                     return ((File) arg1).renameTo((File) arg2) ? Boolean.TRUE : Boolean.FALSE;
                 case SET_ACCESSIBLE_ACTION:
-                    ((AccessibleObject) arg1).setAccessible(true);
+                    getAccessor(((Executable) arg1).getDeclaringClass()).accept(new AccessibleObject[]{(Executable) arg1});
                     return null;
                 case START_ACTIVATOR_ACTION:
                     ((BundleActivator) arg1).start((BundleContext) arg2);
@@ -1872,6 +2066,16 @@
                 case CREATE_PROXY:
                     return Proxy.newProxyInstance((ClassLoader)arg1, (Class<?>[])arg2,
                             (InvocationHandler) arg3);
+                case LAST_MODIFIED:
+                    return ((File) arg1).lastModified();
+                case FILE_IS_FILE_ACTION:
+                    return ((File) arg1).isFile() ? Boolean.TRUE : Boolean.FALSE;
+                case GET_FILE_CHANNEL_ACTION:
+                    return FileChannel.open(((File) arg1).toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
+                case GET_INPUT_ACTION:
+                    return Files.newInputStream(((File) arg1).toPath());
+                case GET_OUTPUT_ACTION:
+                    return Files.newOutputStream(((File) arg1).toPath());
             }
 
             return null;
diff --git a/framework/src/main/java/org/apache/felix/framework/util/ThreadGate.java b/framework/src/main/java/org/apache/felix/framework/util/ThreadGate.java
index f9900a3..ff52080 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/ThreadGate.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/ThreadGate.java
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.framework.util;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * This class implements a simple one-shot gate for threads. The gate
  * starts closed and will block any threads that try to wait on it. Once
@@ -72,14 +74,14 @@
     **/
     public synchronized boolean await(long timeout) throws InterruptedException
     {
-        long start = System.currentTimeMillis();
+        long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
         long remaining = timeout;
         while (!m_open)
         {
             wait(remaining);
             if (timeout > 0)
             {
-                remaining = timeout - (System.currentTimeMillis() - start);
+                remaining = timeout - (TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start);
                 if (remaining <= 0)
                 {
                     break;
diff --git a/framework/src/main/java/org/apache/felix/framework/util/Util.java b/framework/src/main/java/org/apache/felix/framework/util/Util.java
index f6acd36..ee25452 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/Util.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/Util.java
@@ -45,8 +45,9 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -60,37 +61,51 @@
 {
     /**
      * The default name used for the default configuration properties file.
-    **/
-    private static final String DEFAULT_PROPERTIES_FILE = "default.properties";
+     **/
+    private static final String DEFAULT_PROPERTIES_FILE = "/default.properties";
+
+    private static final Properties DEFAULTS;
+
+    private static final IOException DEFAULT_EX;
+
+    private static final Map<String, Set<String>> MODULES_MAP;
+
+    static
+    {
+        Properties defaults = null;
+        IOException defaultEX = null;
+        try
+        {
+            defaults = loadDefaultProperties();
+        }
+        catch (IOException ex)
+        {
+            defaultEX = ex;
+        }
+        DEFAULTS = defaults;
+        DEFAULT_EX = defaultEX;
+
+        MODULES_MAP = calculateModulesMap();
+    }
 
     public static Properties loadDefaultProperties(Logger logger)
     {
+        if (DEFAULTS.isEmpty())
+        {
+            logger.log(Logger.LOG_ERROR, "Unable to load any configuration properties.", DEFAULT_EX);
+        }
+        return DEFAULTS;
+    }
+
+    private static Properties loadDefaultProperties() throws IOException
+    {
         Properties defaultProperties = new Properties();
-        URL propURL = Util.class.getClassLoader().getResource(DEFAULT_PROPERTIES_FILE);
+        URL propURL = Util.class.getResource(DEFAULT_PROPERTIES_FILE);
         if (propURL != null)
         {
-            InputStream is = null;
-            try
+            try (InputStream is = propURL.openConnection().getInputStream())
             {
-                // Load properties from URL.
-                is = propURL.openConnection().getInputStream();
                 defaultProperties.load(is);
-                is.close();
-            }
-            catch (Exception ex)
-            {
-                // Try to close input stream if we have one.
-                try
-                {
-                    if (is != null) is.close();
-                }
-                catch (IOException ex2)
-                {
-                    // Nothing we can do.
-                }
-
-                logger.log(
-                    Logger.LOG_ERROR, "Unable to load any configuration properties.", ex);
             }
         }
         return defaultProperties;
@@ -138,13 +153,15 @@
                 properties.put("ee-jpms", ee.toString());
 
                 properties.put("eecap-jpms", eecap.toString());
+
+                properties.put("felix.detect.jpms", "jpms");
             }
 
-            properties.put("felix.detect.java.specification.version", version.getMajor() < 9 ? ("1." + (version.getMinor() > 6 ? version.getMinor() : 6)) : Integer.toString(version.getMajor()));
+            properties.put("felix.detect.java.specification.version", version.getMajor() < 9 ? ("1." + (version.getMinor() > 6 ? version.getMinor() < 8 ? version.getMinor() : 8 : 6)) : Integer.toString(version.getMajor()));
 
             if (version.getMajor() < 9)
             {
-                properties.put("felix.detect.java.version", String.format("0.0.0.JavaSE_001_%03d", version.getMinor() > 6 ? version.getMinor() : 6));
+                properties.put("felix.detect.java.version", String.format("0.0.0.JavaSE_001_%03d", version.getMinor() > 6 ? version.getMinor() < 8 ? version.getMinor() : 8 : 6));
             }
             else
             {
@@ -157,9 +174,9 @@
         }
     }
 
-    public static Map<String, Set<String>> initializeJPMS(Properties properties)
+    private static Map<String, Set<String>> calculateModulesMap()
     {
-        Map<String,Set<String>> exports = null;
+        Map<String, Set<String>> result = new LinkedHashMap<>();
         try
         {
             Class<?> c_ModuleLayer = Felix.class.getClassLoader().loadClass("java.lang.ModuleLayer");
@@ -168,8 +185,9 @@
             Class<?> c_Exports = Felix.class.getClassLoader().loadClass("java.lang.module.ModuleDescriptor$Exports");
             Method m_getLayer = c_Module.getMethod("getLayer");
             Method m_getModule = Class.class.getMethod("getModule");
-            Method m_canRead = c_Module.getMethod("canRead", c_Module);
             Method m_getName = c_Module.getMethod("getName");
+            Method isAutomatic = c_Descriptor.getMethod("isAutomatic");
+            Method packagesMethod = c_Descriptor.getMethod("packages");
 
             Object self = m_getModule.invoke(Felix.class);
             Object moduleLayer = m_getLayer.invoke(self);
@@ -179,44 +197,69 @@
                 moduleLayer = c_ModuleLayer.getMethod("boot").invoke(null);
             }
 
-            Set<String> modules = new TreeSet<String>();
-            exports = new HashMap<String, Set<String>>();
             for (Object module : ((Iterable) c_ModuleLayer.getMethod("modules").invoke(moduleLayer)))
             {
-                if ((Boolean) m_canRead.invoke(self, module))
+                if (!self.equals(module))
                 {
-                    Object name = m_getName.invoke(module);
-                    properties.put("felix.detect.jpms." + name, name);
-                    modules.add("felix.jpms." + name);
-                    Set<String> pkgs = new HashSet<String>();
+                    String name = (String) m_getName.invoke(module);
+
+                    Set<String> pkgs = new LinkedHashSet<>();
 
                     Object descriptor = c_Module.getMethod("getDescriptor").invoke(module);
 
-                    for (Object export :((Set) c_Descriptor.getMethod("exports").invoke(descriptor)))
+                    if (!((Boolean) isAutomatic.invoke(descriptor)))
                     {
-                        if (((Set) c_Exports.getMethod("targets").invoke(export)).isEmpty())
+                        for (Object export : ((Set) c_Descriptor.getMethod("exports").invoke(descriptor)))
                         {
-                            pkgs.add((String) c_Exports.getMethod("source").invoke(export));
+                            if (((Set) c_Exports.getMethod("targets").invoke(export)).isEmpty())
+                            {
+                                pkgs.add((String) c_Exports.getMethod("source").invoke(export));
+                            }
                         }
                     }
-                    if (!pkgs.isEmpty())
+                    else
                     {
-                        exports.put("felix.jpms." + c_Descriptor.getMethod("toNameAndVersion").invoke(descriptor), pkgs);
+                        pkgs.addAll((Set<String>) packagesMethod.invoke(descriptor));
                     }
+                    result.put(name, pkgs);
+                }
+            }
+        }
+        catch (Exception ex)
+        {
+            //ex.printStackTrace();
+            // Not much we can do - probably not on java9
+        }
+        return result;
+    }
+
+    public static Map<String, Set<String>> initializeJPMS(Properties properties)
+    {
+        Map<String,Set<String>> exports = null;
+        if (!MODULES_MAP.isEmpty())
+        {
+            Set<String> modules = new TreeSet<String>();
+            exports = new HashMap<String, Set<String>>();
+            for (Map.Entry<String, Set<String>> module : MODULES_MAP.entrySet())
+            {
+                Object name = module.getKey();
+                properties.put("felix.detect.jpms." + name, name);
+                modules.add("felix.jpms." + name);
+                Set<String> pkgs = module.getValue();
+
+                if (!pkgs.isEmpty())
+                {
+                    exports.put("felix.jpms." + name, pkgs);
                 }
             }
 
-            properties.put("felix.detect.jpms", "jpms");
             String modulesString = "";
             for (String module : modules) {
                 modulesString += "${" + module + "}";
             }
             properties.put("jre-jpms", modulesString);
         }
-        catch (Exception ex)
-        {
-            // Not much we can do - probably not on java9
-        }
+
         return exports;
     }
 
@@ -427,6 +470,31 @@
         return null;
     }
 
+    public static boolean checkImplementsWithName(Class<?> clazz, String name)
+    {
+        while (clazz != null)
+        {
+            if (clazz.getName().equals(name))
+            {
+                return true;
+            }
+            // Try to see if
+            // one of the class's implemented interface
+            // is the name.
+            Class[] ifcs = clazz.getInterfaces();
+            for (int i = 0; i < ifcs.length; i++)
+            {
+                if (checkImplementsWithName(ifcs[i], name)) {
+                    return true;
+                }
+            }
+
+            // Try the super class class loader.
+            clazz = clazz.getSuperclass();
+        }
+        return false;
+    }
+
     /**
      * This method determines if the requesting bundle is able to cast
      * the specified service reference based on class visibility rules
@@ -1034,4 +1102,4 @@
     {
         return map == null || map.isEmpty() ? EMPTY_MAP : Collections.unmodifiableMap(map);
     }
-}
\ No newline at end of file
+}
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
index 9158c6a..09e0572 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/ManifestParser.java
@@ -20,6 +20,7 @@
 
 import org.apache.felix.framework.BundleRevisionImpl;
 import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.cache.ConnectContentContent;
 import org.apache.felix.framework.capabilityset.SimpleFilter;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.wiring.BundleCapabilityImpl;
@@ -28,6 +29,7 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
 import org.osgi.framework.VersionRange;
+import org.osgi.framework.connect.ConnectContent;
 import org.osgi.framework.namespace.BundleNamespace;
 import org.osgi.framework.namespace.ExecutionEnvironmentNamespace;
 import org.osgi.framework.namespace.IdentityNamespace;
@@ -41,6 +43,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -109,7 +112,7 @@
         // Parse bundle symbolic name.
         //
 
-        BundleCapabilityImpl bundleCap = parseBundleSymbolicName(owner, m_headerMap);
+        BundleCapabilityImpl bundleCap = parseBundleSymbolicName(logger, owner, m_headerMap);
         if (bundleCap != null)
         {
             m_bundleSymbolicName = (String)
@@ -215,7 +218,7 @@
         List<ParsedHeaderClause> exportClauses =
             parseStandardHeader((String) headerMap.get(Constants.EXPORT_PACKAGE));
         exportClauses = normalizeExportClauses(logger, exportClauses,
-            getManifestVersion(), m_bundleSymbolicName, m_bundleVersion);
+            getManifestVersion(), m_bundleSymbolicName, m_bundleVersion, owner instanceof BundleRevisionImpl && ((BundleRevisionImpl) owner).getContent() instanceof ConnectContentContent);
         List<BundleCapability> exportCaps = convertExports(exportClauses, owner);
 
         //
@@ -696,7 +699,7 @@
         throws BundleException
     {
 
-        if (!mv.equals("2") && !clauses.isEmpty())
+        if (mv != null && !mv.equals("2") && !clauses.isEmpty())
         {
             // Should we error here if we are not an R4 bundle?
         }
@@ -836,7 +839,7 @@
 
     private static List<ParsedHeaderClause> normalizeExportClauses(
         Logger logger, List<ParsedHeaderClause> clauses,
-        String mv, String bsn, Version bv)
+        String mv, String bsn, Version bv, boolean connectModule)
         throws BundleException
     {
         for (ParsedHeaderClause clause : clauses)
@@ -845,7 +848,7 @@
             for (String pkgName : clause.m_paths)
             {
                 // Verify that java.* packages are not exported (except from the system bundle).
-                if (!FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(bsn) && pkgName.startsWith("java."))
+                if ((!FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(bsn) && !connectModule) && pkgName.startsWith("java."))
                 {
                     throw new BundleException(
                         "Exporting java.* packages not allowed: "
@@ -1358,12 +1361,12 @@
         return false;
     }
 
-    private static BundleCapabilityImpl parseBundleSymbolicName(
+    private static BundleCapabilityImpl parseBundleSymbolicName(Logger logger,
         BundleRevision owner, Map<String, Object> headerMap)
         throws BundleException
     {
-        List<ParsedHeaderClause> clauses = parseStandardHeader(
-            (String) headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+        List<ParsedHeaderClause> clauses = normalizeCapabilityClauses(logger, parseStandardHeader(
+            (String) headerMap.get(Constants.BUNDLE_SYMBOLICNAME)), getManifestVersion(headerMap));
         if (clauses.size() > 0)
         {
             if (clauses.size() > 1)
@@ -1378,6 +1381,11 @@
                     "Cannot have multiple symbolic names: "
                         + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
             }
+            else if (clauses.get(0).m_attrs.containsKey(Constants.BUNDLE_VERSION))
+            {
+                throw new BundleException(
+                    "Cannot have a bundle version: " + headerMap.get(Constants.BUNDLE_VERSION));
+            }
 
             // Get bundle version.
             Version bundleVersion = Version.emptyVersion;
@@ -1400,6 +1408,48 @@
                 }
             }
 
+            Object tagList = clauses.get(0).m_attrs.get(IdentityNamespace.CAPABILITY_TAGS_ATTRIBUTE);
+            LinkedHashSet<String> tags = new LinkedHashSet<>();
+            if (tagList != null)
+            {
+                if (tagList instanceof List)
+                {
+                    for (Object member : ((List) tagList))
+                    {
+                        if (member instanceof String)
+                        {
+                            tags.add((String) member);
+                        }
+                        else
+                        {
+                            throw new BundleException("Invalid tags list: " + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+                        }
+                    }
+                }
+                else if (tagList instanceof String)
+                {
+                    tags.add((String) tagList);
+                }
+                else
+                {
+                    throw new BundleException("Invalid tags list: " + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+                }
+            }
+
+            if (tags.contains(ConnectContent.TAG_OSGI_CONNECT))
+            {
+                throw new BundleException("Invalid tags list: " + headerMap.get(Constants.BUNDLE_SYMBOLICNAME));
+            }
+            if (owner != null && ((BundleRevisionImpl) owner).getContent() instanceof ConnectContentContent)
+            {
+                tags.add(ConnectContent.TAG_OSGI_CONNECT);
+            }
+
+            if (!tags.isEmpty())
+            {
+                clauses.get(0).m_attrs.put(IdentityNamespace.CAPABILITY_TAGS_ATTRIBUTE, new ArrayList<>(tags));
+            }
+
             // Create a require capability and return it.
             String symName = (String) clauses.get(0).m_paths.get(0);
             clauses.get(0).m_attrs.put(BundleRevision.BUNDLE_NAMESPACE, symName);
@@ -1415,9 +1465,9 @@
     }
 
     private static BundleCapabilityImpl addIdentityCapability(BundleRevision owner,
-        Map<String, Object> headerMap, BundleCapabilityImpl bundleCap)
+        Map<String, Object> headerMap, BundleCapabilityImpl bundleCap) throws BundleException
     {
-        Map<String, Object> attrs = new HashMap<String, Object>();
+        Map<String, Object> attrs = new HashMap<String, Object>(bundleCap.getAttributes());
 
         attrs.put(IdentityNamespace.IDENTITY_NAMESPACE,
             bundleCap.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
diff --git a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/NativeLibraryClause.java b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/NativeLibraryClause.java
index 69e7155..bd4edf0 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/manifestparser/NativeLibraryClause.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/manifestparser/NativeLibraryClause.java
@@ -72,6 +72,7 @@
     private static final String OS_WINDOWS_SERVER_2008 = "windowsserver2008";
     private static final String OS_WINDOWS_SERVER_2012 = "windowsserver2012";
     private static final String OS_WINDOWS_SERVER_2016 = "windowsserver2016";
+    private static final String OS_WINDOWS_SERVER_2019 = "windowsserver2019";
     private static final String OS_WINDOWS_VISTA = "windowsvista";
     private static final String OS_WINDOWS_XP = "windowsxp";
     private static final String OS_WIN_32 = "win32";
@@ -579,6 +580,10 @@
             {
                 os = OS_WINDOWS_SERVER_2016;
             }
+            else if (value.indexOf("2019") >= 0)
+            {
+                os = OS_WINDOWS_SERVER_2019;
+            }
             else if (value.indexOf("xp") >= 0)
             {
                 os = OS_WINDOWS_XP;
diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
index 9fa3806..f426ad1 100644
--- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java
@@ -25,7 +25,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
-import org.apache.felix.framework.capabilityset.SimpleFilter;
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.framework.util.manifestparser.ManifestParser;
 import org.osgi.framework.Constants;
@@ -41,8 +40,6 @@
     private final Map<String, String> m_dirs;
     private final Map<String, Object> m_attrs;
     private final List<String> m_uses;
-    private final List<List<String>> m_includeFilter;
-    private final List<List<String>> m_excludeFilter;
     private final Set<String> m_mandatory;
 
     public BundleCapabilityImpl(BundleRevision revision, String namespace,
@@ -55,13 +52,13 @@
 
         // Find all export directives: uses, mandatory, include, and exclude.
 
-        List<String> uses = Collections.EMPTY_LIST;
+        List<String> uses = Collections.emptyList();
         String value = m_dirs.get(Constants.USES_DIRECTIVE);
         if (value != null)
         {
             // Parse these uses directive.
             StringTokenizer tok = new StringTokenizer(value, ",");
-            uses = new ArrayList(tok.countTokens());
+            uses = new ArrayList<>(tok.countTokens());
             while (tok.hasMoreTokens())
             {
                 uses.add(tok.nextToken().trim());
@@ -69,44 +66,12 @@
         }
         m_uses = uses;
 
-        value = m_dirs.get(Constants.INCLUDE_DIRECTIVE);
-        if (value != null)
-        {
-            List<String> filters = ManifestParser.parseDelimitedString(value, ",");
-            m_includeFilter = new ArrayList<List<String>>(filters.size());
-            for (int filterIdx = 0; filterIdx < filters.size(); filterIdx++)
-            {
-                List<String> substrings = SimpleFilter.parseSubstring(filters.get(filterIdx));
-                m_includeFilter.add(substrings);
-            }
-        }
-        else
-        {
-            m_includeFilter = null;
-        }
-
-        value = m_dirs.get(Constants.EXCLUDE_DIRECTIVE);
-        if (value != null)
-        {
-            List<String> filters = ManifestParser.parseDelimitedString(value, ",");
-            m_excludeFilter = new ArrayList<List<String>>(filters.size());
-            for (int filterIdx = 0; filterIdx < filters.size(); filterIdx++)
-            {
-                List<String> substrings = SimpleFilter.parseSubstring(filters.get(filterIdx));
-                m_excludeFilter.add(substrings);
-            }
-        }
-        else
-        {
-            m_excludeFilter = null;
-        }
-
-        Set<String> mandatory = Collections.EMPTY_SET;
+        Set<String> mandatory = Collections.emptySet();
         value = m_dirs.get(Constants.MANDATORY_DIRECTIVE);
         if (value != null)
         {
             List<String> names = ManifestParser.parseDelimitedString(value, ",");
-            mandatory = new HashSet<String>(names.size());
+            mandatory = new HashSet<>(names.size());
             for (String name : names)
             {
                 // If attribute exists, then record it as mandatory.
@@ -160,38 +125,6 @@
         return m_uses;
     }
 
-    public boolean isIncluded(String name)
-    {
-        if ((m_includeFilter == null) && (m_excludeFilter == null))
-        {
-            return true;
-        }
-
-        // Get the class name portion of the target class.
-        String className = Util.getClassName(name);
-
-        // If there are no include filters then all classes are included
-        // by default, otherwise try to find one match.
-        boolean included = (m_includeFilter == null);
-        for (int i = 0;
-            (!included) && (m_includeFilter != null) && (i < m_includeFilter.size());
-            i++)
-        {
-            included = SimpleFilter.compareSubstring(m_includeFilter.get(i), className);
-        }
-
-        // If there are no exclude filters then no classes are excluded
-        // by default, otherwise try to find one match.
-        boolean excluded = false;
-        for (int i = 0;
-            (!excluded) && (m_excludeFilter != null) && (i < m_excludeFilter.size());
-            i++)
-        {
-            excluded = SimpleFilter.compareSubstring(m_excludeFilter.get(i), className);
-        }
-        return included && !excluded;
-    }
-
     @Override
     public String toString()
     {
diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
index 3e3b685..881d366 100644
--- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java
@@ -61,7 +61,7 @@
         BundleRevision revision, String namespace,
         Map<String, String> dirs, Map<String, Object> attrs)
     {
-        this(revision, namespace, dirs, Collections.EMPTY_MAP, SimpleFilter.convert(attrs));
+        this(revision, namespace, dirs, Collections.emptyMap(), SimpleFilter.convert(attrs));
     }
 
     public String getNamespace()
@@ -91,7 +91,7 @@
 
     public boolean matches(BundleCapability cap)
     {
-        return CapabilitySet.matches((BundleCapabilityImpl) cap, getFilter());
+        return CapabilitySet.matches(cap, getFilter());
     }
 
     public boolean isOptional()
diff --git a/framework/src/main/java/org/osgi/dto/DTO.java b/framework/src/main/java/org/osgi/dto/DTO.java
index 53074a6..f109341 100644
--- a/framework/src/main/java/org/osgi/dto/DTO.java
+++ b/framework/src/main/java/org/osgi/dto/DTO.java
@@ -35,7 +35,7 @@
  * The object graph from a Data Transfer Object must be a tree to simplify
  * serialization and deserialization.
  * 
- * @author $Id$
+ * @author $Id: DTO.java 1825132 2018-02-23 15:11:00Z pauls $
  * @NotThreadSafe
  */
 public abstract class DTO {
diff --git a/framework/src/main/java/org/osgi/dto/package-info.java b/framework/src/main/java/org/osgi/dto/package-info.java
index d0d0ad1..0a1637e 100644
--- a/framework/src/main/java/org/osgi/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/dto/package-info.java
@@ -30,7 +30,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.dto; version="[1.1,1.2)"}
  *
- * @author $Id$
+ * @author $Id: package-info.java 1825132 2018-02-23 15:11:00Z pauls $
  */
 
 @Version("1.1")
diff --git a/framework/src/main/java/org/osgi/framework/BundlePermission.java b/framework/src/main/java/org/osgi/framework/BundlePermission.java
index 2371599..d4de480 100644
--- a/framework/src/main/java/org/osgi/framework/BundlePermission.java
+++ b/framework/src/main/java/org/osgi/framework/BundlePermission.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2004, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2019). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -58,7 +58,7 @@
  * 
  * @since 1.3
  * @ThreadSafe
- * @author $Id: 7b0816059dc9b3e37f0375039bebbe5f0b18d998 $
+ * @author $Id: 7a45b1cb579ff9cfd1582f82436dd755ff805fba $
  */
 
 public final class BundlePermission extends BasicPermission {
@@ -543,7 +543,7 @@
 			// work our way up the tree...
 			int last;
 			int offset = requestedName.length() - 1;
-			while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+			while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
 				requestedName = requestedName.substring(0, last + 1) + "*";
 				bp = pc.get(requestedName);
 				if (bp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/CapabilityPermission.java b/framework/src/main/java/org/osgi/framework/CapabilityPermission.java
index 177ff97..60a5202 100644
--- a/framework/src/main/java/org/osgi/framework/CapabilityPermission.java
+++ b/framework/src/main/java/org/osgi/framework/CapabilityPermission.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@
  * </ul>
  * 
  * @ThreadSafe
- * @author $Id: 8a38df04e56e9dcab7ea413ba69d4c4f05487c25 $
+ * @author $Id: c7bae50cab3a92ba810fcf983081c008f22a6bbd $
  * @since 1.6
  */
 
@@ -714,7 +714,7 @@
 			/* work our way up the tree... */
 			int last;
 			int offset = requestedName.length() - 1;
-			while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+			while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
 				requestedName = requestedName.substring(0, last + 1) + "*";
 				cp = pc.get(requestedName);
 				if (cp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/Constants.java b/framework/src/main/java/org/osgi/framework/Constants.java
index 68dfb53..19c68b8 100644
--- a/framework/src/main/java/org/osgi/framework/Constants.java
+++ b/framework/src/main/java/org/osgi/framework/Constants.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2000, 2018). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2020). All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
  * otherwise indicated.
  * 
  * @since 1.1
- * @author $Id: 41e648afb56767a610f279a9c7effef47dfcbf2e $
+ * @author $Id: 57af8721d5f7e08f9b8a1d9f109a5ebb94bf9646 $
  */
 @ProviderType
 public interface Constants {
@@ -1025,7 +1025,6 @@
 	/**
 	 * Framework environment property identifying whether the Framework supports
 	 * bootclasspath extension bundles.
-	 * 
 	 * <p>
 	 * If the value of this property is {@code true}, then the Framework
 	 * supports bootclasspath extension bundles. The default value is
@@ -1035,6 +1034,7 @@
 	 * {@code BundleContext.getProperty} method.
 	 * 
 	 * @since 1.3
+	 * @deprecated As of 1.10.
 	 */
 	String	SUPPORTS_BOOTCLASSPATH_EXTENSION		= "org.osgi.supports.bootclasspath.extension";
 
@@ -1574,7 +1574,7 @@
 	String	SERVICE_IMPORTED_CONFIGS				= "service.imported.configs";
 
 	/**
-	 * Service property identifying the intents that this service implement.
+	 * Service property identifying the intents that this service implements.
 	 * This property has a dual purpose:
 	 * <ul>
 	 * <li>A bundle can use this service property to notify the distribution
@@ -1833,8 +1833,8 @@
 	 * Service property identifying the monotonically increasing change count of
 	 * a service.
 	 * <p>
-	 * A service may optional provide this property to indicate there has been a
-	 * change in some data provided by the service. The change count must be
+	 * A service may provide this property to indicate there has been a change
+	 * in some data provided by the service. The change count must be
 	 * incremented with a positive value every time the data provided by the
 	 * service is changed. The service announces the modified change count by
 	 * updating its service properties with the new value for this service
diff --git a/framework/src/main/java/org/osgi/framework/FilterImpl.java b/framework/src/main/java/org/osgi/framework/FilterImpl.java
new file mode 100755
index 0000000..5d88a58
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/FilterImpl.java
@@ -0,0 +1,1385 @@
+/*
+ * Copyright (c) OSGi Alliance (2005, 2020). All Rights Reserved.
+ *
+ * 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 org.osgi.framework;
+
+import static java.util.Objects.requireNonNull;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * RFC 1960-based Filter. Filter objects can be created by calling the
+ * constructor with the desired filter string. A Filter object can be called
+ * numerous times to determine if the match argument matches the filter string
+ * that was used to create the Filter object.
+ * <p>
+ * The syntax of a filter string is the string representation of LDAP search
+ * filters as defined in RFC 1960: <i>A String Representation of LDAP Search
+ * Filters</i> (available at http://www.ietf.org/rfc/rfc1960.txt). It should be
+ * noted that RFC 2254: <i>A String Representation of LDAP Search Filters</i>
+ * (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes RFC 1960 but
+ * only adds extensible matching and is not applicable for this API.
+ * <p>
+ * The string representation of an LDAP search filter is defined by the
+ * following grammar. It uses a prefix format.
+ * 
+ * <pre>
+ *   &lt;filter&gt; ::= '(' &lt;filtercomp&gt; ')'
+ *   &lt;filtercomp&gt; ::= &lt;and&gt; | &lt;or&gt; | &lt;not&gt; | &lt;item&gt;
+ *   &lt;and&gt; ::= '&amp;' &lt;filterlist&gt;
+ *   &lt;or&gt; ::= '|' &lt;filterlist&gt;
+ *   &lt;not&gt; ::= '!' &lt;filter&gt;
+ *   &lt;filterlist&gt; ::= &lt;filter&gt; | &lt;filter&gt; &lt;filterlist&gt;
+ *   &lt;item&gt; ::= &lt;simple&gt; | &lt;present&gt; | &lt;substring&gt;
+ *   &lt;simple&gt; ::= &lt;attr&gt; &lt;filtertype&gt; &lt;value&gt;
+ *   &lt;filtertype&gt; ::= &lt;equal&gt; | &lt;approx&gt; | &lt;greater&gt; | &lt;less&gt;
+ *   &lt;equal&gt; ::= '='
+ *   &lt;approx&gt; ::= '&tilde;='
+ *   &lt;greater&gt; ::= '&gt;='
+ *   &lt;less&gt; ::= '&lt;='
+ *   &lt;present&gt; ::= &lt;attr&gt; '=*'
+ *   &lt;substring&gt; ::= &lt;attr&gt; '=' &lt;initial&gt; &lt;any&gt; &lt;final&gt;
+ *   &lt;initial&gt; ::= NULL | &lt;value&gt;
+ *   &lt;any&gt; ::= '*' &lt;starval&gt;
+ *   &lt;starval&gt; ::= NULL | &lt;value&gt; '*' &lt;starval&gt;
+ *   &lt;final&gt; ::= NULL | &lt;value&gt;
+ * </pre>
+ * 
+ * {@code &lt;attr&gt;} is a string representing an attribute, or key, in the
+ * properties objects of the registered services. Attribute names are not case
+ * sensitive; that is cn and CN both refer to the same attribute.
+ * {@code &lt;value&gt;} is a string representing the value, or part of one, of
+ * a key in the properties objects of the registered services. If a
+ * {@code &lt;value&gt;} must contain one of the characters ' {@code *}' or
+ * '{@code (}' or '{@code )}', these characters should be escaped by preceding
+ * them with the backslash '{@code \}' character. Note that although both the
+ * {@code &lt;substring&gt;} and {@code &lt;present&gt;} productions can produce
+ * the {@code 'attr=*'} construct, this construct is used only to denote a
+ * presence filter.
+ * <p>
+ * Examples of LDAP filters are:
+ * 
+ * <pre>
+ *   &quot;(cn=Babs Jensen)&quot;
+ *   &quot;(!(cn=Tim Howes))&quot;
+ *   &quot;(&amp;(&quot; + Constants.OBJECTCLASS + &quot;=Person)(|(sn=Jensen)(cn=Babs J*)))&quot;
+ *   &quot;(o=univ*of*mich*)&quot;
+ * </pre>
+ * <p>
+ * The approximate match ({@code ~=}) is implementation specific but should at
+ * least ignore case and white space differences. Optional are codes like
+ * soundex or other smart "closeness" comparisons.
+ * <p>
+ * Comparison of values is not straightforward. Strings are compared differently
+ * than numbers and it is possible for a key to have multiple values. Note that
+ * that keys in the match argument must always be strings. The comparison is
+ * defined by the object type of the key's value. The following rules apply for
+ * comparison: <blockquote>
+ * <TABLE BORDER=0>
+ * <TR>
+ * <TD><b>Property Value Type </b></TD>
+ * <TD><b>Comparison Type</b></TD>
+ * </TR>
+ * <TR>
+ * <TD>String</TD>
+ * <TD>String comparison</TD>
+ * </TR>
+ * <TR valign=top>
+ * <TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal</TD>
+ * <TD>numerical comparison</TD>
+ * </TR>
+ * <TR>
+ * <TD>Character</TD>
+ * <TD>character comparison</TD>
+ * </TR>
+ * <TR>
+ * <TD>Boolean</TD>
+ * <TD>equality comparisons only</TD>
+ * </TR>
+ * <TR>
+ * <TD>[] (array)</TD>
+ * <TD>recursively applied to values</TD>
+ * </TR>
+ * <TR>
+ * <TD>Collection</TD>
+ * <TD>recursively applied to values</TD>
+ * </TR>
+ * </TABLE>
+ * Note: arrays of primitives are also supported. </blockquote> A filter matches
+ * a key that has multiple values if it matches at least one of those values.
+ * For example,
+ * 
+ * <pre>
+ * Dictionary d = new Hashtable();
+ * d.put(&quot;cn&quot;, new String[] {
+ * 		&quot;a&quot;, &quot;b&quot;, &quot;c&quot;
+ * });
+ * </pre>
+ * 
+ * d will match {@code (cn=a)} and also {@code (cn=b)}
+ * <p>
+ * A filter component that references a key having an unrecognizable data type
+ * will evaluate to {@code false} .
+ */
+abstract class FilterImpl implements Filter {
+	/* normalized filter string for Filter object */
+	private transient String filterString;
+
+	/**
+	 * Creates a {@link FilterImpl} object. This filter object may be used to
+	 * match a {@link ServiceReference} or a Dictionary.
+	 * <p>
+	 * If the filter cannot be parsed, an {@link InvalidSyntaxException} will be
+	 * thrown with a human readable message where the filter became unparsable.
+	 * 
+	 * @param filterString the filter string.
+	 * @throws InvalidSyntaxException If the filter parameter contains an
+	 *             invalid filter string that cannot be parsed.
+	 */
+	static FilterImpl createFilter(String filterString)
+			throws InvalidSyntaxException {
+		return new Parser(filterString).parse();
+	}
+
+	FilterImpl() {
+		// empty constructor for subclasses
+	}
+
+	/**
+	 * Filter using a service's properties.
+	 * <p>
+	 * This {@code Filter} is executed using the keys and values of the
+	 * referenced service's properties. The keys are looked up in a case
+	 * insensitive manner.
+	 * 
+	 * @param reference The reference to the service whose properties are used
+	 *            in the match.
+	 * @return {@code true} if the service's properties match this
+	 *         {@code Filter}; {@code false} otherwise.
+	 */
+	@Override
+	public boolean match(ServiceReference< ? > reference) {
+		return matches0((reference != null) ? new ServiceReferenceMap(reference)
+				: Collections.emptyMap());
+	}
+
+	/**
+	 * Filter using a {@code Dictionary} with case insensitive key lookup. This
+	 * {@code Filter} is executed using the specified {@code Dictionary}'s keys
+	 * and values. The keys are looked up in a case insensitive manner.
+	 * 
+	 * @param dictionary The {@code Dictionary} whose key/value pairs are used
+	 *            in the match.
+	 * @return {@code true} if the {@code Dictionary}'s values match this
+	 *         filter; {@code false} otherwise.
+	 * @throws IllegalArgumentException If {@code dictionary} contains case
+	 *             variants of the same key name.
+	 */
+	@Override
+	public boolean match(Dictionary<String, ? > dictionary) {
+		return matches0(
+				(dictionary != null) ? new CaseInsensitiveMap(dictionary)
+						: Collections.emptyMap());
+	}
+
+	/**
+	 * Filter using a {@code Dictionary}. This {@code Filter} is executed using
+	 * the specified {@code Dictionary}'s keys and values. The keys are looked
+	 * up in a normal manner respecting case.
+	 * 
+	 * @param dictionary The {@code Dictionary} whose key/value pairs are used
+	 *            in the match.
+	 * @return {@code true} if the {@code Dictionary}'s values match this
+	 *         filter; {@code false} otherwise.
+	 * @since 1.3
+	 */
+	@Override
+	public boolean matchCase(Dictionary<String, ? > dictionary) {
+		return matches0((dictionary != null) ? DictionaryMap.asMap(dictionary)
+				: Collections.emptyMap());
+	}
+
+	/**
+	 * Filter using a {@code Map}. This {@code Filter} is executed using the
+	 * specified {@code Map}'s keys and values. The keys are looked up in a
+	 * normal manner respecting case.
+	 * 
+	 * @param map The {@code Map} whose key/value pairs are used in the match.
+	 *            Maps with {@code null} key or values are not supported. A
+	 *            {@code null} value is considered not present to the filter.
+	 * @return {@code true} if the {@code Map}'s values match this filter;
+	 *         {@code false} otherwise.
+	 * @since 1.6
+	 */
+	@Override
+	public boolean matches(Map<String, ? > map) {
+		return matches0((map != null) ? map : Collections.emptyMap());
+	}
+
+	abstract boolean matches0(Map<String, ? > map);
+
+	/**
+	 * Returns this {@code Filter}'s filter string.
+	 * <p>
+	 * The filter string is normalized by removing whitespace which does not
+	 * affect the meaning of the filter.
+	 * 
+	 * @return This {@code Filter}'s filter string.
+	 */
+	@Override
+	public String toString() {
+		String result = filterString;
+		if (result == null) {
+			filterString = result = normalize(new StringBuilder()).toString();
+		}
+		return result;
+	}
+
+	/**
+	 * Returns this {@code Filter}'s normalized filter string.
+	 * <p>
+	 * The filter string is normalized by removing whitespace which does not
+	 * affect the meaning of the filter.
+	 * 
+	 * @return This {@code Filter}'s filter string.
+	 */
+	abstract StringBuilder normalize(StringBuilder sb);
+
+	/**
+	 * Compares this {@code Filter} to another {@code Filter}.
+	 * <p>
+	 * This implementation returns the result of calling
+	 * {@code this.toString().equals(obj.toString()}.
+	 * 
+	 * @param obj The object to compare against this {@code Filter}.
+	 * @return If the other object is a {@code Filter} object, then returns the
+	 *         result of calling {@code this.toString().equals(obj.toString()};
+	 *         {@code false} otherwise.
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+
+		if (!(obj instanceof Filter)) {
+			return false;
+		}
+
+		return this.toString().equals(obj.toString());
+	}
+
+	/**
+	 * Returns the hashCode for this {@code Filter}.
+	 * <p>
+	 * This implementation returns the result of calling
+	 * {@code this.toString().hashCode()}.
+	 * 
+	 * @return The hashCode of this {@code Filter}.
+	 */
+	@Override
+	public int hashCode() {
+		return this.toString().hashCode();
+	}
+
+	static final class And extends FilterImpl {
+		private final FilterImpl[] operands;
+
+		And(FilterImpl[] operands) {
+			this.operands = operands;
+		}
+
+		@Override
+		boolean matches0(Map<String, ? > map) {
+			for (FilterImpl operand : operands) {
+				if (!operand.matches0(map)) {
+					return false;
+				}
+			}
+			return true;
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append('&');
+			for (FilterImpl operand : operands) {
+				operand.normalize(sb);
+			}
+			return sb.append(')');
+		}
+	}
+
+	static final class Or extends FilterImpl {
+		private final FilterImpl[] operands;
+
+		Or(FilterImpl[] operands) {
+			this.operands = operands;
+		}
+
+		@Override
+		boolean matches0(Map<String, ? > map) {
+			for (FilterImpl operand : operands) {
+				if (operand.matches0(map)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append('|');
+			for (FilterImpl operand : operands) {
+				operand.normalize(sb);
+			}
+			return sb.append(')');
+		}
+	}
+
+	static final class Not extends FilterImpl {
+		private final FilterImpl operand;
+
+		Not(FilterImpl operand) {
+			this.operand = operand;
+		}
+
+		@Override
+		boolean matches0(Map<String, ? > map) {
+			return !operand.matches0(map);
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append('!');
+			operand.normalize(sb);
+			return sb.append(')');
+		}
+	}
+
+	static abstract class Item extends FilterImpl {
+		final String attr;
+
+		Item(String attr) {
+			this.attr = attr;
+		}
+
+		@Override
+		boolean matches0(Map<String, ? > map) {
+			return compare(map.get(attr));
+		}
+
+		private boolean compare(Object value1) {
+			if (value1 == null) {
+				return false;
+			}
+			if (value1 instanceof String) {
+				return compare_String((String) value1);
+			}
+			if (value1 instanceof Version) {
+				return compare_Version((Version) value1);
+			}
+
+			Class< ? > clazz = value1.getClass();
+			if (clazz.isArray()) {
+				Class< ? > type = clazz.getComponentType();
+				if (type.isPrimitive()) {
+					return compare_PrimitiveArray(type, value1);
+				}
+				return compare_ObjectArray((Object[]) value1);
+			}
+			if (value1 instanceof Collection< ? >) {
+				return compare_Collection((Collection< ? >) value1);
+			}
+			if (value1 instanceof Integer || value1 instanceof Long
+					|| value1 instanceof Byte || value1 instanceof Short) {
+				return compare_Long(((Number) value1).longValue());
+			}
+			if (value1 instanceof Character) {
+				return compare_Character(((Character) value1).charValue());
+			}
+			if (value1 instanceof Float) {
+				return compare_Float(((Float) value1).floatValue());
+			}
+			if (value1 instanceof Double) {
+				return compare_Double(((Double) value1).doubleValue());
+			}
+			if (value1 instanceof Boolean) {
+				return compare_Boolean(((Boolean) value1).booleanValue());
+			}
+			if (value1 instanceof Comparable< ? >) {
+				@SuppressWarnings("unchecked")
+				Comparable<Object> comparable = (Comparable<Object>) value1;
+				return compare_Comparable(comparable);
+			}
+			return compare_Unknown(value1);
+		}
+
+		private boolean compare_Collection(Collection< ? > collection) {
+			for (Object value1 : collection) {
+				if (compare(value1)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_ObjectArray(Object[] array) {
+			for (Object value1 : array) {
+				if (compare(value1)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		private boolean compare_PrimitiveArray(Class< ? > type,
+				Object primarray) {
+			if (Integer.TYPE.isAssignableFrom(type)) {
+				int[] array = (int[]) primarray;
+				for (int value1 : array) {
+					if (compare_Long(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Long.TYPE.isAssignableFrom(type)) {
+				long[] array = (long[]) primarray;
+				for (long value1 : array) {
+					if (compare_Long(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Byte.TYPE.isAssignableFrom(type)) {
+				byte[] array = (byte[]) primarray;
+				for (byte value1 : array) {
+					if (compare_Long(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Short.TYPE.isAssignableFrom(type)) {
+				short[] array = (short[]) primarray;
+				for (short value1 : array) {
+					if (compare_Long(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Character.TYPE.isAssignableFrom(type)) {
+				char[] array = (char[]) primarray;
+				for (char value1 : array) {
+					if (compare_Character(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Float.TYPE.isAssignableFrom(type)) {
+				float[] array = (float[]) primarray;
+				for (float value1 : array) {
+					if (compare_Float(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Double.TYPE.isAssignableFrom(type)) {
+				double[] array = (double[]) primarray;
+				for (double value1 : array) {
+					if (compare_Double(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (Boolean.TYPE.isAssignableFrom(type)) {
+				boolean[] array = (boolean[]) primarray;
+				for (boolean value1 : array) {
+					if (compare_Boolean(value1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			return false;
+		}
+
+		boolean compare_String(String string) {
+			return false;
+		}
+
+		boolean compare_Version(Version value1) {
+			return false;
+		}
+
+		boolean compare_Comparable(Comparable<Object> value1) {
+			return false;
+		}
+
+		boolean compare_Unknown(Object value1) {
+			return false;
+		}
+
+		boolean compare_Boolean(boolean boolval) {
+			return false;
+		}
+
+		boolean compare_Character(char charval) {
+			return false;
+		}
+
+		boolean compare_Double(double doubleval) {
+			return false;
+		}
+
+		boolean compare_Float(float floatval) {
+			return false;
+		}
+
+		boolean compare_Long(long longval) {
+			return false;
+		}
+
+		/**
+		 * Encode the value string such that '(', '*', ')' and '\' are escaped.
+		 * 
+		 * @param value unencoded value string.
+		 */
+		static StringBuilder encodeValue(StringBuilder sb, String value) {
+			for (int i = 0, len = value.length(); i < len; i++) {
+				char c = value.charAt(i);
+				switch (c) {
+					case '(' :
+					case '*' :
+					case ')' :
+					case '\\' :
+						sb.append('\\');
+						// FALL-THROUGH
+					default :
+						sb.append(c);
+						break;
+				}
+			}
+			return sb;
+		}
+	}
+
+	static final class Present extends Item {
+		Present(String attr) {
+			super(attr);
+		}
+
+		@Override
+		boolean matches0(Map<String, ? > map) {
+			return map.get(attr) != null;
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			return sb.append('(')
+					.append(attr)
+					.append('=')
+					.append('*')
+					.append(')');
+		}
+	}
+
+	static final class Substring extends Item {
+		final String[] substrings;
+
+		Substring(String attr, String[] substrings) {
+			super(attr);
+			this.substrings = substrings;
+		}
+
+		@Override
+		boolean compare_String(String string) {
+			int pos = 0;
+			for (int i = 0, size = substrings.length; i < size; i++) {
+				String substr = substrings[i];
+				if (i + 1 < size) /* if this is not that last substr */ {
+					if (substr == null) /* * */ {
+						String substr2 = substrings[i + 1];
+						if (substr2 == null) /* ** */
+							continue; /* ignore first star */
+						/* xxx */
+						int index = string.indexOf(substr2, pos);
+						if (index == -1) {
+							return false;
+						}
+						pos = index + substr2.length();
+						if (i + 2 < size) // if there are more
+							// substrings, increment
+							// over the string we just
+							// matched; otherwise need
+							// to do the last substr
+							// check
+							i++;
+					} else /* xxx */ {
+						int len = substr.length();
+						if (string.regionMatches(pos, substr, 0, len)) {
+							pos += len;
+						} else {
+							return false;
+						}
+					}
+				} else /* last substr */ {
+					if (substr == null) /* * */ {
+						return true;
+					}
+					/* xxx */
+					return string.endsWith(substr);
+				}
+			}
+			return true;
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append(attr).append('=');
+			for (String substr : substrings) {
+				if (substr == null) /* * */ {
+					sb.append('*');
+				} else /* xxx */ {
+					encodeValue(sb, substr);
+				}
+			}
+			return sb.append(')');
+		}
+	}
+
+	static class Equal extends Item {
+		final String value;
+		private Object	cached;
+
+		Equal(String attr, String value) {
+			super(attr);
+			this.value = value;
+		}
+		
+		private <T> T convert(Class<T> type, Function<String, ? extends T> converter) {
+			@SuppressWarnings("unchecked")
+			T converted = (T) cached;
+			if ((converted != null) && type.isInstance(converted)) {
+				return converted;
+			}
+			cached = converted = converter.apply(value.trim());
+			return converted;
+		}
+
+		boolean comparison(int compare) {
+			return compare == 0;
+		}
+
+		@Override
+		boolean compare_String(String string) {
+			return comparison((string == value) ? 0 : string.compareTo(value));
+		}
+
+		@Override
+		boolean compare_Version(Version value1) {
+			try {
+				Version version2 = convert(Version.class, Version::valueOf);
+				return comparison(value1.compareTo(version2));
+			} catch (Exception e) {
+				// if the valueOf or compareTo method throws an exception
+				return false;
+			}
+		}
+
+		@Override
+		boolean compare_Boolean(boolean boolval) {
+			boolean boolval2 = convert(Boolean.class, Boolean::valueOf).booleanValue();
+			return comparison(Boolean.compare(boolval, boolval2));
+		}
+
+		@Override
+		boolean compare_Character(char charval) {
+			char charval2;
+			try {
+				charval2 = value.charAt(0);
+			} catch (IndexOutOfBoundsException e) {
+				return false;
+			}
+			return comparison(Character.compare(charval, charval2));
+		}
+
+		@Override
+		boolean compare_Double(double doubleval) {
+			double doubleval2;
+			try {
+				doubleval2 = convert(Double.class, Double::valueOf).doubleValue();
+			} catch (IllegalArgumentException e) {
+				return false;
+			}
+			return comparison(Double.compare(doubleval, doubleval2));
+		}
+
+		@Override
+		boolean compare_Float(float floatval) {
+			float floatval2;
+			try {
+				floatval2 = convert(Float.class, Float::valueOf).floatValue();
+			} catch (IllegalArgumentException e) {
+				return false;
+			}
+			return comparison(Float.compare(floatval, floatval2));
+		}
+
+		@Override
+		boolean compare_Long(long longval) {
+			long longval2;
+			try {
+				longval2 = convert(Long.class, Long::valueOf).longValue();
+			} catch (IllegalArgumentException e) {
+				return false;
+			}
+			return comparison(Long.compare(longval, longval2));
+		}
+
+		@Override
+		boolean compare_Comparable(Comparable<Object> value1) {
+			Object value2 = valueOf(value1.getClass());
+			if (value2 == null) {
+				return false;
+			}
+			try {
+				return comparison(value1.compareTo(value2));
+			} catch (Exception e) {
+				// if the compareTo method throws an exception; return false
+				return false;
+			}
+		}
+
+		@Override
+		boolean compare_Unknown(Object value1) {
+			Object value2 = valueOf(value1.getClass());
+			if (value2 == null) {
+				return false;
+			}
+			try {
+				return value1.equals(value2);
+			} catch (Exception e) {
+				// if the equals method throws an exception; return false
+				return false;
+			}
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append(attr).append('=');
+			return encodeValue(sb, value).append(')');
+		}
+
+		Object valueOf(Class< ? > target) {
+			do {
+				Method method;
+				try {
+					method = target.getMethod("valueOf", String.class);
+				} catch (NoSuchMethodException e) {
+					break;
+				}
+				if (Modifier.isStatic(method.getModifiers())
+						&& target.isAssignableFrom(method.getReturnType())) {
+					setAccessible(method);
+					try {
+						return method.invoke(null, value.trim());
+					} catch (Error e) {
+						throw e;
+					} catch (Throwable e) {
+						return null;
+					}
+				}
+			} while (false);
+
+			do {
+				Constructor< ? > constructor;
+				try {
+					constructor = target.getConstructor(String.class);
+				} catch (NoSuchMethodException e) {
+					break;
+				}
+				setAccessible(constructor);
+				try {
+					return constructor.newInstance(value.trim());
+				} catch (Error e) {
+					throw e;
+				} catch (Throwable e) {
+					return null;
+				}
+			} while (false);
+
+			return null;
+		}
+
+		private static void setAccessible(AccessibleObject accessible) {
+			if (!accessible.isAccessible()) {
+				AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+					accessible.setAccessible(true);
+					return null;
+				});
+			}
+		}
+	}
+
+	static final class LessEqual extends Equal {
+		LessEqual(String attr, String value) {
+			super(attr, value);
+		}
+
+		@Override
+		boolean comparison(int compare) {
+			return compare <= 0;
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append(attr).append('<').append('=');
+			return encodeValue(sb, value).append(')');
+		}
+	}
+
+	static final class GreaterEqual extends Equal {
+		GreaterEqual(String attr, String value) {
+			super(attr, value);
+		}
+
+		@Override
+		boolean comparison(int compare) {
+			return compare >= 0;
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append(attr).append('>').append('=');
+			return encodeValue(sb, value).append(')');
+		}
+	}
+
+	static final class Approx extends Equal {
+		final String approx;
+
+		Approx(String attr, String value) {
+			super(attr, value);
+			this.approx = approxString(value);
+		}
+
+		@Override
+		boolean compare_String(String string) {
+			string = approxString(string);
+			return string.equalsIgnoreCase(approx);
+		}
+
+		@Override
+		boolean compare_Character(char charval) {
+			char charval2;
+			try {
+				charval2 = approx.charAt(0);
+			} catch (IndexOutOfBoundsException e) {
+				return false;
+			}
+			return (charval == charval2)
+					|| (Character.toUpperCase(charval) == Character
+							.toUpperCase(charval2))
+					|| (Character.toLowerCase(charval) == Character
+							.toLowerCase(charval2));
+		}
+
+		@Override
+		StringBuilder normalize(StringBuilder sb) {
+			sb.append('(').append(attr).append('~').append('=');
+			return encodeValue(sb, approx).append(')');
+		}
+
+		/**
+		 * Map a string for an APPROX (~=) comparison. This implementation
+		 * removes white spaces. This is the minimum implementation allowed by
+		 * the OSGi spec.
+		 * 
+		 * @param input Input string.
+		 * @return String ready for APPROX comparison.
+		 */
+		static String approxString(String input) {
+			boolean changed = false;
+			char[] output = input.toCharArray();
+			int cursor = 0;
+			for (char c : output) {
+				if (Character.isWhitespace(c)) {
+					changed = true;
+					continue;
+				}
+
+				output[cursor] = c;
+				cursor++;
+			}
+
+			return changed ? new String(output, 0, cursor) : input;
+		}
+	}
+
+	/**
+	 * Parser class for OSGi filter strings. This class parses the complete
+	 * filter string and builds a tree of FilterImpl objects rooted at the
+	 * parent.
+	 */
+	static private final class Parser {
+		private final String	filterstring;
+		private final char[]	filterChars;
+		private int				pos;
+
+		Parser(String filterstring) {
+			this.filterstring = filterstring;
+			filterChars = filterstring.toCharArray();
+			pos = 0;
+		}
+
+		FilterImpl parse() throws InvalidSyntaxException {
+			FilterImpl filter;
+			try {
+				filter = parse_filter();
+			} catch (ArrayIndexOutOfBoundsException e) {
+				throw new InvalidSyntaxException("Filter ended abruptly",
+						filterstring, e);
+			}
+
+			if (pos != filterChars.length) {
+				throw new InvalidSyntaxException(
+						"Extraneous trailing characters: "
+								+ filterstring.substring(pos),
+						filterstring);
+			}
+			return filter;
+		}
+
+		private FilterImpl parse_filter() throws InvalidSyntaxException {
+			FilterImpl filter;
+			skipWhiteSpace();
+
+			if (filterChars[pos] != '(') {
+				throw new InvalidSyntaxException(
+						"Missing '(': " + filterstring.substring(pos),
+						filterstring);
+			}
+
+			pos++;
+
+			filter = parse_filtercomp();
+
+			skipWhiteSpace();
+
+			if (filterChars[pos] != ')') {
+				throw new InvalidSyntaxException(
+						"Missing ')': " + filterstring.substring(pos),
+						filterstring);
+			}
+
+			pos++;
+
+			skipWhiteSpace();
+
+			return filter;
+		}
+
+		private FilterImpl parse_filtercomp() throws InvalidSyntaxException {
+			skipWhiteSpace();
+
+			char c = filterChars[pos];
+
+			switch (c) {
+				case '&' : {
+					pos++;
+					return parse_and();
+				}
+				case '|' : {
+					pos++;
+					return parse_or();
+				}
+				case '!' : {
+					pos++;
+					return parse_not();
+				}
+			}
+			return parse_item();
+		}
+
+		private FilterImpl parse_and() throws InvalidSyntaxException {
+			int lookahead = pos;
+			skipWhiteSpace();
+
+			if (filterChars[pos] != '(') {
+				pos = lookahead - 1;
+				return parse_item();
+			}
+
+			List<FilterImpl> operands = new ArrayList<>(10);
+
+			while (filterChars[pos] == '(') {
+				FilterImpl child = parse_filter();
+				operands.add(child);
+			}
+
+			return new FilterImpl.And(operands.toArray(new FilterImpl[0]));
+		}
+
+		private FilterImpl parse_or() throws InvalidSyntaxException {
+			int lookahead = pos;
+			skipWhiteSpace();
+
+			if (filterChars[pos] != '(') {
+				pos = lookahead - 1;
+				return parse_item();
+			}
+
+			List<FilterImpl> operands = new ArrayList<>(10);
+
+			while (filterChars[pos] == '(') {
+				FilterImpl child = parse_filter();
+				operands.add(child);
+			}
+
+			return new FilterImpl.Or(operands.toArray(new FilterImpl[0]));
+		}
+
+		private FilterImpl parse_not() throws InvalidSyntaxException {
+			int lookahead = pos;
+			skipWhiteSpace();
+
+			if (filterChars[pos] != '(') {
+				pos = lookahead - 1;
+				return parse_item();
+			}
+
+			FilterImpl child = parse_filter();
+
+			return new FilterImpl.Not(child);
+		}
+
+		private FilterImpl parse_item() throws InvalidSyntaxException {
+			String attr = parse_attr();
+
+			skipWhiteSpace();
+
+			switch (filterChars[pos]) {
+				case '~' : {
+					if (filterChars[pos + 1] == '=') {
+						pos += 2;
+						return new FilterImpl.Approx(attr, parse_value());
+					}
+					break;
+				}
+				case '>' : {
+					if (filterChars[pos + 1] == '=') {
+						pos += 2;
+						return new FilterImpl.GreaterEqual(attr, parse_value());
+					}
+					break;
+				}
+				case '<' : {
+					if (filterChars[pos + 1] == '=') {
+						pos += 2;
+						return new FilterImpl.LessEqual(attr, parse_value());
+					}
+					break;
+				}
+				case '=' : {
+					if (filterChars[pos + 1] == '*') {
+						int oldpos = pos;
+						pos += 2;
+						skipWhiteSpace();
+						if (filterChars[pos] == ')') {
+							return new FilterImpl.Present(attr);
+						}
+						pos = oldpos;
+					}
+
+					pos++;
+					String[] substrings = parse_substring();
+
+					int length = substrings.length;
+					if (length == 0) {
+						return new FilterImpl.Equal(attr, "");
+					}
+					if (length == 1) {
+						String single = substrings[0];
+						if (single != null) {
+							return new FilterImpl.Equal(attr, single);
+						}
+					}
+					return new FilterImpl.Substring(attr, substrings);
+				}
+			}
+
+			throw new InvalidSyntaxException(
+					"Invalid operator: " + filterstring.substring(pos),
+					filterstring);
+		}
+
+		private String parse_attr() throws InvalidSyntaxException {
+			skipWhiteSpace();
+
+			int begin = pos;
+			int end = pos;
+
+			char c = filterChars[pos];
+
+			while (c != '~' && c != '<' && c != '>' && c != '=' && c != '('
+					&& c != ')') {
+				pos++;
+
+				if (!Character.isWhitespace(c)) {
+					end = pos;
+				}
+
+				c = filterChars[pos];
+			}
+
+			int length = end - begin;
+
+			if (length == 0) {
+				throw new InvalidSyntaxException(
+						"Missing attr: " + filterstring.substring(pos),
+						filterstring);
+			}
+
+			return new String(filterChars, begin, length);
+		}
+
+		private String parse_value() throws InvalidSyntaxException {
+			StringBuilder sb = new StringBuilder(filterChars.length - pos);
+
+			parseloop: while (true) {
+				char c = filterChars[pos];
+
+				switch (c) {
+					case ')' : {
+						break parseloop;
+					}
+
+					case '(' : {
+						throw new InvalidSyntaxException(
+								"Invalid value: " + filterstring.substring(pos),
+								filterstring);
+					}
+
+					case '\\' : {
+						pos++;
+						c = filterChars[pos];
+						/* fall through into default */
+					}
+
+					default : {
+						sb.append(c);
+						pos++;
+						break;
+					}
+				}
+			}
+
+			if (sb.length() == 0) {
+				throw new InvalidSyntaxException(
+						"Missing value: " + filterstring.substring(pos),
+						filterstring);
+			}
+
+			return sb.toString();
+		}
+
+		private String[] parse_substring() throws InvalidSyntaxException {
+			StringBuilder sb = new StringBuilder(filterChars.length - pos);
+
+			List<String> operands = new ArrayList<>(10);
+
+			parseloop: while (true) {
+				char c = filterChars[pos];
+
+				switch (c) {
+					case ')' : {
+						if (sb.length() > 0) {
+							operands.add(sb.toString());
+						}
+
+						break parseloop;
+					}
+
+					case '(' : {
+						throw new InvalidSyntaxException(
+								"Invalid value: " + filterstring.substring(pos),
+								filterstring);
+					}
+
+					case '*' : {
+						if (sb.length() > 0) {
+							operands.add(sb.toString());
+						}
+
+						sb.setLength(0);
+
+						operands.add(null);
+						pos++;
+
+						break;
+					}
+
+					case '\\' : {
+						pos++;
+						c = filterChars[pos];
+						/* fall through into default */
+					}
+
+					default : {
+						sb.append(c);
+						pos++;
+						break;
+					}
+				}
+			}
+
+			return operands.toArray(new String[0]);
+		}
+
+		private void skipWhiteSpace() {
+			for (int length = filterChars.length; (pos < length)
+					&& Character.isWhitespace(filterChars[pos]);) {
+				pos++;
+			}
+		}
+	}
+
+	/**
+	 * This Map is used for key lookup during filter evaluation. This Map
+	 * implementation only supports the get operation using a String key as no
+	 * other operations are used by the Filter implementation.
+	 */
+	private static class DictionaryMap extends AbstractMap<String,Object>
+			implements Map<String,Object> {
+		static Map<String, ? > asMap(Dictionary<String, ? > dictionary) {
+			if (dictionary instanceof Map) {
+				@SuppressWarnings("unchecked")
+				Map<String, ? > coerced = (Map<String, ? >) dictionary;
+				return coerced;
+			}
+			return new DictionaryMap(dictionary);
+		}
+
+		private final Dictionary<String, ? > dictionary;
+
+		DictionaryMap(Dictionary<String, ? > dictionary) {
+			this.dictionary = requireNonNull(dictionary);
+		}
+
+		@Override
+		public Object get(Object key) {
+			return dictionary.get(key);
+		}
+
+		@Override
+		public Set<Entry<String,Object>> entrySet() {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	/**
+	 * This Map is used for case-insensitive key lookup during filter
+	 * evaluation. This Map implementation only supports the get operation using
+	 * a String key as no other operations are used by the Filter
+	 * implementation.
+	 */
+	private static final class CaseInsensitiveMap
+			extends DictionaryMap implements Map<String,Object> {
+		private final String[]					keys;
+
+		/**
+		 * Create a case insensitive map from the specified dictionary.
+		 * 
+		 * @param dictionary
+		 * @throws IllegalArgumentException If {@code dictionary} contains case
+		 *             variants of the same key name.
+		 */
+		CaseInsensitiveMap(Dictionary<String, ? > dictionary) {
+			super(dictionary);
+			List<String> keyList = new ArrayList<>(dictionary.size());
+			for (Enumeration< ? > e = dictionary.keys(); e.hasMoreElements();) {
+				Object k = e.nextElement();
+				if (k instanceof String) {
+					String key = (String) k;
+					for (String i : keyList) {
+						if (key.equalsIgnoreCase(i)) {
+							throw new IllegalArgumentException();
+						}
+					}
+					keyList.add(key);
+				}
+			}
+			this.keys = keyList.toArray(new String[0]);
+		}
+
+		@Override
+		public Object get(Object o) {
+			String k = (String) o;
+			for (String key : keys) {
+				if (key.equalsIgnoreCase(k)) {
+					return super.get(key);
+				}
+			}
+			return null;
+		}
+	}
+
+	/**
+	 * This Map is used for key lookup from a ServiceReference during filter
+	 * evaluation. This Map implementation only supports the get operation using
+	 * a String key as no other operations are used by the Filter
+	 * implementation.
+	 */
+	private static final class ServiceReferenceMap
+			extends AbstractMap<String,Object> implements Map<String,Object> {
+		private final ServiceReference< ? > reference;
+
+		ServiceReferenceMap(ServiceReference< ? > reference) {
+			this.reference = requireNonNull(reference);
+		}
+
+		@Override
+		public Object get(Object key) {
+			return reference.getProperty((String) key);
+		}
+
+		@Override
+		public Set<Entry<String,Object>> entrySet() {
+			throw new UnsupportedOperationException();
+		}
+	}
+}
diff --git a/framework/src/main/java/org/osgi/framework/FrameworkEvent.java b/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
index 84c63f1..9156a79 100644
--- a/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
+++ b/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2004, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2020). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
  * 
  * @Immutable
  * @see FrameworkListener
- * @author $Id: b3072b2d058e70389a52e342ed5f8647b930b8f1 $
+ * @author $Id: bcff0614c20b454723977355f99486ca01ee89ea $
  */
 
 public class FrameworkEvent extends EventObject {
@@ -148,13 +148,13 @@
 
 	/**
 	 * The Framework has stopped and the boot class path has changed.
-	 * 
 	 * <p>
 	 * This event is fired when the Framework has been stopped because of a stop
 	 * operation on the system bundle and a bootclasspath extension bundle has
 	 * been installed or updated. The source of this event is the System Bundle.
 	 * 
 	 * @since 1.5
+	 * @deprecated As of 1.10.
 	 */
 	public final static int	STOPPED_BOOTCLASSPATH_MODIFIED	= 0x00000100;
 
@@ -173,9 +173,9 @@
 	 * The Framework has stopped and the framework requires a new class loader
 	 * to restart.
 	 * <p>
-	 * This event is fired when the Framework has been stopped because of a stop
-	 * operation on the system bundle and the framework requires a new class
-	 * loader to be used to restart. For example, if a framework extension
+	 * This event is fired when the Framework has been stopped because of a
+	 * refresh operation on the system bundle and the framework requires a new
+	 * class loader to be used to restart. For example, if a framework extension
 	 * bundle has been refreshed. The source of this event is the System Bundle.
 	 * 
 	 * @since 1.9
@@ -244,7 +244,6 @@
 	 * <li>{@link #PACKAGES_REFRESHED}</li>
 	 * <li>{@link #STARTLEVEL_CHANGED}</li>
 	 * <li>{@link #STOPPED}</li>
-	 * <li>{@link #STOPPED_BOOTCLASSPATH_MODIFIED}</li>
 	 * <li>{@link #STOPPED_UPDATE}</li>
 	 * <li>{@link #WAIT_TIMEDOUT}</li>
 	 * </ul>
diff --git a/framework/src/main/java/org/osgi/framework/FrameworkUtil.java b/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
index 9f72092..edc8008 100644
--- a/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
+++ b/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2005, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2020). All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,25 +16,28 @@
 
 package org.osgi.framework;
 
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
+import static java.util.Objects.requireNonNull;
+
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.AbstractMap;
+import java.util.AbstractSet;
 import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.ServiceLoader;
 import java.util.Set;
 
 import javax.security.auth.x500.X500Principal;
 
+import org.osgi.framework.connect.FrameworkUtilHelper;
+
 /**
  * Framework Utility class.
  * 
@@ -44,7 +47,7 @@
  * 
  * @since 1.3
  * @ThreadSafe
- * @author $Id: 90d50e4d3f69b659bed23beedab6e54b31b96d76 $
+ * @author $Id: 71423feb17277b685e6d5d7864907e768da8cd0b $
  */
 public class FrameworkUtil {
 	/**
@@ -77,7 +80,7 @@
 	 * @see Filter
 	 */
 	public static Filter createFilter(String filter) throws InvalidSyntaxException {
-		return FilterImpl.newInstance(filter);
+		return FilterImpl.createFilter(filter);
 	}
 
 	/**
@@ -194,1523 +197,68 @@
 	}
 
 	/**
-	 * Return a {@code Bundle} for the specified bundle class. The returned
-	 * {@code Bundle} is the bundle associated with the bundle class loader
-	 * which defined the specified class.
+	 * Return a {@code Bundle} for the specified bundle class loader.
 	 * 
-	 * @param classFromBundle A class defined by a bundle class loader.
+	 * @param bundleClassLoader A bundle class loader.
+	 * @return An Optional containing {@code Bundle} for the specified bundle
+	 *         class loader or an empty Optional if the specified class loader
+	 *         is not associated with a specific bundle.
+	 * @since 1.10
+	 */
+	public static Optional<Bundle> getBundle(ClassLoader bundleClassLoader) {
+		requireNonNull(bundleClassLoader);
+		return Optional
+				.ofNullable((bundleClassLoader instanceof BundleReference)
+						? ((BundleReference) bundleClassLoader).getBundle()
+						: null);
+	}
+
+	/**
+	 * Return a {@code Bundle} for the specified bundle class.
+	 * 
+	 * @param classFromBundle A class defined by a bundle.
 	 * @return A {@code Bundle} for the specified bundle class or {@code null}
-	 *         if the specified class was not defined by a bundle class loader.
+	 *         if the specified class was not defined by a bundle.
 	 * @since 1.5
 	 */
-	public static Bundle getBundle(final Class<?> classFromBundle) {
+	public static Bundle getBundle(Class< ? > classFromBundle) {
 		// We use doPriv since the caller may not have permission
 		// to call getClassLoader.
-		Object cl = AccessController.doPrivileged(new PrivilegedAction<Object>() {
-			@Override
-			public Object run() {
-				return classFromBundle.getClassLoader();
-			}
-		});
+		Optional<ClassLoader> cl = Optional
+				.ofNullable(AccessController.doPrivileged(
+						(PrivilegedAction<ClassLoader>) () -> classFromBundle
+								.getClassLoader()));
 
-		if (cl instanceof BundleReference) {
-			return ((BundleReference) cl).getBundle();
-		}
-		return null;
+		return cl.flatMap(FrameworkUtil::getBundle)
+				.orElseGet(() -> helpers.stream()
+						.map(helper -> helper.getBundle(classFromBundle))
+						.filter(Optional::isPresent)
+						.map(Optional::get)
+						.findFirst()
+						.orElse(null));
 	}
 
-	/**
-	 * RFC 1960-based Filter. Filter objects can be created by calling the
-	 * constructor with the desired filter string. A Filter object can be called
-	 * numerous times to determine if the match argument matches the filter
-	 * string that was used to create the Filter object.
-	 * 
-	 * <p>
-	 * The syntax of a filter string is the string representation of LDAP search
-	 * filters as defined in RFC 1960: <i>A String Representation of LDAP Search
-	 * Filters</i> (available at http://www.ietf.org/rfc/rfc1960.txt). It should
-	 * be noted that RFC 2254: <i>A String Representation of LDAP Search
-	 * Filters</i> (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes
-	 * RFC 1960 but only adds extensible matching and is not applicable for this
-	 * API.
-	 * 
-	 * <p>
-	 * The string representation of an LDAP search filter is defined by the
-	 * following grammar. It uses a prefix format.
-	 * 
-	 * <pre>
-	 *   &lt;filter&gt; ::= '(' &lt;filtercomp&gt; ')'
-	 *   &lt;filtercomp&gt; ::= &lt;and&gt; | &lt;or&gt; | &lt;not&gt; | &lt;item&gt;
-	 *   &lt;and&gt; ::= '&amp;' &lt;filterlist&gt;
-	 *   &lt;or&gt; ::= '|' &lt;filterlist&gt;
-	 *   &lt;not&gt; ::= '!' &lt;filter&gt;
-	 *   &lt;filterlist&gt; ::= &lt;filter&gt; | &lt;filter&gt; &lt;filterlist&gt;
-	 *   &lt;item&gt; ::= &lt;simple&gt; | &lt;present&gt; | &lt;substring&gt;
-	 *   &lt;simple&gt; ::= &lt;attr&gt; &lt;filtertype&gt; &lt;value&gt;
-	 *   &lt;filtertype&gt; ::= &lt;equal&gt; | &lt;approx&gt; | &lt;greater&gt; | &lt;less&gt;
-	 *   &lt;equal&gt; ::= '='
-	 *   &lt;approx&gt; ::= '&tilde;='
-	 *   &lt;greater&gt; ::= '&gt;='
-	 *   &lt;less&gt; ::= '&lt;='
-	 *   &lt;present&gt; ::= &lt;attr&gt; '=*'
-	 *   &lt;substring&gt; ::= &lt;attr&gt; '=' &lt;initial&gt; &lt;any&gt; &lt;final&gt;
-	 *   &lt;initial&gt; ::= NULL | &lt;value&gt;
-	 *   &lt;any&gt; ::= '*' &lt;starval&gt;
-	 *   &lt;starval&gt; ::= NULL | &lt;value&gt; '*' &lt;starval&gt;
-	 *   &lt;final&gt; ::= NULL | &lt;value&gt;
-	 * </pre>
-	 * 
-	 * {@code &lt;attr&gt;} is a string representing an attribute, or key, in
-	 * the properties objects of the registered services. Attribute names are
-	 * not case sensitive; that is cn and CN both refer to the same attribute.
-	 * {@code &lt;value&gt;} is a string representing the value, or part of one,
-	 * of a key in the properties objects of the registered services. If a
-	 * {@code &lt;value&gt;} must contain one of the characters ' {@code *}' or
-	 * '{@code (}' or '{@code )}', these characters should be escaped by
-	 * preceding them with the backslash '{@code \}' character. Note that
-	 * although both the {@code &lt;substring&gt;} and {@code &lt;present&gt;}
-	 * productions can produce the {@code 'attr=*'} construct, this construct is
-	 * used only to denote a presence filter.
-	 * 
-	 * <p>
-	 * Examples of LDAP filters are:
-	 * 
-	 * <pre>
-	 *   &quot;(cn=Babs Jensen)&quot;
-	 *   &quot;(!(cn=Tim Howes))&quot;
-	 *   &quot;(&amp;(&quot; + Constants.OBJECTCLASS + &quot;=Person)(|(sn=Jensen)(cn=Babs J*)))&quot;
-	 *   &quot;(o=univ*of*mich*)&quot;
-	 * </pre>
-	 * 
-	 * <p>
-	 * The approximate match ({@code ~=}) is implementation specific but should
-	 * at least ignore case and white space differences. Optional are codes like
-	 * soundex or other smart "closeness" comparisons.
-	 * 
-	 * <p>
-	 * Comparison of values is not straightforward. Strings are compared
-	 * differently than numbers and it is possible for a key to have multiple
-	 * values. Note that that keys in the match argument must always be strings.
-	 * The comparison is defined by the object type of the key's value. The
-	 * following rules apply for comparison:
-	 * 
-	 * <blockquote>
-	 * <TABLE BORDER=0>
-	 * <TR>
-	 * <TD><b>Property Value Type </b></TD>
-	 * <TD><b>Comparison Type</b></TD>
-	 * </TR>
-	 * <TR>
-	 * <TD>String</TD>
-	 * <TD>String comparison</TD>
-	 * </TR>
-	 * <TR valign=top>
-	 * <TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal</TD>
-	 * <TD>numerical comparison</TD>
-	 * </TR>
-	 * <TR>
-	 * <TD>Character</TD>
-	 * <TD>character comparison</TD>
-	 * </TR>
-	 * <TR>
-	 * <TD>Boolean</TD>
-	 * <TD>equality comparisons only</TD>
-	 * </TR>
-	 * <TR>
-	 * <TD>[] (array)</TD>
-	 * <TD>recursively applied to values</TD>
-	 * </TR>
-	 * <TR>
-	 * <TD>Collection</TD>
-	 * <TD>recursively applied to values</TD>
-	 * </TR>
-	 * </TABLE>
-	 * Note: arrays of primitives are also supported. </blockquote>
-	 * 
-	 * A filter matches a key that has multiple values if it matches at least
-	 * one of those values. For example,
-	 * 
-	 * <pre>
-	 * Dictionary d = new Hashtable();
-	 * d.put(&quot;cn&quot;, new String[] {&quot;a&quot;, &quot;b&quot;, &quot;c&quot;});
-	 * </pre>
-	 * 
-	 * d will match {@code (cn=a)} and also {@code (cn=b)}
-	 * 
-	 * <p>
-	 * A filter component that references a key having an unrecognizable data
-	 * type will evaluate to {@code false} .
-	 */
-	static private final class FilterImpl implements Filter {
-		/* filter operators */
-		private static final int	EQUAL		= 1;
-		private static final int	APPROX		= 2;
-		private static final int	GREATER		= 3;
-		private static final int	LESS		= 4;
-		private static final int	PRESENT		= 5;
-		private static final int	SUBSTRING	= 6;
-		private static final int	AND			= 7;
-		private static final int	OR			= 8;
-		private static final int	NOT			= 9;
-
-		/** filter operation */
-		private final int			op;
-		/** filter attribute or null if operation AND, OR or NOT */
-		private final String		attr;
-		/** filter operands */
-		private final Object		value;
-
-		/* normalized filter string for Filter object */
-		private transient String	filterString;
-
-		/**
-		 * Constructs a {@link FilterImpl} object. This filter object may be
-		 * used to match a {@link ServiceReference} or a Dictionary.
-		 * 
-		 * <p>
-		 * If the filter cannot be parsed, an {@link InvalidSyntaxException}
-		 * will be thrown with a human readable message where the filter became
-		 * unparsable.
-		 * 
-		 * @param filterString the filter string.
-		 * @throws InvalidSyntaxException If the filter parameter contains an
-		 *         invalid filter string that cannot be parsed.
-		 */
-		static FilterImpl newInstance(String filterString) throws InvalidSyntaxException {
-			return new Parser(filterString).parse();
-		}
-
-		FilterImpl(int operation, String attr, Object value) {
-			this.op = operation;
-			this.attr = attr;
-			this.value = value;
-			filterString = null;
-		}
-
-		/**
-		 * Filter using a service's properties.
-		 * <p>
-		 * This {@code Filter} is executed using the keys and values of the
-		 * referenced service's properties. The keys are looked up in a case
-		 * insensitive manner.
-		 * 
-		 * @param reference The reference to the service whose properties are
-		 *        used in the match.
-		 * @return {@code true} if the service's properties match this
-		 *         {@code Filter}; {@code false} otherwise.
-		 */
-		@Override
-		public boolean match(ServiceReference<?> reference) {
-			return matches(new ServiceReferenceMap(reference));
-		}
-
-		/**
-		 * Filter using a {@code Dictionary} with case insensitive key lookup.
-		 * This {@code Filter} is executed using the specified
-		 * {@code Dictionary}'s keys and values. The keys are looked up in a
-		 * case insensitive manner.
-		 * 
-		 * @param dictionary The {@code Dictionary} whose key/value pairs are
-		 *        used in the match.
-		 * @return {@code true} if the {@code Dictionary}'s values match this
-		 *         filter; {@code false} otherwise.
-		 * @throws IllegalArgumentException If {@code dictionary} contains case
-		 *         variants of the same key name.
-		 */
-		@Override
-		public boolean match(Dictionary<String, ?> dictionary) {
-			return matches(new CaseInsensitiveMap(dictionary));
-		}
-
-		/**
-		 * Filter using a {@code Dictionary}. This {@code Filter} is executed
-		 * using the specified {@code Dictionary}'s keys and values. The keys
-		 * are looked up in a normal manner respecting case.
-		 * 
-		 * @param dictionary The {@code Dictionary} whose key/value pairs are
-		 *        used in the match.
-		 * @return {@code true} if the {@code Dictionary}'s values match this
-		 *         filter; {@code false} otherwise.
-		 * @since 1.3
-		 */
-		@Override
-		public boolean matchCase(Dictionary<String, ?> dictionary) {
-			switch (op) {
-				case AND : {
-					FilterImpl[] filters = (FilterImpl[]) value;
-					for (FilterImpl f : filters) {
-						if (!f.matchCase(dictionary)) {
-							return false;
-						}
-					}
-					return true;
-				}
-
-				case OR : {
-					FilterImpl[] filters = (FilterImpl[]) value;
-					for (FilterImpl f : filters) {
-						if (f.matchCase(dictionary)) {
-							return true;
-						}
-					}
-					return false;
-				}
-
-				case NOT : {
-					FilterImpl filter = (FilterImpl) value;
-					return !filter.matchCase(dictionary);
-				}
-
-				case SUBSTRING :
-				case EQUAL :
-				case GREATER :
-				case LESS :
-				case APPROX : {
-					Object prop = (dictionary == null) ? null : dictionary.get(attr);
-					return compare(op, prop, value);
-				}
-
-				case PRESENT : {
-					Object prop = (dictionary == null) ? null : dictionary.get(attr);
-					return prop != null;
-				}
-			}
-
-			return false;
-		}
-
-		/**
-		 * Filter using a {@code Map}. This {@code Filter} is executed using the
-		 * specified {@code Map}'s keys and values. The keys are looked up in a
-		 * normal manner respecting case.
-		 * 
-		 * @param map The {@code Map} whose key/value pairs are used in the
-		 *        match. Maps with {@code null} key or values are not supported.
-		 *        A {@code null} value is considered not present to the filter.
-		 * @return {@code true} if the {@code Map}'s values match this filter;
-		 *         {@code false} otherwise.
-		 * @since 1.6
-		 */
-		@Override
-		public boolean matches(Map<String, ?> map) {
-			switch (op) {
-				case AND : {
-					FilterImpl[] filters = (FilterImpl[]) value;
-					for (FilterImpl f : filters) {
-						if (!f.matches(map)) {
-							return false;
-						}
-					}
-					return true;
-				}
-
-				case OR : {
-					FilterImpl[] filters = (FilterImpl[]) value;
-					for (FilterImpl f : filters) {
-						if (f.matches(map)) {
-							return true;
-						}
-					}
-					return false;
-				}
-
-				case NOT : {
-					FilterImpl filter = (FilterImpl) value;
-					return !filter.matches(map);
-				}
-
-				case SUBSTRING :
-				case EQUAL :
-				case GREATER :
-				case LESS :
-				case APPROX : {
-					Object prop = (map == null) ? null : map.get(attr);
-					return compare(op, prop, value);
-				}
-
-				case PRESENT : {
-					Object prop = (map == null) ? null : map.get(attr);
-					return prop != null;
-				}
-			}
-
-			return false;
-		}
-
-		/**
-		 * Returns this {@code Filter}'s filter string.
-		 * <p>
-		 * The filter string is normalized by removing whitespace which does not
-		 * affect the meaning of the filter.
-		 * 
-		 * @return This {@code Filter}'s filter string.
-		 */
-		@Override
-		public String toString() {
-			String result = filterString;
-			if (result == null) {
-				filterString = result = normalize().toString();
-			}
-			return result;
-		}
-
-		/**
-		 * Returns this {@code Filter}'s normalized filter string.
-		 * <p>
-		 * The filter string is normalized by removing whitespace which does not
-		 * affect the meaning of the filter.
-		 * 
-		 * @return This {@code Filter}'s filter string.
-		 */
-		private StringBuilder normalize() {
-			StringBuilder sb = new StringBuilder();
-			sb.append('(');
-
-			switch (op) {
-				case AND : {
-					sb.append('&');
-
-					FilterImpl[] filters = (FilterImpl[]) value;
-					for (FilterImpl f : filters) {
-						sb.append(f.normalize());
-					}
-
-					break;
-				}
-
-				case OR : {
-					sb.append('|');
-
-					FilterImpl[] filters = (FilterImpl[]) value;
-					for (FilterImpl f : filters) {
-						sb.append(f.normalize());
-					}
-
-					break;
-				}
-
-				case NOT : {
-					sb.append('!');
-					FilterImpl filter = (FilterImpl) value;
-					sb.append(filter.normalize());
-
-					break;
-				}
-
-				case SUBSTRING : {
-					sb.append(attr);
-					sb.append('=');
-
-					String[] substrings = (String[]) value;
-
-					for (String substr : substrings) {
-						if (substr == null) /* * */{
-							sb.append('*');
-						} else /* xxx */{
-							sb.append(encodeValue(substr));
-						}
-					}
-
-					break;
-				}
-				case EQUAL : {
-					sb.append(attr);
-					sb.append('=');
-					sb.append(encodeValue((String) value));
-
-					break;
-				}
-				case GREATER : {
-					sb.append(attr);
-					sb.append(">=");
-					sb.append(encodeValue((String) value));
-
-					break;
-				}
-				case LESS : {
-					sb.append(attr);
-					sb.append("<=");
-					sb.append(encodeValue((String) value));
-
-					break;
-				}
-				case APPROX : {
-					sb.append(attr);
-					sb.append("~=");
-					sb.append(encodeValue(approxString((String) value)));
-
-					break;
-				}
-
-				case PRESENT : {
-					sb.append(attr);
-					sb.append("=*");
-
-					break;
-				}
-			}
-
-			sb.append(')');
-
-			return sb;
-		}
-
-		/**
-		 * Compares this {@code Filter} to another {@code Filter}.
-		 * 
-		 * <p>
-		 * This implementation returns the result of calling
-		 * {@code this.toString().equals(obj.toString()}.
-		 * 
-		 * @param obj The object to compare against this {@code Filter}.
-		 * @return If the other object is a {@code Filter} object, then returns
-		 *         the result of calling
-		 *         {@code this.toString().equals(obj.toString()}; {@code false}
-		 *         otherwise.
-		 */
-		@Override
-		public boolean equals(Object obj) {
-			if (obj == this) {
-				return true;
-			}
-
-			if (!(obj instanceof Filter)) {
-				return false;
-			}
-
-			return this.toString().equals(obj.toString());
-		}
-
-		/**
-		 * Returns the hashCode for this {@code Filter}.
-		 * 
-		 * <p>
-		 * This implementation returns the result of calling
-		 * {@code this.toString().hashCode()}.
-		 * 
-		 * @return The hashCode of this {@code Filter}.
-		 */
-		@Override
-		public int hashCode() {
-			return this.toString().hashCode();
-		}
-
-		/**
-		 * Encode the value string such that '(', '*', ')' and '\' are escaped.
-		 * 
-		 * @param value unencoded value string.
-		 * @return encoded value string.
-		 */
-		private static String encodeValue(String value) {
-			boolean encoded = false;
-			int inlen = value.length();
-			int outlen = inlen << 1; /* inlen 2 */
-
-			char[] output = new char[outlen];
-			value.getChars(0, inlen, output, inlen);
-
-			int cursor = 0;
-			for (int i = inlen; i < outlen; i++) {
-				char c = output[i];
-
-				switch (c) {
-					case '(' :
-					case '*' :
-					case ')' :
-					case '\\' : {
-						output[cursor] = '\\';
-						cursor++;
-						encoded = true;
-
-						break;
-					}
-				}
-
-				output[cursor] = c;
-				cursor++;
-			}
-
-			return encoded ? new String(output, 0, cursor) : value;
-		}
-
-		private boolean compare(int operation, Object value1, Object value2) {
-			if (value1 == null) {
-				return false;
-			}
-			if (value1 instanceof String) {
-				return compare_String(operation, (String) value1, value2);
-			}
-			if (value1 instanceof Version) {
-				return compare_Version(operation, (Version) value1, value2);
-			}
-
-			Class<?> clazz = value1.getClass();
-			if (clazz.isArray()) {
-				Class<?> type = clazz.getComponentType();
-				if (type.isPrimitive()) {
-					return compare_PrimitiveArray(operation, type, value1, value2);
-				}
-				return compare_ObjectArray(operation, (Object[]) value1, value2);
-			}
-			if (value1 instanceof Collection<?>) {
-				return compare_Collection(operation, (Collection<?>) value1, value2);
-			}
-			if (value1 instanceof Integer) {
-				return compare_Integer(operation, ((Integer) value1).intValue(), value2);
-			}
-			if (value1 instanceof Long) {
-				return compare_Long(operation, ((Long) value1).longValue(), value2);
-			}
-			if (value1 instanceof Byte) {
-				return compare_Byte(operation, ((Byte) value1).byteValue(), value2);
-			}
-			if (value1 instanceof Short) {
-				return compare_Short(operation, ((Short) value1).shortValue(), value2);
-			}
-			if (value1 instanceof Character) {
-				return compare_Character(operation, ((Character) value1).charValue(), value2);
-			}
-			if (value1 instanceof Float) {
-				return compare_Float(operation, ((Float) value1).floatValue(), value2);
-			}
-			if (value1 instanceof Double) {
-				return compare_Double(operation, ((Double) value1).doubleValue(), value2);
-			}
-			if (value1 instanceof Boolean) {
-				return compare_Boolean(operation, ((Boolean) value1).booleanValue(), value2);
-			}
-			if (value1 instanceof Comparable<?>) {
-				@SuppressWarnings("unchecked")
-				Comparable<Object> comparable = (Comparable<Object>) value1;
-				return compare_Comparable(operation, comparable, value2);
-			}
-			return compare_Unknown(operation, value1, value2);
-		}
-
-		private boolean compare_Collection(int operation, Collection<?> collection, Object value2) {
-			for (Object value1 : collection) {
-				if (compare(operation, value1, value2)) {
-					return true;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_ObjectArray(int operation, Object[] array, Object value2) {
-			for (Object value1 : array) {
-				if (compare(operation, value1, value2)) {
-					return true;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_PrimitiveArray(int operation, Class<?> type, Object primarray, Object value2) {
-			if (Integer.TYPE.isAssignableFrom(type)) {
-				int[] array = (int[]) primarray;
-				for (int value1 : array) {
-					if (compare_Integer(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			if (Long.TYPE.isAssignableFrom(type)) {
-				long[] array = (long[]) primarray;
-				for (long value1 : array) {
-					if (compare_Long(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			if (Byte.TYPE.isAssignableFrom(type)) {
-				byte[] array = (byte[]) primarray;
-				for (byte value1 : array) {
-					if (compare_Byte(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			if (Short.TYPE.isAssignableFrom(type)) {
-				short[] array = (short[]) primarray;
-				for (short value1 : array) {
-					if (compare_Short(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			if (Character.TYPE.isAssignableFrom(type)) {
-				char[] array = (char[]) primarray;
-				for (char value1 : array) {
-					if (compare_Character(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			if (Float.TYPE.isAssignableFrom(type)) {
-				float[] array = (float[]) primarray;
-				for (float value1 : array) {
-					if (compare_Float(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			if (Double.TYPE.isAssignableFrom(type)) {
-				double[] array = (double[]) primarray;
-				for (double value1 : array) {
-					if (compare_Double(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			if (Boolean.TYPE.isAssignableFrom(type)) {
-				boolean[] array = (boolean[]) primarray;
-				for (boolean value1 : array) {
-					if (compare_Boolean(operation, value1, value2)) {
-						return true;
-					}
-				}
-				return false;
-			}
-			return false;
-		}
-
-		private boolean compare_String(int operation, String string, Object value2) {
-			switch (operation) {
-				case SUBSTRING : {
-					String[] substrings = (String[]) value2;
-					int pos = 0;
-					for (int i = 0, size = substrings.length; i < size; i++) {
-						String substr = substrings[i];
-
-						if (i + 1 < size) /* if this is not that last substr */{
-							if (substr == null) /* * */{
-								String substr2 = substrings[i + 1];
-
-								if (substr2 == null) /* ** */
-									continue; /* ignore first star */
-								/* xxx */
-								int index = string.indexOf(substr2, pos);
-								if (index == -1) {
-									return false;
-								}
-
-								pos = index + substr2.length();
-								if (i + 2 < size) // if there are more
-									// substrings, increment
-									// over the string we just
-									// matched; otherwise need
-									// to do the last substr
-									// check
-									i++;
-							} else /* xxx */{
-								int len = substr.length();
-								if (string.regionMatches(pos, substr, 0, len)) {
-									pos += len;
-								} else {
-									return false;
-								}
-							}
-						} else /* last substr */{
-							if (substr == null) /* * */{
-								return true;
-							}
-							/* xxx */
-							return string.endsWith(substr);
-						}
-					}
-
-					return true;
-				}
-				case EQUAL : {
-					return string.equals(value2);
-				}
-				case APPROX : {
-					string = approxString(string);
-					String string2 = approxString((String) value2);
-
-					return string.equalsIgnoreCase(string2);
-				}
-				case GREATER : {
-					return string.compareTo((String) value2) >= 0;
-				}
-				case LESS : {
-					return string.compareTo((String) value2) <= 0;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Integer(int operation, int intval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			int intval2;
+	private final static List<FrameworkUtilHelper> helpers;
+	static {
+		List<FrameworkUtilHelper> l = new ArrayList<>();
+		try {
+			ServiceLoader<FrameworkUtilHelper> helperLoader = AccessController
+					.doPrivileged(
+							(PrivilegedAction<ServiceLoader<FrameworkUtilHelper>>) () -> ServiceLoader
+									.load(FrameworkUtilHelper.class,
+											FrameworkUtilHelper.class
+													.getClassLoader()));
+			helperLoader.forEach(l::add);
+		} catch (Throwable error) {
+			// try hard not to fail static <clinit>
 			try {
-				intval2 = Integer.parseInt(((String) value2).trim());
-			} catch (IllegalArgumentException e) {
-				return false;
-			}
-			switch (operation) {
-				case APPROX :
-				case EQUAL : {
-					return intval == intval2;
-				}
-				case GREATER : {
-					return intval >= intval2;
-				}
-				case LESS : {
-					return intval <= intval2;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Long(int operation, long longval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			long longval2;
-			try {
-				longval2 = Long.parseLong(((String) value2).trim());
-			} catch (IllegalArgumentException e) {
-				return false;
-			}
-
-			switch (operation) {
-				case APPROX :
-				case EQUAL : {
-					return longval == longval2;
-				}
-				case GREATER : {
-					return longval >= longval2;
-				}
-				case LESS : {
-					return longval <= longval2;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Byte(int operation, byte byteval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			byte byteval2;
-			try {
-				byteval2 = Byte.parseByte(((String) value2).trim());
-			} catch (IllegalArgumentException e) {
-				return false;
-			}
-
-			switch (operation) {
-				case APPROX :
-				case EQUAL : {
-					return byteval == byteval2;
-				}
-				case GREATER : {
-					return byteval >= byteval2;
-				}
-				case LESS : {
-					return byteval <= byteval2;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Short(int operation, short shortval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			short shortval2;
-			try {
-				shortval2 = Short.parseShort(((String) value2).trim());
-			} catch (IllegalArgumentException e) {
-				return false;
-			}
-
-			switch (operation) {
-				case APPROX :
-				case EQUAL : {
-					return shortval == shortval2;
-				}
-				case GREATER : {
-					return shortval >= shortval2;
-				}
-				case LESS : {
-					return shortval <= shortval2;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Character(int operation, char charval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			char charval2;
-			try {
-				charval2 = ((String) value2).charAt(0);
-			} catch (IndexOutOfBoundsException e) {
-				return false;
-			}
-
-			switch (operation) {
-				case EQUAL : {
-					return charval == charval2;
-				}
-				case APPROX : {
-					return (charval == charval2) || (Character.toUpperCase(charval) == Character.toUpperCase(charval2)) || (Character.toLowerCase(charval) == Character.toLowerCase(charval2));
-				}
-				case GREATER : {
-					return charval >= charval2;
-				}
-				case LESS : {
-					return charval <= charval2;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Boolean(int operation, boolean boolval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			boolean boolval2 = Boolean.valueOf(((String) value2).trim()).booleanValue();
-			switch (operation) {
-				case APPROX :
-				case EQUAL :
-				case GREATER :
-				case LESS : {
-					return boolval == boolval2;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Float(int operation, float floatval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			float floatval2;
-			try {
-				floatval2 = Float.parseFloat(((String) value2).trim());
-			} catch (IllegalArgumentException e) {
-				return false;
-			}
-
-			switch (operation) {
-				case APPROX :
-				case EQUAL : {
-					return Float.compare(floatval, floatval2) == 0;
-				}
-				case GREATER : {
-					return Float.compare(floatval, floatval2) >= 0;
-				}
-				case LESS : {
-					return Float.compare(floatval, floatval2) <= 0;
-				}
-			}
-			return false;
-		}
-
-		private boolean compare_Double(int operation, double doubleval, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			double doubleval2;
-			try {
-				doubleval2 = Double.parseDouble(((String) value2).trim());
-			} catch (IllegalArgumentException e) {
-				return false;
-			}
-
-			switch (operation) {
-				case APPROX :
-				case EQUAL : {
-					return Double.compare(doubleval, doubleval2) == 0;
-				}
-				case GREATER : {
-					return Double.compare(doubleval, doubleval2) >= 0;
-				}
-				case LESS : {
-					return Double.compare(doubleval, doubleval2) <= 0;
-				}
-			}
-			return false;
-		}
-
-		private static Object valueOf(Class<?> target, String value2) {
-			do {
-				Method method;
-				try {
-					method = target.getMethod("valueOf", String.class);
-				} catch (NoSuchMethodException e) {
-					break;
-				}
-				if (Modifier.isStatic(method.getModifiers()) && target.isAssignableFrom(method.getReturnType())) {
-					setAccessible(method);
-					try {
-						return method.invoke(null, value2.trim());
-					} catch (IllegalAccessException e) {
-						return null;
-					} catch (InvocationTargetException e) {
-						return null;
-					}
-				}
-			} while (false);
-
-			do {
-				Constructor<?> constructor;
-				try {
-					constructor = target.getConstructor(String.class);
-				} catch (NoSuchMethodException e) {
-					break;
-				}
-				setAccessible(constructor);
-				try {
-					return constructor.newInstance(value2.trim());
-				} catch (IllegalAccessException e) {
-					return null;
-				} catch (InvocationTargetException e) {
-					return null;
-				} catch (InstantiationException e) {
-					return null;
-				}
-			} while (false);
-
-			return null;
-		}
-
-		private static void setAccessible(AccessibleObject accessible) {
-			if (!accessible.isAccessible()) {
-				AccessController.doPrivileged(new SetAccessibleAction(accessible));
+				Thread t = Thread.currentThread();
+				t.getUncaughtExceptionHandler().uncaughtException(t, error);
+			} catch (Throwable ignored) {
+				// we ignore this
 			}
 		}
-
-		private boolean compare_Comparable(int operation, Comparable<Object> value1, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			value2 = valueOf(value1.getClass(), (String) value2);
-			if (value2 == null) {
-				return false;
-			}
-			try {
-				switch (operation) {
-					case APPROX :
-					case EQUAL : {
-						return value1.compareTo(value2) == 0;
-					}
-					case GREATER : {
-						return value1.compareTo(value2) >= 0;
-					}
-					case LESS : {
-						return value1.compareTo(value2) <= 0;
-					}
-				}
-			} catch (Exception e) {
-				// if the compareTo method throws an exception; return false
-				return false;
-			}
-			return false;
-		}
-
-		private boolean compare_Version(int operation, Version value1, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			try {
-				Version version2 = Version.valueOf((String) value2);
-				switch (operation) {
-					case APPROX :
-					case EQUAL : {
-						return value1.compareTo(version2) == 0;
-					}
-					case GREATER : {
-						return value1.compareTo(version2) >= 0;
-					}
-					case LESS : {
-						return value1.compareTo(version2) <= 0;
-					}
-				}
-			} catch (Exception e) {
-				// if the valueOf or compareTo method throws an exception
-				return false;
-			}
-			return false;
-		}
-
-		private boolean compare_Unknown(int operation, Object value1, Object value2) {
-			if (operation == SUBSTRING) {
-				return false;
-			}
-			value2 = valueOf(value1.getClass(), (String) value2);
-			if (value2 == null) {
-				return false;
-			}
-			try {
-				switch (operation) {
-					case APPROX :
-					case EQUAL :
-					case GREATER :
-					case LESS : {
-						return value1.equals(value2);
-					}
-				}
-			} catch (Exception e) {
-				// if the equals method throws an exception; return false
-				return false;
-			}
-			return false;
-		}
-
-		/**
-		 * Map a string for an APPROX (~=) comparison.
-		 * 
-		 * This implementation removes white spaces. This is the minimum
-		 * implementation allowed by the OSGi spec.
-		 * 
-		 * @param input Input string.
-		 * @return String ready for APPROX comparison.
-		 */
-		private static String approxString(String input) {
-			boolean changed = false;
-			char[] output = input.toCharArray();
-			int cursor = 0;
-			for (char c : output) {
-				if (Character.isWhitespace(c)) {
-					changed = true;
-					continue;
-				}
-
-				output[cursor] = c;
-				cursor++;
-			}
-
-			return changed ? new String(output, 0, cursor) : input;
-		}
-
-		/**
-		 * Parser class for OSGi filter strings. This class parses the complete
-		 * filter string and builds a tree of Filter objects rooted at the
-		 * parent.
-		 */
-		static private final class Parser {
-			private final String	filterstring;
-			private final char[]	filterChars;
-			private int				pos;
-
-			Parser(String filterstring) {
-				this.filterstring = filterstring;
-				filterChars = filterstring.toCharArray();
-				pos = 0;
-			}
-
-			FilterImpl parse() throws InvalidSyntaxException {
-				FilterImpl filter;
-				try {
-					filter = parse_filter();
-				} catch (ArrayIndexOutOfBoundsException e) {
-					throw new InvalidSyntaxException("Filter ended abruptly", filterstring, e);
-				}
-
-				if (pos != filterChars.length) {
-					throw new InvalidSyntaxException("Extraneous trailing characters: " + filterstring.substring(pos), filterstring);
-				}
-				return filter;
-			}
-
-			private FilterImpl parse_filter() throws InvalidSyntaxException {
-				FilterImpl filter;
-				skipWhiteSpace();
-
-				if (filterChars[pos] != '(') {
-					throw new InvalidSyntaxException("Missing '(': " + filterstring.substring(pos), filterstring);
-				}
-
-				pos++;
-
-				filter = parse_filtercomp();
-
-				skipWhiteSpace();
-
-				if (filterChars[pos] != ')') {
-					throw new InvalidSyntaxException("Missing ')': " + filterstring.substring(pos), filterstring);
-				}
-
-				pos++;
-
-				skipWhiteSpace();
-
-				return filter;
-			}
-
-			private FilterImpl parse_filtercomp() throws InvalidSyntaxException {
-				skipWhiteSpace();
-
-				char c = filterChars[pos];
-
-				switch (c) {
-					case '&' : {
-						pos++;
-						return parse_and();
-					}
-					case '|' : {
-						pos++;
-						return parse_or();
-					}
-					case '!' : {
-						pos++;
-						return parse_not();
-					}
-				}
-				return parse_item();
-			}
-
-			private FilterImpl parse_and() throws InvalidSyntaxException {
-				int lookahead = pos;
-				skipWhiteSpace();
-
-				if (filterChars[pos] != '(') {
-					pos = lookahead - 1;
-					return parse_item();
-				}
-
-				List<FilterImpl> operands = new ArrayList<FilterImpl>(10);
-
-				while (filterChars[pos] == '(') {
-					FilterImpl child = parse_filter();
-					operands.add(child);
-				}
-
-				return new FilterImpl(FilterImpl.AND, null,
-						operands.toArray(new FilterImpl[0]));
-			}
-
-			private FilterImpl parse_or() throws InvalidSyntaxException {
-				int lookahead = pos;
-				skipWhiteSpace();
-
-				if (filterChars[pos] != '(') {
-					pos = lookahead - 1;
-					return parse_item();
-				}
-
-				List<FilterImpl> operands = new ArrayList<FilterImpl>(10);
-
-				while (filterChars[pos] == '(') {
-					FilterImpl child = parse_filter();
-					operands.add(child);
-				}
-
-				return new FilterImpl(FilterImpl.OR, null,
-						operands.toArray(new FilterImpl[0]));
-			}
-
-			private FilterImpl parse_not() throws InvalidSyntaxException {
-				int lookahead = pos;
-				skipWhiteSpace();
-
-				if (filterChars[pos] != '(') {
-					pos = lookahead - 1;
-					return parse_item();
-				}
-
-				FilterImpl child = parse_filter();
-
-				return new FilterImpl(FilterImpl.NOT, null, child);
-			}
-
-			private FilterImpl parse_item() throws InvalidSyntaxException {
-				String attr = parse_attr();
-
-				skipWhiteSpace();
-
-				switch (filterChars[pos]) {
-					case '~' : {
-						if (filterChars[pos + 1] == '=') {
-							pos += 2;
-							return new FilterImpl(FilterImpl.APPROX, attr, parse_value());
-						}
-						break;
-					}
-					case '>' : {
-						if (filterChars[pos + 1] == '=') {
-							pos += 2;
-							return new FilterImpl(FilterImpl.GREATER, attr, parse_value());
-						}
-						break;
-					}
-					case '<' : {
-						if (filterChars[pos + 1] == '=') {
-							pos += 2;
-							return new FilterImpl(FilterImpl.LESS, attr, parse_value());
-						}
-						break;
-					}
-					case '=' : {
-						if (filterChars[pos + 1] == '*') {
-							int oldpos = pos;
-							pos += 2;
-							skipWhiteSpace();
-							if (filterChars[pos] == ')') {
-								return new FilterImpl(FilterImpl.PRESENT, attr, null);
-							}
-							pos = oldpos;
-						}
-
-						pos++;
-						Object string = parse_substring();
-
-						if (string instanceof String) {
-							return new FilterImpl(FilterImpl.EQUAL, attr, string);
-						}
-						return new FilterImpl(FilterImpl.SUBSTRING, attr, string);
-					}
-				}
-
-				throw new InvalidSyntaxException("Invalid operator: " + filterstring.substring(pos), filterstring);
-			}
-
-			private String parse_attr() throws InvalidSyntaxException {
-				skipWhiteSpace();
-
-				int begin = pos;
-				int end = pos;
-
-				char c = filterChars[pos];
-
-				while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
-					pos++;
-
-					if (!Character.isWhitespace(c)) {
-						end = pos;
-					}
-
-					c = filterChars[pos];
-				}
-
-				int length = end - begin;
-
-				if (length == 0) {
-					throw new InvalidSyntaxException("Missing attr: " + filterstring.substring(pos), filterstring);
-				}
-
-				return new String(filterChars, begin, length);
-			}
-
-			private String parse_value() throws InvalidSyntaxException {
-				StringBuilder sb = new StringBuilder(filterChars.length - pos);
-
-				parseloop: while (true) {
-					char c = filterChars[pos];
-
-					switch (c) {
-						case ')' : {
-							break parseloop;
-						}
-
-						case '(' : {
-							throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring);
-						}
-
-						case '\\' : {
-							pos++;
-							c = filterChars[pos];
-							/* fall through into default */
-						}
-
-						default : {
-							sb.append(c);
-							pos++;
-							break;
-						}
-					}
-				}
-
-				if (sb.length() == 0) {
-					throw new InvalidSyntaxException("Missing value: " + filterstring.substring(pos), filterstring);
-				}
-
-				return sb.toString();
-			}
-
-			private Object parse_substring() throws InvalidSyntaxException {
-				StringBuilder sb = new StringBuilder(filterChars.length - pos);
-
-				List<String> operands = new ArrayList<String>(10);
-
-				parseloop: while (true) {
-					char c = filterChars[pos];
-
-					switch (c) {
-						case ')' : {
-							if (sb.length() > 0) {
-								operands.add(sb.toString());
-							}
-
-							break parseloop;
-						}
-
-						case '(' : {
-							throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring);
-						}
-
-						case '*' : {
-							if (sb.length() > 0) {
-								operands.add(sb.toString());
-							}
-
-							sb.setLength(0);
-
-							operands.add(null);
-							pos++;
-
-							break;
-						}
-
-						case '\\' : {
-							pos++;
-							c = filterChars[pos];
-							/* fall through into default */
-						}
-
-						default : {
-							sb.append(c);
-							pos++;
-							break;
-						}
-					}
-				}
-
-				int size = operands.size();
-
-				if (size == 0) {
-					return "";
-				}
-
-				if (size == 1) {
-					Object single = operands.get(0);
-
-					if (single != null) {
-						return single;
-					}
-				}
-
-				return operands.toArray(new String[0]);
-			}
-
-			private void skipWhiteSpace() {
-				for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) {
-					pos++;
-				}
-			}
-		}
-	}
-
-	/**
-	 * This Map is used for case-insensitive key lookup during filter
-	 * evaluation. This Map implementation only supports the get operation using
-	 * a String key as no other operations are used by the Filter
-	 * implementation.
-	 */
-	static private final class CaseInsensitiveMap extends AbstractMap<String, Object> implements Map<String, Object> {
-		private final Dictionary<String, ?>	dictionary;
-		private final String[]				keys;
-
-		/**
-		 * Create a case insensitive map from the specified dictionary.
-		 * 
-		 * @param dictionary
-		 * @throws IllegalArgumentException If {@code dictionary} contains case
-		 *         variants of the same key name.
-		 */
-		CaseInsensitiveMap(Dictionary<String, ?> dictionary) {
-			if (dictionary == null) {
-				this.dictionary = null;
-				this.keys = new String[0];
-				return;
-			}
-			this.dictionary = dictionary;
-			List<String> keyList = new ArrayList<String>(dictionary.size());
-			for (Enumeration<?> e = dictionary.keys(); e.hasMoreElements();) {
-				Object k = e.nextElement();
-				if (k instanceof String) {
-					String key = (String) k;
-					for (String i : keyList) {
-						if (key.equalsIgnoreCase(i)) {
-							throw new IllegalArgumentException();
-						}
-					}
-					keyList.add(key);
-				}
-			}
-			this.keys = keyList.toArray(new String[0]);
-		}
-
-		@Override
-		public Object get(Object o) {
-			String k = (String) o;
-			for (String key : keys) {
-				if (key.equalsIgnoreCase(k)) {
-					return dictionary.get(key);
-				}
-			}
-			return null;
-		}
-
-		@Override
-		public Set<java.util.Map.Entry<String, Object>> entrySet() {
-			throw new UnsupportedOperationException();
-		}
-	}
-
-	/**
-	 * This Map is used for key lookup from a ServiceReference during filter
-	 * evaluation. This Map implementation only supports the get operation using
-	 * a String key as no other operations are used by the Filter
-	 * implementation.
-	 */
-	static private final class ServiceReferenceMap extends AbstractMap<String, Object> implements Map<String, Object> {
-		private final ServiceReference<?>	reference;
-
-		ServiceReferenceMap(ServiceReference<?> reference) {
-			this.reference = reference;
-		}
-
-		@Override
-		public Object get(Object key) {
-			if (reference == null) {
-				return null;
-			}
-			return reference.getProperty((String) key);
-		}
-
-		@Override
-		public Set<java.util.Map.Entry<String, Object>> entrySet() {
-			throw new UnsupportedOperationException();
-		}
-	}
-
-	static private final class SetAccessibleAction implements PrivilegedAction<Void> {
-		private final AccessibleObject	accessible;
-
-		SetAccessibleAction(AccessibleObject accessible) {
-			this.accessible = accessible;
-		}
-
-		@Override
-		public Void run() {
-			accessible.setAccessible(true);
-			return null;
-		}
+		helpers = Collections.unmodifiableList(l);
 	}
 
 	/**
@@ -2155,4 +703,357 @@
 			return sb.toString();
 		}
 	}
+
+	/**
+	 * Return a Map wrapper around a Dictionary.
+	 *
+	 * @param <K> The type of the key.
+	 * @param <V> The type of the value.
+	 * @param dictionary The dictionary to wrap.
+	 * @return A Map object which wraps the specified dictionary. If the
+	 *         specified dictionary can be cast to a Map, then the specified
+	 *         dictionary is returned.
+	 * @since 1.10
+	 */
+	public static <K, V> Map<K,V> asMap(
+			Dictionary< ? extends K, ? extends V> dictionary) {
+		if (dictionary instanceof Map) {
+			@SuppressWarnings("unchecked")
+			Map<K,V> coerced = (Map<K,V>) dictionary;
+			return coerced;
+		}
+		return new DictionaryAsMap<>(dictionary);
+	}
+
+	private static class DictionaryAsMap<K, V> extends AbstractMap<K,V> {
+		private final Dictionary<K,V> dict;
+
+		@SuppressWarnings("unchecked")
+		DictionaryAsMap(Dictionary< ? extends K, ? extends V> dict) {
+			this.dict = (Dictionary<K,V>) requireNonNull(dict);
+		}
+
+		Iterator<K> keys() {
+			List<K> keys = new ArrayList<>(dict.size());
+			for (Enumeration<K> e = dict.keys(); e.hasMoreElements();) {
+				keys.add(e.nextElement());
+			}
+			return keys.iterator();
+		}
+
+		@Override
+		public int size() {
+			return dict.size();
+		}
+
+		@Override
+		public boolean isEmpty() {
+			return dict.isEmpty();
+		}
+
+		@Override
+		public boolean containsKey(Object key) {
+			if (key == null) {
+				return false;
+			}
+			return dict.get(key) != null;
+		}
+
+		@Override
+		public V get(Object key) {
+			if (key == null) {
+				return null;
+			}
+			return dict.get(key);
+		}
+
+		@Override
+		public V put(K key, V value) {
+			return dict.put(
+					requireNonNull(key,
+							"a Dictionary cannot contain a null key"),
+					requireNonNull(value,
+							"a Dictionary cannot contain a null value"));
+		}
+
+		@Override
+		public V remove(Object key) {
+			if (key == null) {
+				return null;
+			}
+			return dict.remove(key);
+		}
+
+		@Override
+		public void clear() {
+			for (Iterator<K> iter = keys(); iter.hasNext();) {
+				dict.remove(iter.next());
+			}
+		}
+
+		@Override
+		public Set<K> keySet() {
+			return new KeySet();
+		}
+
+		@Override
+		public Set<Map.Entry<K,V>> entrySet() {
+			return new EntrySet();
+		}
+
+		@Override
+		public String toString() {
+			return dict.toString();
+		}
+
+		final class KeySet extends AbstractSet<K> {
+			@Override
+			public Iterator<K> iterator() {
+				return new KeyIterator();
+			}
+
+			@Override
+			public int size() {
+				return DictionaryAsMap.this.size();
+			}
+
+			@Override
+			public boolean isEmpty() {
+				return DictionaryAsMap.this.isEmpty();
+			}
+
+			@Override
+			public boolean contains(Object key) {
+				return DictionaryAsMap.this.containsKey(key);
+			}
+
+			@Override
+			public boolean remove(Object key) {
+				return DictionaryAsMap.this.remove(key) != null;
+			}
+
+			@Override
+			public void clear() {
+				DictionaryAsMap.this.clear();
+			}
+		}
+
+		final class KeyIterator implements Iterator<K> {
+			private final Iterator<K>	keys	= DictionaryAsMap.this.keys();
+			private K					key		= null;
+
+			@Override
+			public boolean hasNext() {
+				return keys.hasNext();
+			}
+
+			@Override
+			public K next() {
+				return key = keys.next();
+			}
+
+			@Override
+			public void remove() {
+				if (key == null) {
+					throw new IllegalStateException();
+				}
+				DictionaryAsMap.this.remove(key);
+				key = null;
+			}
+		}
+
+		final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+			@Override
+			public Iterator<Map.Entry<K,V>> iterator() {
+				return new EntryIterator();
+			}
+
+			@Override
+			public int size() {
+				return DictionaryAsMap.this.size();
+			}
+
+			@Override
+			public boolean isEmpty() {
+				return DictionaryAsMap.this.isEmpty();
+			}
+
+			@Override
+			public boolean contains(Object o) {
+				if (o instanceof Map.Entry) {
+					Map.Entry< ? , ? > e = (Map.Entry< ? , ? >) o;
+					return containsEntry(e);
+				}
+				return false;
+			}
+
+			private boolean containsEntry(Map.Entry< ? , ? > e) {
+				Object key = e.getKey();
+				if (key == null) {
+					return false;
+				}
+				Object value = e.getValue();
+				if (value == null) {
+					return false;
+				}
+				return Objects.equals(DictionaryAsMap.this.get(key), value);
+			}
+
+			@Override
+			public boolean remove(Object o) {
+				if (o instanceof Map.Entry) {
+					Map.Entry< ? , ? > e = (Map.Entry< ? , ? >) o;
+					if (containsEntry(e)) {
+						DictionaryAsMap.this.remove(e.getKey());
+						return true;
+					}
+				}
+				return false;
+			}
+
+			@Override
+			public void clear() {
+				DictionaryAsMap.this.clear();
+			}
+		}
+
+		final class EntryIterator implements Iterator<Map.Entry<K,V>> {
+			private final Iterator<K>	keys	= DictionaryAsMap.this.keys();
+			private K					key		= null;
+
+			@Override
+			public boolean hasNext() {
+				return keys.hasNext();
+			}
+
+			@Override
+			public Map.Entry<K,V> next() {
+				return new Entry(key = keys.next());
+			}
+
+			@Override
+			public void remove() {
+				if (key == null) {
+					throw new IllegalStateException();
+				}
+				DictionaryAsMap.this.remove(key);
+				key = null;
+			}
+		}
+
+		final class Entry extends SimpleEntry<K,V> {
+			private static final long serialVersionUID = 1L;
+
+			Entry(K key) {
+				super(key, DictionaryAsMap.this.get(key));
+			}
+
+			@Override
+			public V setValue(V value) {
+				DictionaryAsMap.this.put(getKey(), value);
+				return super.setValue(value);
+			}
+		}
+	}
+
+	/**
+	 * Return a Dictionary wrapper around a Map.
+	 *
+	 * @param <K> The type of the key.
+	 * @param <V> The type of the value.
+	 * @param map The map to wrap.
+	 * @return A Dictionary object which wraps the specified map. If the
+	 *         specified map can be cast to a Dictionary, then the specified map
+	 *         is returned.
+	 * @since 1.10
+	 */
+	public static <K, V> Dictionary<K,V> asDictionary(
+			Map< ? extends K, ? extends V> map) {
+		if (map instanceof Dictionary) {
+			@SuppressWarnings("unchecked")
+			Dictionary<K,V> coerced = (Dictionary<K,V>) map;
+			return coerced;
+		}
+		return new MapAsDictionary<>(map);
+	}
+
+	private static class MapAsDictionary<K, V> extends Dictionary<K,V> {
+		private final Map<K,V> map;
+
+		@SuppressWarnings("unchecked")
+		MapAsDictionary(Map< ? extends K, ? extends V> map) {
+			this.map = (Map<K,V>) requireNonNull(map);
+			boolean nullKey;
+			try {
+				nullKey = map.containsKey(null);
+			} catch (NullPointerException e) {
+				nullKey = false; // map does not allow null key
+			}
+			if (nullKey) {
+				throw new NullPointerException(
+						"a Dictionary cannot contain a null key");
+			}
+			boolean nullValue;
+			try {
+				nullValue = map.containsValue(null);
+			} catch (NullPointerException e) {
+				nullValue = false; // map does not allow null value
+			}
+			if (nullValue) {
+				throw new NullPointerException(
+						"a Dictionary cannot contain a null value");
+			}
+		}
+
+		@Override
+		public int size() {
+			return map.size();
+		}
+
+		@Override
+		public boolean isEmpty() {
+			return map.isEmpty();
+		}
+
+		@Override
+		public Enumeration<K> keys() {
+			return Collections.enumeration(map.keySet());
+		}
+
+		@Override
+		public Enumeration<V> elements() {
+			return Collections.enumeration(map.values());
+		}
+
+		@Override
+		public V get(Object key) {
+			if (key == null) {
+				return null;
+			}
+			return map.get(key);
+		}
+
+		@Override
+		public V put(K key, V value) {
+			return map.put(
+					requireNonNull(key,
+							"a Dictionary cannot contain a null key"),
+					requireNonNull(value,
+							"a Dictionary cannot contain a null value"));
+		}
+
+		@Override
+		public V remove(Object key) {
+			if (key == null) {
+				return null;
+			}
+			return map.remove(key);
+		}
+
+		@Override
+		public String toString() {
+			return map.toString();
+		}
+	}
+
 }
diff --git a/framework/src/main/java/org/osgi/framework/PackagePermission.java b/framework/src/main/java/org/osgi/framework/PackagePermission.java
index 1338daa..c10c211 100644
--- a/framework/src/main/java/org/osgi/framework/PackagePermission.java
+++ b/framework/src/main/java/org/osgi/framework/PackagePermission.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@
  * deprecated, implies the {@code import} action.
  * 
  * @ThreadSafe
- * @author $Id: 264ccd683465cbe22d571b0cb7d0b19352d582f7 $
+ * @author $Id: cc8cd627f5ca1e77bd3420d6e64d07b1a9ba4684 $
  */
 
 public final class PackagePermission extends BasicPermission {
@@ -713,7 +713,7 @@
 			/* work our way up the tree... */
 			int last;
 			int offset = requestedName.length() - 1;
-			while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+			while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
 				requestedName = requestedName.substring(0, last + 1) + "*";
 				pp = pc.get(requestedName);
 				if (pp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java b/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java
index 864506f..9a3a3c8 100644
--- a/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java
+++ b/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java
@@ -65,7 +65,7 @@
  * @see ServiceObjects
  * @ThreadSafe
  * @since 1.8
- * @author $Id$
+ * @author $Id: 864506fa15679676e52eee91982a6fd5c1e9768f $
  */
 @ConsumerType
 public interface PrototypeServiceFactory<S> extends ServiceFactory<S> {
diff --git a/framework/src/main/java/org/osgi/framework/ServiceObjects.java b/framework/src/main/java/org/osgi/framework/ServiceObjects.java
index 8490189..9b8ca46 100644
--- a/framework/src/main/java/org/osgi/framework/ServiceObjects.java
+++ b/framework/src/main/java/org/osgi/framework/ServiceObjects.java
@@ -41,7 +41,7 @@
  * @see PrototypeServiceFactory
  * @ThreadSafe
  * @since 1.8
- * @author $Id$
+ * @author $Id: 84901895b763946d9f0e3819e47ecbf0ffa60f04 $
  */
 @ProviderType
 public interface ServiceObjects<S> {
diff --git a/framework/src/main/java/org/osgi/framework/ServicePermission.java b/framework/src/main/java/org/osgi/framework/ServicePermission.java
index e7d6c6f..693a787 100644
--- a/framework/src/main/java/org/osgi/framework/ServicePermission.java
+++ b/framework/src/main/java/org/osgi/framework/ServicePermission.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@
  * to get the specific service.
  * 
  * @ThreadSafe
- * @author $Id: 8db61d0b1cadd57ab173cba677b6bfb353680800 $
+ * @author $Id: a6b52521c8ba68698c1e167d4596f3ac56aab8ca $
  */
 
 public final class ServicePermission extends BasicPermission {
@@ -866,7 +866,7 @@
 		// work our way up the tree...
 		int last;
 		int offset = requestedName.length() - 1;
-		while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+		while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
 			requestedName = requestedName.substring(0, last + 1) + "*";
 			sp = pc.get(requestedName);
 			if (sp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/ServiceReference.java b/framework/src/main/java/org/osgi/framework/ServiceReference.java
index 5d1b175..c512a44 100644
--- a/framework/src/main/java/org/osgi/framework/ServiceReference.java
+++ b/framework/src/main/java/org/osgi/framework/ServiceReference.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -50,10 +50,11 @@
  * @see BundleContext#getService(ServiceReference)
  * @see BundleContext#getServiceObjects(ServiceReference)
  * @ThreadSafe
- * @author $Id: 1454244c30992b7a52ac3838b03bc584c3495816 $
+ * @author $Id: adb91d7f0922417180e901dc6ec447f467b34921 $
  */
 @ProviderType
-public interface ServiceReference<S> extends Comparable<Object> {
+public interface ServiceReference<S>
+		extends Comparable<Object>, BundleReference {
 	/**
 	 * Returns the property value to which the specified property key is mapped
 	 * in the properties {@code Dictionary} object of the service referenced by
@@ -109,6 +110,7 @@
 	 *         already been unregistered.
 	 * @see BundleContext#registerService(String[],Object,Dictionary)
 	 */
+	@Override
 	public Bundle getBundle();
 
 	/**
@@ -131,14 +133,24 @@
 	 * <p>
 	 * This method performs the following checks:
 	 * <ol>
+	 * <li>If the specified bundle is equal to the bundle that registered the
+	 * service referenced by this {@code ServiceReference} (registrant bundle)
+	 * return {@code true}.</li>
 	 * <li>Get the package name from the specified class name.</li>
-	 * <li>For the bundle that registered the service referenced by this
-	 * {@code ServiceReference} (registrant bundle); find the source for the
-	 * package. If no source is found then return {@code true} if the registrant
-	 * bundle is equal to the specified bundle; otherwise return {@code false}.</li>
-	 * <li>If the package source of the registrant bundle is equal to the
-	 * package source of the specified bundle then return {@code true};
-	 * otherwise return {@code false}.</li>
+	 * <li>For the specified bundle; find the source for the package. If no
+	 * source is found then return {@code true} (use of reflection is assumed by
+	 * the specified bundle).</li>
+	 * <li>For the registrant bundle; find the source for the package. If the
+	 * package source is found then return {@code true} if the package source
+	 * equals the package source of the specified bundle; otherwise return
+	 * {@code false}.</li>
+	 * <li>If no package source is found for the registrant bundle then
+	 * determine the package source based on the service object. If the service
+	 * object is a {@code ServiceFactory} and the factory implementation is not
+	 * from the registrant bundle return {@code true}; otherwise attempt to find
+	 * the package source based on the service object class. If the package
+	 * source is found and is equal to package source of the specified bundle
+	 * return {@code true}; otherwise return {@code false}.</li>
 	 * </ol>
 	 * 
 	 * @param bundle The {@code Bundle} object to check.
@@ -148,8 +160,8 @@
 	 *         bundle use the same source for the package of the specified class
 	 *         name. Otherwise {@code false} is returned.
 	 * @throws IllegalArgumentException If the specified {@code Bundle} was not
-	 *         created by the same framework instance as this
-	 *         {@code ServiceReference}.
+	 *             created by the same framework instance as this
+	 *             {@code ServiceReference}.
 	 * @since 1.3
 	 */
 	public boolean isAssignableTo(Bundle bundle, String className);
@@ -212,4 +224,27 @@
 	 * @since 1.9
 	 */
 	public Dictionary<String,Object> getProperties();
+
+	/**
+	 * Adapt this {@code ServiceReference} object to the specified type.
+	 * <p>
+	 * Adapting this {@code ServiceReference} object to the specified type may
+	 * require certain checks, including security checks, to succeed. If a check
+	 * does not succeed, then this {@code ServiceReference} object cannot be
+	 * adapted and {@code null} is returned.
+	 * 
+	 * @param <A> The type to which this {@code ServiceReference} object is to
+	 *            be adapted.
+	 * @param type Class object for the type to which this
+	 *            {@code ServiceReference} object is to be adapted.
+	 * @return The object, of the specified type, to which this
+	 *         {@code ServiceReference} object has been adapted or {@code null}
+	 *         if this {@code ServiceReference} object cannot be adapted to the
+	 *         specified type.
+	 * @throws SecurityException If the caller does not have the appropriate
+	 *             {@code AdaptPermission[type,this,ADAPT]}, and the Java
+	 *             Runtime Environment supports permissions.
+	 * @since 1.10
+	 */
+	<A> A adapt(Class<A> type);
 }
diff --git a/framework/src/main/java/org/osgi/framework/connect/ConnectContent.java b/framework/src/main/java/org/osgi/framework/connect/ConnectContent.java
new file mode 100644
index 0000000..3a90329
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/connect/ConnectContent.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) OSGi Alliance (2019, 2020). All Rights Reserved.
+ *
+ * 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 org.osgi.framework.connect;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Optional;
+
+import org.osgi.annotation.versioning.ConsumerType;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.wiring.BundleRevisions;
+
+/**
+ * A {@code ConnectContent} provides a {@link Framework} instance access to the
+ * content of a {@link ConnectModule}.
+ * <p>
+ * A framework may {@link #open() open} and {@link #close() close} the content
+ * for a {@link ConnectModule} multiple times while the {@code ConnectContent}
+ * is in use by the framework. The framework must close the
+ * {@code ConnectContent} once the {@code ConnectContent} is no longer used as
+ * the content of a current bundle revision or an in use bundle revision.
+ * <p>
+ * An entry in a {@code ConnectContent} is identified by a path name that is a
+ * solidus (<code>'/' \u002F</code>) separated path. A {@code ConnectContent}
+ * may treat directories as entries. A directory entry path name will end with a
+ * solidus. A directory entry may be located using a path name that omits the
+ * trailing solidus.
+ * 
+ * @see BundleRevisions
+ * @ThreadSafe
+ * @author $Id: 9e455f9d467f0e38daea0ea52a59a5ccb8c81257 $
+ */
+@ConsumerType
+public interface ConnectContent {
+	/**
+	 * The {@code osgi.identity}
+	 * {@link IdentityNamespace#CAPABILITY_TAGS_ATTRIBUTE tags} attribute value
+	 * used by the framework to tag connect bundle revisions.
+	 */
+	String TAG_OSGI_CONNECT = "osgi.connect";
+
+	/**
+	 * Returns the Manifest headers and values of this {@code ConnectContent}.
+	 * 
+	 * @return An {@code Optional} containing the Manifest headers and values
+	 *         for this {@code ConnectContent}, or an empty {@code Optional} if
+	 *         the framework should handle parsing the Manifest of the content
+	 *         itself.
+	 * @throws IllegalStateException If this {@code ConnectContent} has been
+	 *             closed.
+	 */
+	Optional<Map<String,String>> getHeaders();
+
+	/**
+	 * Returns the entry names available in this {@code ConnectContent}.
+	 * 
+	 * @return An {@code Iterable} which can supply the available entry names.
+	 * @throws IOException If an error occurs reading this
+	 *             {@code ConnectContent}.
+	 * @throws IllegalStateException If this {@code ConnectContent} has been
+	 *             closed.
+	 */
+	Iterable<String> getEntries() throws IOException;
+
+	/**
+	 * Returns the {@link ConnectEntry} for the specified path name in this
+	 * content.
+	 * <p>
+	 * The {@link Optional#empty() empty} value is returned if an entry with the
+	 * specified path name does not exist. The path must not start with a
+	 * &quot;/&quot; and is relative to the root of this content. A connect
+	 * entry for a directory will have a path name that ends with a slash ('/').
+	 * 
+	 * @param path The path name of the entry.
+	 * @return An {@code Optional} containing the {@link ConnectEntry} for the
+	 *         specified path, or an empty {@code Optional} if no entry for
+	 *         specified path can be found.
+	 * @throws IllegalStateException If this {@code ConnectContent} has been
+	 *             closed.
+	 */
+	Optional<ConnectEntry> getEntry(String path);
+
+	/**
+	 * Returns a class loader for this {@code ConnectContent}.
+	 * <p>
+	 * This method is called by the framework for {@link Bundle#RESOLVED
+	 * resolved} bundles only and will be called at most once while a bundle is
+	 * resolved. If a bundle associated with a {@link ConnectModule} is
+	 * refreshed and resolved again, the framework will ask the
+	 * {@code ConnectContent} for the class loader again. This allows for a
+	 * {@code ConnectContent} to reuse or create a new class loader each time
+	 * the bundle revision is resolved.
+	 * 
+	 * @return An {@code Optional} containing the class loader for this
+	 *         {@code ConnectContent}, or an empty {@code Optional} if framework
+	 *         should handle creating a class loader for the bundle revision
+	 *         associated with this {@code ConnectContent}.
+	 * @throws IllegalStateException If this {@code ConnectContent} has been
+	 *             closed.
+	 */
+	Optional<ClassLoader> getClassLoader();
+
+	/**
+	 * Opens this {@code ConnectContent}.
+	 * <p>
+	 * The framework will open the content when it needs to access the content
+	 * for a bundle revision associated with this {@code ConnectContent}. The
+	 * framework may defer calling this method until requests to access the
+	 * bundle revision content are made.
+	 * 
+	 * @throws IOException If an error occurred opening this
+	 *             {@code ConnectContent}.
+	 */
+	void open() throws IOException;
+
+	/**
+	 * Closes this {@code ConnectContent}.
+	 * 
+	 * @throws IOException If an error occurred closing this
+	 *             {@code ConnectContent}.
+	 */
+	void close() throws IOException;
+
+	/**
+	 * Represents the entry of a {@code ConnectContent}.
+	 */
+	@ConsumerType
+	public interface ConnectEntry {
+		/**
+		 * Returns the path name of this entry.
+		 * 
+		 * @return The path name of this entry.
+		 */
+		String getName();
+
+		/**
+		 * Returns the content length of this entry.
+		 * 
+		 * @return The content length of the entry, or {@code -1} if the content
+		 *         length is not known.
+		 */
+		public long getContentLength();
+
+		/**
+		 * Returns the last modification time of this entry.
+		 * 
+		 * @return The last modification time of this entry measured in
+		 *         milliseconds since the epoch (00:00:00 GMT, January 1, 1970).
+		 */
+		public long getLastModified();
+
+		/**
+		 * Returns the content of this entry.
+		 * 
+		 * @return The content of this entry.
+		 * @throws IOException If an error occurs reading the content.
+		 */
+		default byte[] getBytes() throws IOException {
+			long longLength = getContentLength();
+			if (longLength > Integer.MAX_VALUE - 8) {
+				throw new IOException(
+						"Entry is to big to fit into a byte[]: " + getName());
+			}
+
+			try (InputStream in = getInputStream()) {
+				int length = (int) longLength;
+				if (length > 0) {
+					int bytesread = 0;
+					byte[] result = new byte[length];
+					int readcount = 0;
+					while (bytesread < length) {
+						readcount = in.read(result, bytesread,
+								length - bytesread);
+						bytesread += readcount;
+						if (readcount <= 0) {
+							break;
+						}
+					}
+					return result;
+				} else {
+					ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+					int nRead;
+					byte[] data = new byte[1024];
+					while ((nRead = in.read(data, 0, data.length)) > 0) {
+						buffer.write(data, 0, nRead);
+					}
+					buffer.flush();
+					return buffer.toByteArray();
+				}
+			}
+		}
+
+		/**
+		 * Returns an input stream for the content of this entry.
+		 * 
+		 * @return An input stream for the content of this entry.
+		 * @throws IOException If an error occurs reading the content.
+		 */
+		InputStream getInputStream() throws IOException;
+	}
+}
diff --git a/framework/src/main/java/org/osgi/framework/connect/ConnectFrameworkFactory.java b/framework/src/main/java/org/osgi/framework/connect/ConnectFrameworkFactory.java
new file mode 100644
index 0000000..307f419
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/connect/ConnectFrameworkFactory.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) OSGi Alliance (2019, 2020). All Rights Reserved.
+ *
+ * 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 org.osgi.framework.connect;
+
+import java.util.Map;
+
+import org.osgi.annotation.versioning.ProviderType;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.launch.Framework;
+
+/**
+ * A factory for creating {@link Framework} instances.
+ * <p>
+ * If a framework supports {@link ModuleConnector}, then the implementation jar
+ * must contain the following resource:
+ * 
+ * <pre>
+ * /META-INF/services/org.osgi.framework.connect.ConnectFrameworkFactory
+ * </pre>
+ * 
+ * This UTF-8 encoded resource must contain the name of the framework
+ * implementation's ConnectFrameworkFactory implementation class. Space and tab
+ * characters, including blank lines, in the resource must be ignored. The
+ * number sign ({@code '#'} &#92;u0023) and all characters following it on each
+ * line are a comment and must be ignored.
+ * <p>
+ * Launchers can find the name of the ConnectFrameworkFactory implementation
+ * class in the resource and then load and construct a ConnectFrameworkFactory
+ * object for the framework implementation. The ConnectFrameworkFactory
+ * implementation class must have a public, no-argument constructor. Java&#8482;
+ * SE 6 introduced the {@code ServiceLoader} class which can create a
+ * ConnectFrameworkFactory instance from the resource.
+ * 
+ * @ThreadSafe
+ * @author $Id: fee4e88754bbaa4a88bcee0c0eaefa54893df6a1 $
+ */
+@ProviderType
+public interface ConnectFrameworkFactory {
+	/**
+	 * Create a new {@link Framework} instance using the specified
+	 * {@link ModuleConnector module connector}.
+	 * 
+	 * @param configuration The framework properties to configure the new
+	 *            framework instance. If framework properties are not provided
+	 *            by the configuration argument, the created framework instance
+	 *            must use some reasonable default configuration appropriate for
+	 *            the current VM. For example, the system packages for the
+	 *            current execution environment should be properly exported. The
+	 *            specified configuration argument may be {@code null}. The
+	 *            created framework instance must copy any information needed
+	 *            from the specified configuration argument since the
+	 *            configuration argument can be changed after the framework
+	 *            instance has been created.
+	 * @param moduleConnector The module connector that the new framework
+	 *            instance will use. The specified module connector argument may
+	 *            be {@code null}.
+	 * @return A new, configured {@link Framework} instance. The framework
+	 *         instance must be in the {@link Bundle#INSTALLED} state.
+	 * @throws SecurityException If the caller does not have
+	 *             {@code AllPermission}, and the Java Runtime Environment
+	 *             supports permissions.
+	 * @see ModuleConnector
+	 */
+	Framework newFramework(Map<String,String> configuration,
+			ModuleConnector moduleConnector);
+}
diff --git a/framework/src/main/java/org/osgi/framework/connect/ConnectModule.java b/framework/src/main/java/org/osgi/framework/connect/ConnectModule.java
new file mode 100644
index 0000000..d3b8376
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/connect/ConnectModule.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) OSGi Alliance (2019, 2020). All Rights Reserved.
+ *
+ * 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 org.osgi.framework.connect;
+
+import java.io.IOException;
+
+import org.osgi.annotation.versioning.ConsumerType;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.wiring.BundleRevision;
+
+/**
+ * A {@code ConnectModule} is used by a {@link Framework} instance to access the
+ * content of the connected bundle.
+ * 
+ * @ThreadSafe
+ * @author $Id: d81245bffb9c6de8e3d2e9515f1443b0f6b47189 $
+ */
+@ConsumerType
+public interface ConnectModule {
+	/**
+	 * Returns the current content of this connect module.
+	 * <p>
+	 * The framework must call this method when it needs to access the content
+	 * for the current {@link BundleRevision bundle revision} of this
+	 * {@code ConnectModule}. The framework may defer opening the returned
+	 * {@link ConnectContent} until requests to access the bundle revision
+	 * content are made.
+	 * 
+	 * @return The current {@link ConnectContent} of this {@code ConnectModule}.
+	 * @throws IOException If an error occurred getting the content.
+	 * @see ModuleConnector#connect(String)
+	 */
+	ConnectContent getContent() throws IOException;
+}
diff --git a/framework/src/main/java/org/osgi/framework/connect/FrameworkUtilHelper.java b/framework/src/main/java/org/osgi/framework/connect/FrameworkUtilHelper.java
new file mode 100644
index 0000000..f7b54ab
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/connect/FrameworkUtilHelper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) OSGi Alliance (2019, 2020). All Rights Reserved.
+ *
+ * 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 org.osgi.framework.connect;
+
+import java.util.Optional;
+
+import org.osgi.annotation.versioning.ConsumerType;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * A helper for the {@link FrameworkUtil} class.
+ * <p>
+ * This helper provides alternative implementations for methods on
+ * {@link FrameworkUtil}.
+ */
+@ConsumerType
+public interface FrameworkUtilHelper {
+	/**
+	 * Returns the {@link Bundle} associated with the specified class.
+	 * <p>
+	 * This helper method is called by {@link FrameworkUtil#getBundle(Class)} if
+	 * the standard implementation of {@link FrameworkUtil} is unable to find
+	 * the bundle.
+	 * 
+	 * @param classFromBundle A class associated with a bundle.
+	 * @return An {@code Optional} containing the {@link Bundle} for the
+	 *         specified class, or an empty {@code Optional} if the specified
+	 *         class is not from a bundle.
+	 */
+	default Optional<Bundle> getBundle(Class< ? > classFromBundle) {
+		return Optional.empty();
+	}
+}
diff --git a/framework/src/main/java/org/osgi/framework/connect/ModuleConnector.java b/framework/src/main/java/org/osgi/framework/connect/ModuleConnector.java
new file mode 100644
index 0000000..e62b0e0
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/connect/ModuleConnector.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) OSGi Alliance (2019, 2020). All Rights Reserved.
+ *
+ * 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 org.osgi.framework.connect;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Optional;
+
+import org.osgi.annotation.versioning.ConsumerType;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.launch.Framework;
+
+/**
+ * A {@code ModuleConnector} provides connections to instances of
+ * {@link ConnectModule} that are used by a {@link Framework} instance to
+ * connect installed bundles locations with content provided by the
+ * {@code ModuleConnector}.
+ * <p>
+ * This allows a {@code ModuleConnector} to provide content and classes for a
+ * connected bundle installed in the {@code Framework}. A
+ * {@code ModuleConnector} is provided when
+ * {@link ConnectFrameworkFactory#newFramework(Map, ModuleConnector) creating} a
+ * framework instance. Because a {@code ModuleConnector} instance can
+ * participate in the initialization of the {@code Framework} and the life cycle
+ * of a {@code Framework} instance the {@code ModuleConnector} instance should
+ * only be used with a single {@code Framework} instance at a time.
+ * 
+ * @ThreadSafe
+ * @author $Id: 5ee358acfec177e4bf92994fee8e61c9c841ec06 $
+ */
+@ConsumerType
+public interface ModuleConnector {
+
+	/**
+	 * Initializes this {@code ModuleConnector} with the
+	 * {@link Constants#FRAMEWORK_STORAGE framework persistent storage} file and
+	 * framework properties configured for a {@link Framework} instance.
+	 * <p>
+	 * This method is called once by a {@link Framework} instance and is called
+	 * before any other methods on this module connector are called.
+	 * 
+	 * @param storage The persistent storage area used by the {@link Framework}
+	 *            or {@code null} if the platform does not have file system
+	 *            support.
+	 * @param configuration An unmodifiable map of framework configuration
+	 *            properties that were used to configure the new framework
+	 *            instance.
+	 */
+	void initialize(File storage, Map<String,String> configuration);
+
+	/**
+	 * Connects a bundle location with a {@link ConnectModule}.
+	 * <p>
+	 * When the result is empty, then the framework must handle reading the
+	 * content of the bundle itself. Otherwise, the returned
+	 * {@link ConnectModule} must be used by the framework to access the content
+	 * of the bundle.
+	 * 
+	 * @param location The bundle location used to install a bundle.
+	 * @return An {@code Optional} containing the {@link ConnectModule} for the
+	 *         specified bundle location, or an empty {@code Optional} if the
+	 *         framework must handle reading the content of the bundle itself.
+	 * @throws BundleException If the location cannot be handled.
+	 */
+	Optional<ConnectModule> connect(String location) throws BundleException;
+
+	/**
+	 * Creates a new activator for this {@code ModuleConnector}.
+	 * <p>
+	 * This method is called by the framework during framework
+	 * {@link Framework#init(FrameworkListener...) initialization}. Returning an
+	 * activator allows this {@code ModuleConnector} to participate in the
+	 * framework life cycle. If an activator is returned:
+	 * <ul>
+	 * <li>The framework will call the activator's
+	 * {@link BundleActivator#start(BundleContext) start} method prior to
+	 * activating any extension bundles.</li>
+	 * <li>The framework will call the activator's
+	 * {@link BundleActivator#stop(BundleContext) stop} method after
+	 * deactivating any extension bundles.</li>
+	 * </ul>
+	 * 
+	 * @return An {@code Optional} containing a new {@link BundleActivator} for
+	 *         this {@code ModuleConnector}, or an empty {@code Optional} if no
+	 *         {@link BundleActivator} is necessary.
+	 */
+	Optional<BundleActivator> newBundleActivator();
+}
diff --git a/framework/src/main/java/org/osgi/framework/connect/package-info.java b/framework/src/main/java/org/osgi/framework/connect/package-info.java
new file mode 100644
index 0000000..d4e22a4
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/connect/package-info.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) OSGi Alliance (2019, 2020). All Rights Reserved.
+ * 
+ * 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.
+ */
+
+/**
+ * Framework Connect Package Version 1.0.
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest.
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.framework.connect; version="[1.0,2.0)"}
+ * 
+ * @author $Id: b7344ca62c5cef84330e009ce4a0704e4d83b6c0 $
+ */
+
+@Version("1.0")
+package org.osgi.framework.connect;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java b/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java
index aa30709..6b83401 100644
--- a/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java
+++ b/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java
@@ -25,7 +25,7 @@
  * <p>
  * A Bundle can be adapted to provide a {@code BundleDTO} for the Bundle.
  * 
- * @author $Id$
+ * @author $Id: aa30709351d8fe70b19c9ea99456ebd15ecab7c3 $
  * @NotThreadSafe
  */
 public class BundleDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java b/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java
index 7c52572..7b32f93 100644
--- a/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java
+++ b/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java
@@ -30,7 +30,7 @@
  * framework will contain only the launch properties of the framework. These
  * properties will not include the System properties.
  * 
- * @author $Id$
+ * @author $Id: 7c525727cbe877e888b460cd14d8f9054f99ee0c $
  * @NotThreadSafe
  */
 public class FrameworkDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java b/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java
index 87265de..2f92fb1 100644
--- a/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java
+++ b/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2012, 2014). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2019). All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,22 +17,23 @@
 package org.osgi.framework.dto;
 
 import java.util.Map;
+
 import org.osgi.dto.DTO;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
 /**
  * Data Transfer Object for a ServiceReference.
- * 
  * <p>
  * {@code ServiceReferenceDTO}s for all registered services can be obtained from
- * a {@link FrameworkDTO}. A started Bundle can be adapted to provide a
+ * a {@link FrameworkDTO}. A {@link ServiceReference} can be adapted to a
+ * {@code ServiceReferenceDTO}. A started Bundle can be adapted to provide a
  * {@code ServiceReferenceDTO[]} of the services registered by the Bundle. A
  * {@code ServiceReferenceDTO} obtained from a framework must convert service
  * property values which are not valid value types for DTOs to type
  * {@code String} using {@code String.valueOf(Object)}.
  * 
- * @author $Id$
+ * @author $Id: 8ac26a24b8adacdcd09f441dcdfc8d6a27bbaabd $
  * @NotThreadSafe
  */
 public class ServiceReferenceDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/dto/package-info.java b/framework/src/main/java/org/osgi/framework/dto/package-info.java
index 2acfb6f..4499fc8 100644
--- a/framework/src/main/java/org/osgi/framework/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/dto/package-info.java
@@ -32,7 +32,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.dto; version="[1.8,1.9)"}
  * 
- * @author $Id$
+ * @author $Id: 2acfb6f1633e18f1ceedd27c04e70131cae4f293 $
  */
 
 @Version("1.8")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java
index 08c20ca..ce89815 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java
@@ -26,7 +26,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.hooks.bundle; version="[1.1,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: 08c20cab669f1850f585c5cd4b3b897ce587b2bd $
  */
 
 @Version("1.1")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java
index de05003..6333093 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java
@@ -26,7 +26,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.hooks.resolver; version="[1.0,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: de050037c6b835045603f09b12ad58a6353d1229 $
  */
 
 @Version("1.0")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java
index 74f0c41..5fd8020 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java
@@ -26,7 +26,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.hooks.service; version="[1.1,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: 74f0c41d5ebf20181942ee393965d885deb3889c $
  */
 
 @Version("1.1")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java
index 254dd9b..8768402 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2020). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,12 +18,11 @@
 
 /**
  * A weaving exception used to indicate that the class load should be failed but
- * the weaving hook must not be blacklisted by the framework.
- * 
+ * the weaving hook must not be deny listed by the framework.
  * <p>
  * This exception conforms to the general purpose exception chaining mechanism.
  * 
- * @author $Id: 7575fc1b015fea7c77397391df6c8d2085513e76 $
+ * @author $Id: 29ebe6460fbe20ce8037f14a162c72f633b1de31 $
  */
 
 public class WeavingException extends RuntimeException {
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java
index 760b00c..b3e7ac4 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2020). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,30 +36,29 @@
  * bytes as modified by previously called weaving hooks.
  * 
  * @ThreadSafe
- * @author $Id: 8d99df5b0f3e7ffa9573695923afe86de9835fde $
+ * @author $Id: e5b54121d2cab7caefbae3b718421b28e5a9ede7 $
  */
 @ConsumerType
 public interface WeavingHook {
 	/**
 	 * Weaving hook method.
-	 * 
+	 * <p>
 	 * This method can modify the specified woven class object to weave the
 	 * class being defined.
-	 * 
 	 * <p>
 	 * If this method throws any exception, the framework must log the exception
 	 * and fail the class load in progress. This weaving hook service must be
-	 * blacklisted by the framework and must not be called again. The
-	 * blacklisting of this weaving hook service must expire when this weaving
-	 * hook service is unregistered. However, this method can throw a
+	 * deny listed by the framework and must not be called again. The deny
+	 * listing of this weaving hook service must expire when this weaving hook
+	 * service is unregistered. However, this method can throw a
 	 * {@link WeavingException} to deliberately fail the class load in progress
-	 * without being blacklisted by the framework.
+	 * without being deny listed by the framework.
 	 * 
 	 * @param wovenClass The {@link WovenClass} object that represents the data
-	 *        that will be used to define the class.
+	 *            that will be used to define the class.
 	 * @throws WeavingException If this weaving hook wants to deliberately fail
-	 *         the class load in progress without being blacklisted by the
-	 *         framework
+	 *             the class load in progress without being deny listed by the
+	 *             framework
 	 */
 	public void weave(WovenClass wovenClass);
 }
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java
index 4a7a699..36e7303 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java
@@ -47,7 +47,7 @@
  * 
  * @ThreadSafe
  * @since 1.1
- * @author $Id$
+ * @author $Id: 4a7a69943bffbc53738f050c51d49f11b67a13cb $
  */
 @ConsumerType
 public interface WovenClassListener {
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java
index 5b48f04..bffee3e 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java
@@ -28,7 +28,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.hooks.weaving; version="[1.1,2.0)"}
  * </p>
- * @author $Id$
+ * @author $Id: 5b48f041a1764e8b2979cdbbb528082054ab3e7f $
  */
 
 @Version("1.1")
diff --git a/framework/src/main/java/org/osgi/framework/launch/Framework.java b/framework/src/main/java/org/osgi/framework/launch/Framework.java
index 37a519d..fd6d325 100644
--- a/framework/src/main/java/org/osgi/framework/launch/Framework.java
+++ b/framework/src/main/java/org/osgi/framework/launch/Framework.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2008, 2018). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2008, 2020). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 import java.io.InputStream;
 import java.net.URL;
 import java.util.Enumeration;
+
 import org.osgi.annotation.versioning.ProviderType;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
@@ -35,7 +36,7 @@
  * instance.
  * 
  * @ThreadSafe
- * @author $Id: 7fa67978e59a43dfedd6e755ddfa5b1aa6ea9141 $
+ * @author $Id: bf960bdc39d19a780694a8cab5a555b3e0dc0fde $
  */
 @ProviderType
 public interface Framework extends Bundle {
@@ -117,37 +118,33 @@
 	 * A Framework Event is returned to indicate why this Framework has stopped.
 	 * 
 	 * @param timeout Maximum number of milliseconds to wait until this
-	 *        Framework has completely stopped. A value of zero will wait
-	 *        indefinitely.
+	 *            Framework has completely stopped. A value of zero will wait
+	 *            indefinitely.
 	 * @return A Framework Event indicating the reason this method returned. The
 	 *         following {@code FrameworkEvent} types may be returned by this
 	 *         method.
 	 *         <ul>
 	 *         <li>{@link FrameworkEvent#STOPPED STOPPED} - This Framework has
-	 *         been stopped. </li>
-	 * 
+	 *         been stopped.</li>
 	 *         <li>{@link FrameworkEvent#STOPPED_UPDATE STOPPED_UPDATE} - This
 	 *         Framework has been updated which has shutdown and will now
 	 *         restart.</li>
-	 * 
-	 *         <li> {@link FrameworkEvent#STOPPED_BOOTCLASSPATH_MODIFIED
-	 *         STOPPED_BOOTCLASSPATH_MODIFIED} - This Framework has been stopped
-	 *         and a bootclasspath extension bundle has been installed or
-	 *         updated. The VM must be restarted in order for the changed boot
-	 *         class path to take effect. </li>
-	 * 
+	 *         <li>{@link FrameworkEvent#STOPPED_SYSTEM_REFRESHED
+	 *         STOPPED_SYSTEM_REFRESHED} - The Framework has been stopped
+	 *         because of a refresh operation on the system bundle. A new class
+	 *         loader must be used to restart the Framework.</li>
 	 *         <li>{@link FrameworkEvent#ERROR ERROR} - The Framework
 	 *         encountered an error while shutting down or an error has occurred
-	 *         which forced the framework to shutdown. </li>
-	 * 
-	 *         <li> {@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This
+	 *         which forced the framework to shutdown.</li>
+	 *         <li>{@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This
 	 *         method has timed out and returned before this Framework has
 	 *         stopped.</li>
 	 *         </ul>
 	 * @throws InterruptedException If another thread interrupted the current
-	 *         thread before or while the current thread was waiting for this
-	 *         Framework to completely stop. The <i>interrupted status</i> of
-	 *         the current thread is cleared when this exception is thrown.
+	 *             thread before or while the current thread was waiting for
+	 *             this Framework to completely stop. The <i>interrupted
+	 *             status</i> of the current thread is cleared when this
+	 *             exception is thrown.
 	 * @throws IllegalArgumentException If the value of timeout is negative.
 	 */
 	FrameworkEvent waitForStop(long timeout) throws InterruptedException;
diff --git a/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java b/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
index 6d656d3..f5e29a9 100644
--- a/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
+++ b/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2009, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2009, 2019). All Rights Reserved.
  * 
  * 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 org.osgi.framework.launch;
 
 import java.util.Map;
+
 import org.osgi.annotation.versioning.ProviderType;
 import org.osgi.framework.Bundle;
 
@@ -45,7 +46,7 @@
  * the resource.
  * 
  * @ThreadSafe
- * @author $Id: c1647bcb8416b6dfa9e37c6cc146bb54c7173526 $
+ * @author $Id: ecb53ee09a939a2c23a47ecad6f94fcfdf2f7c46 $
  */
 @ProviderType
 public interface FrameworkFactory {
diff --git a/framework/src/main/java/org/osgi/framework/launch/package-info.java b/framework/src/main/java/org/osgi/framework/launch/package-info.java
index db5e926..77d416f 100644
--- a/framework/src/main/java/org/osgi/framework/launch/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/launch/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2010, 2014). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2019). All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.launch; version="[1.2,2.0)"}
  *
- * @author $Id$
+ * @author $Id: 70417d372c5e8200dc743847b14aeb300870b839 $
  */
 
 @Version("1.2")
diff --git a/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java b/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java
index 2f843a8..c6af9d8 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2012, 2014). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2020). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -54,19 +54,19 @@
  * </ul>
  * 
  * <p>
- * A non-fragment resource with the with the
- * {@link IdentityNamespace#TYPE_BUNDLE osgi.bundle} type
- * {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE identity} provides zero or
- * one<sup>&#8224;</sup> host capabilities. A fragment resource with the
- * {@link IdentityNamespace#TYPE_FRAGMENT osgi.fragment} type
- * {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE identity} must not declare
- * a host capability and must declare exactly one host requirement.
+ * A non-fragment resource with the {@link IdentityNamespace#TYPE_BUNDLE
+ * osgi.bundle} type {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
+ * identity} provides zero or one<sup>&#8224;</sup> host capabilities. A
+ * fragment resource with the {@link IdentityNamespace#TYPE_FRAGMENT
+ * osgi.fragment} type {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
+ * identity} must not declare a host capability and must declare exactly one
+ * host requirement.
  * <p>
  * &#8224; A resource with no bundle symbolic name must not provide a host
  * capability.
  * 
  * @Immutable
- * @author $Id: 9f789ca25dafcf9d5e9a4f45d377f943d62b134a $
+ * @author $Id: 79484b4d0c372d8cebf7c767ec12e134b60b8411 $
  */
 public final class HostNamespace extends AbstractWiringNamespace {
 
@@ -135,7 +135,6 @@
 	 * fragment. The default value is {@link #EXTENSION_FRAMEWORK framework}.
 	 * 
 	 * @see #EXTENSION_FRAMEWORK
-	 * @see #EXTENSION_BOOTCLASSPATH
 	 */
 	public final static String	REQUIREMENT_EXTENSION_DIRECTIVE				= "extension";
 
@@ -153,6 +152,7 @@
 	 * loaded by the boot class loader.
 	 * 
 	 * @see #REQUIREMENT_EXTENSION_DIRECTIVE
+	 * @deprecated As of 1.2.
 	 */
 	public final static String	EXTENSION_BOOTCLASSPATH						= "bootclasspath";
 
diff --git a/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java b/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java
index cfbb843..3ef3f11 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2012, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2020). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@
  * capability.
  * 
  * @Immutable
- * @author $Id: 7bc7a11c45b30538ffbb7572c4539f6160557684 $
+ * @author $Id: d2357fa05b1e68f952710e07a2fab46bf4ea3cec $
  */
 public final class IdentityNamespace extends Namespace {
 
@@ -105,6 +105,16 @@
 	public static final String	TYPE_UNKNOWN						= "unknown";
 
 	/**
+	 * The attribute value that contains tags for the resource. A tag is used to
+	 * identify an aspect of the resource that is not otherwise expressed by the
+	 * capabilities of the resource. The value of this attribute must be of type
+	 * {@code List<String>}.
+	 * 
+	 * @since 1.2
+	 */
+	public static final String	CAPABILITY_TAGS_ATTRIBUTE			= "tags";
+
+	/**
 	 * The capability attribute that contains a human readable copyright notice
 	 * for the resource. See the {@code Bundle-Copyright} manifest header.
 	 */
diff --git a/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java b/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java
index fc91420..4376082 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2012, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2020). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
  * 
  * @Immutable
  * @since 1.1
- * @author $Id$
+ * @author $Id: f252fb2850001968fe0ee4e741a66847560dce33 $
  */
 public final class NativeNamespace extends Namespace {
 
@@ -44,7 +44,7 @@
 	 * The capability attribute contains alias values of the
 	 * {@link Constants#FRAMEWORK_OS_NAME org.osgi.framework.os.name} launching
 	 * property value according to the
-	 * <a href="https://www.osgi.org/developer/specifications/reference/">OSGi
+	 * <a href="https://docs.osgi.org/reference/">OSGi
 	 * Specification References</a>. The value of this attribute must be of type
 	 * {@code List<String>}.
 	 */
@@ -62,7 +62,7 @@
 	 * The capability attribute contains alias values of the
 	 * {@link Constants#FRAMEWORK_PROCESSOR org.osgi.framework.processor}
 	 * launching property value according to the
-	 * <a href="https://www.osgi.org/developer/specifications/reference/">OSGi
+	 * <a href="https://docs.osgi.org/reference/">OSGi
 	 * Specification References</a>. The value of this attribute must be of type
 	 * {@code List<String>}.
 	 */
diff --git a/framework/src/main/java/org/osgi/framework/namespace/package-info.java b/framework/src/main/java/org/osgi/framework/namespace/package-info.java
index e89f34a..78fec59 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2012, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2019). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,17 +15,17 @@
  */
 
 /**
- * Namespace Package Version 1.1.
+ * Namespace Package Version 1.2.
  * 
  * <p>
  * Bundles should not need to import this package at runtime since all
  * the types in this package just contain constants for capability and 
  * requirement namespaces specified by the OSGi Alliance.
  * 
- * @author $Id$
+ * @author $Id: 43f3804d39ad166dc082926b3a3679be67962fcc $
  */
 
-@Version("1.1")
+@Version("1.2")
 package org.osgi.framework.namespace;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/framework/src/main/java/org/osgi/framework/package-info.java b/framework/src/main/java/org/osgi/framework/package-info.java
index 818d4ae..44ad83a 100644
--- a/framework/src/main/java/org/osgi/framework/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) OSGi Alliance (2010, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2019). All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,19 +15,19 @@
  */
 
 /**
- * Framework Package Version 1.9.
+ * Framework Package Version 1.10.
  * <p>
  * Bundles wishing to use this package must list the package in the
  * Import-Package header of the bundle's manifest.
  * <p>
  * Example import for consumers using the API in this package:
  * <p>
- * {@code  Import-Package: org.osgi.framework; version="[1.9,2.0)"}
+ * {@code  Import-Package: org.osgi.framework; version="[1.10,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: 5b7956509a6fcf8b3f7ad23ca343dcae27cf37c6 $
  */
 
-@Version("1.9")
+@Version("1.10")
 package org.osgi.framework;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java b/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java
index 81430e2..c36575b 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java
@@ -26,7 +26,7 @@
  * An installed Bundle can be adapted to provide a {@code BundleStartLevelDTO}
  * for the Bundle.
  * 
- * @author $Id$
+ * @author $Id: 81430e24483d75fd406e57214284ec43b4b3f6a7 $
  * @NotThreadSafe
  */
 public class BundleStartLevelDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java b/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java
index 2d1de40..cf9ff88 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java
@@ -26,7 +26,7 @@
  * The System Bundle can be adapted to provide a {@code FrameworkStartLevelDTO}
  * for the framework of the Bundle.
  * 
- * @author $Id$
+ * @author $Id: 2d1de40ba2b1d12832ebe0e5cdd4f789d439b6f6 $
  * @NotThreadSafe
  */
 public class FrameworkStartLevelDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java b/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java
index 62262c5..cef11d9 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java
@@ -32,7 +32,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.startlevel.dto; version="[1.0,1.1)"}
  * 
- * @author $Id$
+ * @author $Id: 62262c52e6446fbe4a7b29725881f01791396c29 $
  */
 
 @Version("1.0")
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/package-info.java b/framework/src/main/java/org/osgi/framework/startlevel/package-info.java
index 27d775b..3265948 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/package-info.java
@@ -73,7 +73,7 @@
  * Import-Package: org.osgi.framework.startlevel; version=&quot;[1.0,2.0)&quot;
  * </pre>
  * 
- * @author $Id$
+ * @author $Id: 27d775bbe53df5e1dd5d7fe6f5e1c95b294c2301 $
  */
 
 @Version("1.0")
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java
index 43d7416..1358b2a 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java
@@ -28,7 +28,7 @@
  * in use revisions of the Bundle can be obtained by adapting the bundle to
  * {@code BundleRevisionDTO[]}.
  * 
- * @author $Id$
+ * @author $Id: 43d74167b8b59468b148ceb9dcde4509b68c2a90 $
  * @NotThreadSafe
  */
 public class BundleRevisionDTO extends ResourceDTO {
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java
index ef923b4..b55e634 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java
@@ -26,7 +26,7 @@
  * <p>
  * {@code BundleWireDTO}s are referenced {@link BundleWiringDTO.NodeDTO}s.
  * 
- * @author $Id$
+ * @author $Id: ef923b41460de6d3e34fad73dc794a788533c1e9 $
  * @NotThreadSafe
  */
 public class BundleWireDTO extends WireDTO {
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java
index e23e80f..a95c185 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java
@@ -30,7 +30,7 @@
  * wirings of the Bundle can be obtained by adapting the bundle to
  * {@code BundleWiringDTO[]}.
  * 
- * @author $Id$
+ * @author $Id: e23e80fcf8a14cbc9f565ec146821a4f22f2731b $
  * @NotThreadSafe
  */
 public class BundleWiringDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java b/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java
index 47eb1ee..6a41ae5 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java
@@ -30,7 +30,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.framework.wiring.dto; version="[1.3,1.4)"}
  * 
- * @author $Id$
+ * @author $Id: 47eb1eed801ba77d58d8807aa85e9e000bca00d0 $
  */
 
 @Version("1.3")
diff --git a/framework/src/main/java/org/osgi/framework/wiring/package-info.java b/framework/src/main/java/org/osgi/framework/wiring/package-info.java
index 6fb7232..199d60c 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/package-info.java
@@ -25,7 +25,7 @@
  * Import-Package: org.osgi.framework.wiring; version=&quot;[1.2,2.0)&quot;
  * </pre>
  * 
- * @author $Id$
+ * @author $Id: 6fb7232ca6c7b389c20f75566a46c4022b8dd5d5 $
  */
 
 @Version("1.2")
diff --git a/framework/src/main/java/org/osgi/resource/dto/CapabilityDTO.java b/framework/src/main/java/org/osgi/resource/dto/CapabilityDTO.java
index 1f7fad1..941ec8f 100644
--- a/framework/src/main/java/org/osgi/resource/dto/CapabilityDTO.java
+++ b/framework/src/main/java/org/osgi/resource/dto/CapabilityDTO.java
@@ -23,7 +23,7 @@
 /**
  * Data Transfer Object for a Capability.
  * 
- * @author $Id$
+ * @author $Id: CapabilityDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
  * @NotThreadSafe
  */
 public class CapabilityDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/resource/dto/CapabilityRefDTO.java b/framework/src/main/java/org/osgi/resource/dto/CapabilityRefDTO.java
index 81d5b85..4a94459 100644
--- a/framework/src/main/java/org/osgi/resource/dto/CapabilityRefDTO.java
+++ b/framework/src/main/java/org/osgi/resource/dto/CapabilityRefDTO.java
@@ -21,7 +21,7 @@
 /**
  * Data Transfer Object for a reference to a Capability.
  * 
- * @author $Id$
+ * @author $Id: CapabilityRefDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
  * @NotThreadSafe
  */
 public class CapabilityRefDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/resource/dto/RequirementDTO.java b/framework/src/main/java/org/osgi/resource/dto/RequirementDTO.java
index dfa21db..d8e02a0 100644
--- a/framework/src/main/java/org/osgi/resource/dto/RequirementDTO.java
+++ b/framework/src/main/java/org/osgi/resource/dto/RequirementDTO.java
@@ -23,7 +23,7 @@
 /**
  * Data Transfer Object for a Requirement.
  * 
- * @author $Id$
+ * @author $Id: RequirementDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
  * @NotThreadSafe
  */
 public class RequirementDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/resource/dto/RequirementRefDTO.java b/framework/src/main/java/org/osgi/resource/dto/RequirementRefDTO.java
index 8f913a7..9f8c316 100644
--- a/framework/src/main/java/org/osgi/resource/dto/RequirementRefDTO.java
+++ b/framework/src/main/java/org/osgi/resource/dto/RequirementRefDTO.java
@@ -21,7 +21,7 @@
 /**
  * Data Transfer Object for a reference to a Requirement.
  * 
- * @author $Id$
+ * @author $Id: RequirementRefDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
  * @NotThreadSafe
  */
 public class RequirementRefDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/resource/dto/ResourceDTO.java b/framework/src/main/java/org/osgi/resource/dto/ResourceDTO.java
index 377b7af..5e35165 100644
--- a/framework/src/main/java/org/osgi/resource/dto/ResourceDTO.java
+++ b/framework/src/main/java/org/osgi/resource/dto/ResourceDTO.java
@@ -23,7 +23,7 @@
 /**
  * Data Transfer Object for a Resource.
  * 
- * @author $Id$
+ * @author $Id: ResourceDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
  * @NotThreadSafe
  */
 public class ResourceDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/resource/dto/WireDTO.java b/framework/src/main/java/org/osgi/resource/dto/WireDTO.java
index 017ea7c..00b61d8 100644
--- a/framework/src/main/java/org/osgi/resource/dto/WireDTO.java
+++ b/framework/src/main/java/org/osgi/resource/dto/WireDTO.java
@@ -22,7 +22,7 @@
 /**
  * Data Transfer Object for a Wire.
  * 
- * @author $Id$
+ * @author $Id: WireDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
  * @NotThreadSafe
  */
 public class WireDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/resource/dto/WiringDTO.java b/framework/src/main/java/org/osgi/resource/dto/WiringDTO.java
index 8dc3844..4484658 100644
--- a/framework/src/main/java/org/osgi/resource/dto/WiringDTO.java
+++ b/framework/src/main/java/org/osgi/resource/dto/WiringDTO.java
@@ -23,7 +23,7 @@
 /**
  * Data Transfer Object for a Wiring node.
  * 
- * @author $Id$
+ * @author $Id: WiringDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
  * @NotThreadSafe
  */
 public class WiringDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/resource/dto/package-info.java b/framework/src/main/java/org/osgi/resource/dto/package-info.java
index 6e316cd..de4e2c9 100644
--- a/framework/src/main/java/org/osgi/resource/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/resource/dto/package-info.java
@@ -32,7 +32,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.resource.dto; version="[1.0,1.1)"}
  * 
- * @author $Id$
+ * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
  */
 
 @Version("1.0")
diff --git a/framework/src/main/java/org/osgi/resource/package-info.java b/framework/src/main/java/org/osgi/resource/package-info.java
index c537ca9..c0349ff 100644
--- a/framework/src/main/java/org/osgi/resource/package-info.java
+++ b/framework/src/main/java/org/osgi/resource/package-info.java
@@ -25,7 +25,7 @@
  * Import-Package: org.osgi.resource; version=&quot;[1.0,2.0)&quot;
  * </pre>
  * 
- * @author $Id$
+ * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
  */
 
 @Version("1.0")
diff --git a/framework/src/main/java/org/osgi/service/condition/Condition.java b/framework/src/main/java/org/osgi/service/condition/Condition.java
new file mode 100755
index 0000000..fcd6da8
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/condition/Condition.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) OSGi Alliance (2020). All Rights Reserved.
+ * 
+ * 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 org.osgi.service.condition;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Condition Service interface.
+ * <p>
+ * In dynamic systems, such as OSGi, one of the more challenging problems can be
+ * to define when a system or part of it is ready to do work. The answer can
+ * change depending on the individual perspective. The developer of a web server
+ * might say, the system is ready when the server starts listening on port 80.
+ * An application developer however would define the system as ready when the
+ * database connection is up and all servlets are registered. Taking the
+ * application developers view, the web server should start listening on port 80
+ * when the application is ready and not beforehand.
+ * <p>
+ * The {@code Condition} service interface is a marker interface designed to
+ * address this issue. Its role is to provide a dependency that can be tracked.
+ * It acts as a defined signal to other services.
+ * <p>
+ * A {@code Condition} service must be registered with the
+ * {@link Condition#CONDITION_ID} service property.
+ * 
+ * @ThreadSafe
+ * @author $Id: 9736e5e1c38c45254f733d73ed7ae2c0e253f544 $
+ */
+@ConsumerType
+public interface Condition {
+
+	/**
+	 * Service property identifying a condition's unique identifier.
+	 * <p>
+	 * Since a {@code Condition} service can potentially describe more then one
+	 * condition, the type of this service property is {@code String+}.
+	 */
+	String		CONDITION_ID		= "osgi.condition.id";
+
+	/**
+	 * The unique identifier for the default True condition.
+	 * <p>
+	 * The default True condition is registered by the framework during
+	 * framework initialization and therefore can always be relied upon.
+	 * 
+	 * @see Condition#CONDITION_ID
+	 */
+	String		CONDITION_ID_TRUE	= "true";
+
+	/**
+	 * A condition instance that can be used to register {@code Condition}
+	 * services.
+	 * <p>
+	 * This can be helpful to avoid a bundle having to implement this interface
+	 * to register a {@code Condition} service
+	 */
+	Condition	INSTANCE			= new ConditionImpl();
+}
+
+final class ConditionImpl implements Condition {
+	ConditionImpl() {
+	}
+}
diff --git a/framework/src/main/java/org/osgi/service/condition/package-info.java b/framework/src/main/java/org/osgi/service/condition/package-info.java
new file mode 100755
index 0000000..a3ddce5
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/condition/package-info.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) OSGi Alliance (2020). All Rights Reserved.
+ * 
+ * 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.
+ */
+
+/**
+ * Condition Service Package Version 1.0.
+ * <p>
+ * Bundles wishing to use this package must list the package in the
+ * Import-Package header of the bundle's manifest. This package has two types of
+ * users: the consumers that use the API in this package and the providers that
+ * implement the API in this package.
+ * <p>
+ * Example import for consumers using the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.condition; version="[1.0,2.0)"}
+ * <p>
+ * Example import for providers implementing the API in this package:
+ * <p>
+ * {@code  Import-Package: org.osgi.service.condition; version="[1.0,1.1)"}
+ * 
+ * @author $Id: 52df94eac922bd9d4f2f680cdd98e6d405844958 $
+ */
+
+@Version("1.0")
+package org.osgi.service.condition;
+
+import org.osgi.annotation.versioning.Version;
diff --git a/framework/src/main/java/org/osgi/service/packageadmin/package-info.java b/framework/src/main/java/org/osgi/service/packageadmin/package-info.java
index 41bb8d3..1baf3bd 100644
--- a/framework/src/main/java/org/osgi/service/packageadmin/package-info.java
+++ b/framework/src/main/java/org/osgi/service/packageadmin/package-info.java
@@ -31,7 +31,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.service.packageadmin; version="[1.2,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: package-info.java 1825132 2018-02-23 15:11:00Z pauls $
  */
 
 @Version("1.2")
diff --git a/framework/src/main/java/org/osgi/service/startlevel/package-info.java b/framework/src/main/java/org/osgi/service/startlevel/package-info.java
index 70b62bd..c0954f1 100644
--- a/framework/src/main/java/org/osgi/service/startlevel/package-info.java
+++ b/framework/src/main/java/org/osgi/service/startlevel/package-info.java
@@ -31,7 +31,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.service.startlevel; version="[1.1,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: package-info.java 1825132 2018-02-23 15:11:00Z pauls $
  */
 
 @Version("1.1")
diff --git a/framework/src/main/java/org/osgi/service/url/package-info.java b/framework/src/main/java/org/osgi/service/url/package-info.java
index 7053546..3e73e2b 100644
--- a/framework/src/main/java/org/osgi/service/url/package-info.java
+++ b/framework/src/main/java/org/osgi/service/url/package-info.java
@@ -26,7 +26,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.service.url; version="[1.0,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
  */
 
 @Version("1.0")
diff --git a/framework/src/main/java/org/osgi/util/tracker/ServiceTracker.java b/framework/src/main/java/org/osgi/util/tracker/ServiceTracker.java
index 42c176c..45b1f32 100644
--- a/framework/src/main/java/org/osgi/util/tracker/ServiceTracker.java
+++ b/framework/src/main/java/org/osgi/util/tracker/ServiceTracker.java
@@ -20,6 +20,7 @@
 import java.util.Collections;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
 
 import org.osgi.annotation.versioning.ConsumerType;
 import org.osgi.framework.AllServiceListener;
@@ -493,7 +494,7 @@
 			return object;
 		}
 
-		final long endTime = (timeout == 0) ? 0 : (System.currentTimeMillis() + timeout);
+		final long endTime = (timeout == 0) ? 0 : (TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) + timeout);
 		do {
 			final Tracked t = tracked();
 			if (t == null) { /* if ServiceTracker is not open */
@@ -506,7 +507,7 @@
 			}
 			object = getService();
 			if (endTime > 0) { // if we have a timeout
-				timeout = endTime - System.currentTimeMillis();
+				timeout = endTime - TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
 				if (timeout <= 0) { // that has expired
 					break;
 				}
diff --git a/framework/src/main/java/org/osgi/util/tracker/package-info.java b/framework/src/main/java/org/osgi/util/tracker/package-info.java
index b72e066..b0007b8 100644
--- a/framework/src/main/java/org/osgi/util/tracker/package-info.java
+++ b/framework/src/main/java/org/osgi/util/tracker/package-info.java
@@ -26,7 +26,7 @@
  * <p>
  * {@code  Import-Package: org.osgi.util.tracker; version="[1.5,2.0)"}
  * 
- * @author $Id$
+ * @author $Id: package-info.java 1825132 2018-02-23 15:11:00Z pauls $
  */
 
 @Version("1.5.2")
diff --git a/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/native-image.properties b/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/native-image.properties
new file mode 100644
index 0000000..85eb4e1
--- /dev/null
+++ b/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/native-image.properties
@@ -0,0 +1,5 @@
+Args = --initialize-at-build-time=\
+org.apache.felix.framework.util.Util,\
+org.apache.felix.framework.util.SecureAction,\
+org.apache.felix.framework.BundleWiringImpl,\
+org.apache.felix.framework.BundleRevisionImpl
diff --git a/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/reflect-config.json b/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/reflect-config.json
new file mode 100644
index 0000000..b1bc8ad
--- /dev/null
+++ b/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/reflect-config.json
@@ -0,0 +1,27 @@
+[
+  {
+    "name":"org.osgi.framework.Version",
+    "allPublicConstructors" : true,
+    "allPublicMethods" : true
+  },
+  {
+    "name":"org.osgi.framework.VersionRange",
+    "allPublicConstructors" : true,
+    "allPublicMethods" : true
+  },
+  {
+    "name" : "java.net.URL",
+    "allPublicConstructors" : true,
+    "allPublicMethods" : true,
+    "allDeclaredMethods" : true,
+    "allPublicFields" : true,
+    "allDeclaredFields" : true
+  },
+  {
+    "name" : "java.net.URLStreamHandler",
+    "allPublicMethods" : true,
+    "allDeclaredMethods" : true,
+    "allPublicFields" : true,
+    "allDeclaredFields" : true
+  }
+]
diff --git a/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/resource-config.json b/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/resource-config.json
new file mode 100644
index 0000000..cfeeac1
--- /dev/null
+++ b/framework/src/main/resources/META-INF/native-image/org.apache.felix/org.apache.felix.framework/resource-config.json
@@ -0,0 +1,9 @@
+{
+  "resources":[
+    {"pattern":"META-INF/services/org.osgi.framework.connect.ConnectFrameworkFactory"},
+    {"pattern":"META-INF/services/org.osgi.framework.launch.FrameworkFactory"},
+    {"pattern":"default.properties"},
+    {"pattern":"org/apache/felix/framework/Felix.properties"},
+    {"pattern":"org/apache/felix/framework/util/accessor.bytes"}
+  ]
+}
diff --git a/framework/src/main/resources/META-INF/services/org.osgi.framework.connect.ConnectFrameworkFactory b/framework/src/main/resources/META-INF/services/org.osgi.framework.connect.ConnectFrameworkFactory
new file mode 100644
index 0000000..3708ae5
--- /dev/null
+++ b/framework/src/main/resources/META-INF/services/org.osgi.framework.connect.ConnectFrameworkFactory
@@ -0,0 +1 @@
+org.apache.felix.framework.FrameworkFactory
\ No newline at end of file
diff --git a/framework/src/main/resources/default.properties b/framework/src/main/resources/default.properties
index f6b4821..792bfdb 100644
--- a/framework/src/main/resources/default.properties
+++ b/framework/src/main/resources/default.properties
@@ -21,7 +21,7 @@
 
 # New-style generic execution environment capabilities.
 org.osgi.framework.system.capabilities= \
- ${dollar}{felix.service.caps} ${dollar}{eecap-${dollar}{java.specification.version}} ${dollar}{eecap-${dollar}{felix.detect.jpms}}
+ ${dollar}{felix.service.caps} ${dollar}{eecap-${dollar}{felix.detect.java.specification.version}} ${dollar}{eecap-${dollar}{felix.detect.jpms}}
  
 # Native Processor Aliases.  Format is felix.native.processor.alias.<normalized Processor Name>=alias1,alias2
 felix.native.processor.alias.68k=
@@ -69,6 +69,7 @@
 felix.native.osname.alias.windowsserver2008=windows server 2008,win32
 felix.native.osname.alias.windowsserver2012=windows server 2012,win32
 felix.native.osname.alias.windowsserver2016=windows server 2016,win32
+felix.native.osname.alias.windowsserver2019=windows server 2019,win32
 felix.native.osname.alias.win32=
 
 felix.service.caps=osgi.service; objectClass:List<String>=org.osgi.service.resolver.Resolver; uses:=org.osgi.service.resolver, \
@@ -87,7 +88,7 @@
 
 # Deprecated old-style execution environment properties.
 org.osgi.framework.executionenvironment= \
- ${dollar}{ee-${dollar}{java.specification.version}} ${dollar}{ee-${dollar}{felix.detect.jpms}}
+ ${dollar}{ee-${dollar}{felix.detect.java.specification.version}} ${dollar}{ee-${dollar}{felix.detect.jpms}}
 
 ee-1.8=JavaSE-1.8,JavaSE-1.7,JavaSE-1.6,J2SE-1.5,J2SE-1.4,J2SE-1.3, \
  J2SE-1.2,JRE-1.1,JRE-1.0,OSGi/Minimum-1.2,OSGi/Minimum-1.1, \
@@ -100,14 +101,20 @@
 
 # Default packages exported by system bundle.
 org.osgi.framework.system.packages=\
- org.osgi.framework;version="1.9", \
+ ${dollar}{osgi-exports} \
+ ${dollar}{jre-${dollar}{felix.detect.java.specification.version}} \
+ ${dollar}{jre-${dollar}{felix.detect.jpms}}
+
+osgi-exports= \
+ org.osgi.framework;version="1.10", \
+ org.osgi.framework.connect;version="1.0.0", \
  org.osgi.framework.dto;version="1.8";uses:="org.osgi.dto", \
  org.osgi.framework.hooks.bundle;version="1.1";uses:="org.osgi.framework", \
  org.osgi.framework.hooks.resolver;version="1.0";uses:="org.osgi.framework.wiring", \
  org.osgi.framework.hooks.service;version="1.1";uses:="org.osgi.framework", \
  org.osgi.framework.hooks.weaving;version="1.1";uses:="org.osgi.framework.wiring", \
  org.osgi.framework.launch;version="1.2";uses:="org.osgi.framework", \
- org.osgi.framework.namespace;version="1.1";uses:="org.osgi.resource", \
+ org.osgi.framework.namespace;version="1.2";uses:="org.osgi.resource", \
  org.osgi.framework.startlevel;version="1.0";uses:="org.osgi.framework", \
  org.osgi.framework.startlevel.dto;version="1.0";uses:="org.osgi.dto", \
  org.osgi.framework.wiring;version="1.2";uses:="org.osgi.framework,org.osgi.resource", \
@@ -119,9 +126,8 @@
  org.osgi.service.url;version="1.0", \
  org.osgi.service.resolver;version="1.1";uses:="org.osgi.resource", \
  org.osgi.util.tracker;version="1.5.2";uses:="org.osgi.framework", \
- org.osgi.dto;version="1.1" \
- ${dollar}{jre-${dollar}{felix.detect.java.specification.version}} \
- ${dollar}{jre-${dollar}{felix.detect.jpms}}
+ org.osgi.dto;version="1.1", \
+ org.osgi.service.condition;version="1.0"
 
 #
 # Java platform package export properties.
@@ -374,4 +380,4 @@
  java.util.function;version="${dollar}{felix.detect.java.version}", \
  java.util.stream;version="${dollar}{felix.detect.java.version}", \
  javax.crypto;uses:="javax.crypto.spec,javax.security.auth";version="${dollar}{felix.detect.java.version}", \
- javax.lang.model;uses:="javax.lang.model.element";version="${dollar}{felix.detect.java.version}"
\ No newline at end of file
+ javax.lang.model;uses:="javax.lang.model.element";version="${dollar}{felix.detect.java.version}"
diff --git a/framework/src/main/resources/org/apache/felix/framework/util/accessor.bytes b/framework/src/main/resources/org/apache/felix/framework/util/accessor.bytes
new file mode 100644
index 0000000..f395846
--- /dev/null
+++ b/framework/src/main/resources/org/apache/felix/framework/util/accessor.bytes
Binary files differ
diff --git a/framework/src/main/resources/org/apache/felix/framework/util/accessor.src b/framework/src/main/resources/org/apache/felix/framework/util/accessor.src
new file mode 100644
index 0000000..2fe3e07
--- /dev/null
+++ b/framework/src/main/resources/org/apache/felix/framework/util/accessor.src
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 java.net;
+
+import java.lang.reflect.AccessibleObject;
+import java.util.function.Consumer;
+
+public class Accessor implements Consumer<AccessibleObject[]>
+{
+    @Override
+    public void accept(AccessibleObject[] accessibleObjectStream)
+    {
+        AccessibleObject.setAccessible(accessibleObjectStream, true);
+    }
+}
diff --git a/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java b/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java
index a04fe4a..0861de8 100644
--- a/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/CollisionHookTest.java
@@ -214,7 +214,7 @@
 
         try
         {
-            new BundleImpl(felixMock, null, archive);
+            new BundleImpl(felixMock, new BundleImpl(), archive);
             fail("Should have thrown a BundleException because the collision hook is not enabled");
         }
         catch (BundleException be)
@@ -290,7 +290,7 @@
 
         try
         {
-            new BundleImpl(felixMock, null, archive);
+            new BundleImpl(felixMock, new BundleImpl(), archive);
             fail("Should have thrown a BundleException because the installed bundle is not unique");
         }
         catch (BundleException be)
diff --git a/framework/src/test/java/org/apache/felix/framework/ConnectTest.java b/framework/src/test/java/org/apache/felix/framework/ConnectTest.java
new file mode 100644
index 0000000..0a6c3f0
--- /dev/null
+++ b/framework/src/test/java/org/apache/felix/framework/ConnectTest.java
@@ -0,0 +1,369 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.felix.framework;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+
+import junit.framework.TestCase;
+import org.apache.felix.framework.util.StringMap;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.Version;
+import org.osgi.framework.connect.ConnectContent;
+import org.osgi.framework.connect.ModuleConnector;
+import org.osgi.framework.connect.ConnectModule;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.framework.wiring.FrameworkWiring;
+
+public class ConnectTest extends TestCase
+{
+    public void testSimpleConnect() throws Exception
+    {
+        File cacheDir = File.createTempFile("felix-cache", ".dir");
+        cacheDir.delete();
+        cacheDir.mkdirs();
+        String cache = cacheDir.getPath();
+
+        Map<String, String> params = new HashMap<String, String>();
+        params.put("felix.cache.profiledir", cache);
+        params.put("felix.cache.dir", cache);
+        params.put(Constants.FRAMEWORK_STORAGE, cache);
+
+
+        FrameworkFactory factory = new FrameworkFactory();
+        Framework framework = null;
+        try
+        {
+            final AtomicReference<String> version = new AtomicReference<String>("1.0.0");
+            ModuleConnector connectFactory = new ModuleConnector()
+            {
+                @Override
+                public void initialize(File storage, Map<String, String> configuration)
+                {
+
+                }
+
+                @Override
+                public Optional<ConnectModule> connect(String location) throws IllegalStateException
+                {
+                    return location.startsWith("connect:foo") ? Optional.of(new ConnectModule()
+                    {
+                        @Override
+                        public ConnectContent getContent() throws IOException
+                        {
+                            return new ConnectContent()
+                            {
+                                @Override
+                                public Optional<ConnectEntry> getEntry(String name)
+                                {
+
+                                    return "foo.txt".equals(name) ? Optional.of(
+                                        new ConnectEntry()
+                                        {
+                                            @Override
+                                            public String getName()
+                                            {
+                                                return name;
+                                            }
+
+                                            @Override
+                                            public long getContentLength()
+                                            {
+                                                return 0;
+                                            }
+
+                                            @Override
+                                            public long getLastModified()
+                                            {
+                                                return 0;
+                                            }
+
+                                            @Override
+                                            public InputStream getInputStream() throws IOException
+                                            {
+                                                return null;
+                                            }
+                                        }
+                                    ) : Optional.empty();
+                                }
+
+                                @Override
+                                public Iterable<String> getEntries()
+                                {
+                                    return Arrays.asList("foo.txt");
+                                }
+
+                                @Override
+                                public Optional<ClassLoader> getClassLoader()
+                                {
+                                    return Optional.of(getClass().getClassLoader());
+                                }
+
+                                @Override
+                                public void open() throws IOException
+                                {
+                                }
+
+                                @Override
+                                public void close() throws IOException
+                                {
+                                }
+
+                                @Override
+                                public Optional<Map<String, String>> getHeaders()
+                                {
+                                    Map<String, String> headers = new HashMap<String, String>();
+                                    headers.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+                                    headers.put(Constants.BUNDLE_SYMBOLICNAME, "connect.foo");
+                                    headers.put(Constants.BUNDLE_VERSION, version.get());
+                                    headers.put(Constants.EXPORT_PACKAGE, ConnectTest.class.getPackage().getName());
+                                    return Optional.of(headers);
+                                }
+                            };
+                        }
+
+
+                    }) : location.startsWith("connect:extension") ? Optional.of(new ConnectModule()
+                    {
+                        @Override
+                        public ConnectContent getContent() throws IOException
+                        {
+                            return new ConnectContent()
+                            {
+                                @Override
+                                public Optional<ConnectEntry> getEntry(String name)
+                                {
+
+                                    return "foo.txt".equals(name) ? Optional.of(
+                                        new ConnectEntry()
+                                        {
+                                            @Override
+                                            public String getName()
+                                            {
+                                                return name;
+                                            }
+
+                                            @Override
+                                            public long getContentLength()
+                                            {
+                                                return 0;
+                                            }
+
+                                            @Override
+                                            public long getLastModified()
+                                            {
+                                                return 0;
+                                            }
+
+                                            @Override
+                                            public InputStream getInputStream() throws IOException
+                                            {
+                                                return null;
+                                            }
+                                        }
+                                    ) : Optional.empty();
+                                }
+
+                                @Override
+                                public Iterable<String> getEntries()
+                                {
+                                    return Arrays.asList("foo.txt");
+                                }
+
+                                @Override
+                                public Optional<ClassLoader> getClassLoader()
+                                {
+                                    return Optional.of(getClass().getClassLoader());
+                                }
+
+                                @Override
+                                public void open() throws IOException
+                                {
+
+                                }
+
+                                @Override
+                                public void close() throws IOException
+                                {
+
+                                }
+
+                                @Override
+                                public Optional<Map<String, String>> getHeaders()
+                                {
+                                    Map<String, String> headers = new HashMap<String, String>();
+                                    headers.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+                                    headers.put(Constants.BUNDLE_SYMBOLICNAME, "connect.extension");
+                                    headers.put(Constants.BUNDLE_VERSION, "1.0.0");
+                                    headers.put(Constants.FRAGMENT_HOST, "system.bundle;extension:=framework");
+                                    return Optional.of(headers);
+                                }
+                            };
+                        }
+
+
+                    })
+                        : Optional.empty();
+                }
+
+                @Override
+                public Optional<BundleActivator> newBundleActivator()
+                {
+                    return Optional.empty();
+                }
+            };
+
+            framework = factory.newFramework(params, connectFactory);
+
+            framework.start();
+            Bundle b = framework.getBundleContext().installBundle("connect:foo");
+
+            TestCase.assertNotNull(b);
+            TestCase.assertEquals("connect.foo", b.getSymbolicName());
+            TestCase.assertEquals(b, framework.getBundleContext().getBundle("connect:foo"));
+
+            TestCase.assertNotNull(b.getEntry("foo.txt"));
+            TestCase.assertNull(b.getEntry("bar.txt"));
+
+            Bundle extension = framework.getBundleContext().installBundle("connect:extension");
+
+            TestCase.assertEquals(Bundle.RESOLVED, extension.getState());
+
+            framework.stop();
+            framework.waitForStop(1000);
+            framework = factory.newFramework(params, connectFactory);
+            framework.start();
+
+            b = framework.getBundleContext().getBundle("connect:foo");
+            assertNotNull(b);
+            TestCase.assertEquals("connect.foo", b.getSymbolicName());
+            TestCase.assertNotNull(b.getEntry("foo.txt"));
+            TestCase.assertNull(b.getEntry("bar.txt"));
+
+            TestCase.assertEquals(ConnectTest.class, b.loadClass(ConnectTest.class.getName()));
+
+            String mf = "Bundle-SymbolicName: connect.test\n"
+                + "Bundle-Version: 1.0.0\n"
+                + "Bundle-ManifestVersion: 2\n"
+                + "Import-Package: " + ConnectTest.class.getPackage().getName()
+                + "\n";
+
+            File bundleFile = createBundle(mf, cacheDir, StringMap.class);
+
+            Bundle b2 = framework.getBundleContext().installBundle(bundleFile.toURI().toURL().toString());
+            b2.start();
+            TestCase.assertEquals(Bundle.ACTIVE, b2.getState());
+            TestCase.assertEquals(ConnectTest.class, b2.loadClass(ConnectTest.class.getName()));
+            TestCase.assertNotSame(StringMap.class, b2.loadClass(StringMap.class.getName()));
+            TestCase.assertEquals(Version.parseVersion("1.0.0"), b.getVersion());
+            Version revVersion = b.adapt(BundleRevision.class).getVersion();
+
+            TestCase.assertEquals(b.adapt(BundleRevision.class),
+                b2.adapt(BundleWiring.class).getRequiredWires(PackageNamespace.PACKAGE_NAMESPACE).get(0).getProvider());
+
+            version.set("2.0.0");
+
+            b.update();
+
+            final CountDownLatch latch = new CountDownLatch(1);
+
+            framework.adapt(FrameworkWiring.class).refreshBundles(Arrays.asList(b), new FrameworkListener()
+            {
+                @Override
+                public void frameworkEvent(FrameworkEvent event)
+                {
+                    latch.countDown();
+                }
+            });
+
+            latch.await(1, TimeUnit.SECONDS);
+
+
+            TestCase.assertEquals(Version.parseVersion("2.0.0"), b.getVersion());
+
+            TestCase.assertEquals(Bundle.ACTIVE, b2.getState());
+            TestCase.assertEquals(ConnectTest.class, b2.loadClass(ConnectTest.class.getName()));
+            TestCase.assertNotSame(StringMap.class, b2.loadClass(StringMap.class.getName()));
+            TestCase.assertEquals(b.adapt(BundleRevision.class),
+                b2.adapt(BundleWiring.class).getRequiredWires(PackageNamespace.PACKAGE_NAMESPACE).get(0).getProvider());
+            TestCase.assertNotSame(revVersion, b2.adapt(BundleWiring.class).getRequiredWires(PackageNamespace.PACKAGE_NAMESPACE).get(0).getProvider());
+
+        }
+        finally
+        {
+            try
+            {
+                if (framework != null)
+                {
+                    framework.stop();
+                    framework.waitForStop(1000);
+                }
+            }
+            finally {
+                MultiReleaseVersionTest.deleteDir(cacheDir);
+            }
+        }
+    }
+
+    private static File createBundle(String manifest, File tempDir, Class... classes) throws IOException
+    {
+        File f = File.createTempFile("felix-bundle", ".jar", tempDir);
+
+        Manifest mf = new Manifest(new ByteArrayInputStream(manifest.getBytes("utf-8")));
+        mf.getMainAttributes().putValue("Manifest-Version", "1.0");
+
+        JarOutputStream os = new JarOutputStream(new FileOutputStream(f), mf);
+
+        for (Class c : classes)
+        {
+            String path = c.getName().replace('.', '/') + ".class";
+            os.putNextEntry(new ZipEntry(path));
+
+            InputStream is = c.getClassLoader().getResourceAsStream(path);
+            byte[] b = new byte[is.available()];
+            is.read(b);
+            is.close();
+            os.write(b);
+        }
+
+        os.close();
+        return f;
+    }
+}
diff --git a/framework/src/test/java/org/apache/felix/framework/LaunchTest.java b/framework/src/test/java/org/apache/felix/framework/LaunchTest.java
new file mode 100644
index 0000000..fcb6295
--- /dev/null
+++ b/framework/src/test/java/org/apache/felix/framework/LaunchTest.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.felix.framework;
+
+import junit.framework.TestCase;
+import org.apache.felix.framework.util.FelixConstants;
+import org.osgi.framework.*;
+import org.osgi.framework.connect.ConnectModule;
+import org.osgi.framework.connect.ModuleConnector;
+import org.osgi.framework.launch.Framework;
+import org.osgi.service.resolver.Resolver;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class LaunchTest extends TestCase
+{
+    public void testInit() throws Exception
+    {
+        Map params = new HashMap();
+        File cacheDir = File.createTempFile("felix-cache", ".dir");
+        cacheDir.delete();
+        cacheDir.mkdirs();
+        String cache = cacheDir.getPath();
+        params.put("felix.cache.profiledir", cache);
+        params.put("felix.cache.dir", cache);
+        params.put(FelixConstants.LOG_LOGGER_PROP, new Logger()
+        {
+            @Override
+            protected void doLogOut(int level, String s, Throwable throwable) {
+
+            }
+        });
+        params.put(Constants.FRAMEWORK_STORAGE, cache);
+
+        try
+        {
+            Framework f = new Felix(params, new ModuleConnector()
+            {
+                boolean first = true;
+                @Override
+                public void initialize(File storage, Map<String, String> configuration)
+                {
+                    if (first) {
+                        first = false;
+                        throw new IllegalStateException("Test");
+                    }
+                }
+
+                @Override
+                public Optional<ConnectModule> connect(String location)
+                {
+                    return Optional.empty();
+                }
+
+                @Override
+                public Optional<BundleActivator> newBundleActivator()
+                {
+                    return Optional.empty();
+                }
+            }){
+                boolean first = true;
+                @Override
+                synchronized BundleActivator getActivator()
+                {
+                    BundleActivator activator = super.getActivator();
+                    if (first) {
+                        first = false;
+                        return new BundleActivator() {
+                            @Override
+                            public void start(BundleContext context) throws Exception
+                            {
+                                activator.start(context);
+                                throw new IllegalStateException("TEst");
+                            }
+
+                            @Override
+                            public void stop(BundleContext context) throws Exception
+                            {
+                                activator.stop(context);
+                            }
+                        };
+                    }
+                    return super.getActivator();
+                }
+            };
+            try
+            {
+                f.init();
+                fail("Excepted init to fail");
+            }
+            catch (Exception ex)
+            {
+
+            }
+            assertEquals(Bundle.INSTALLED, f.getState());
+            try
+            {
+                f.init();
+                fail("Excepted init to fail");
+            }
+            catch (Exception ex)
+            {
+
+            }
+            assertEquals(Bundle.INSTALLED, f.getState());
+            f.init();
+            assertEquals(Bundle.STARTING, f.getState());
+            f.stop();
+            f.waitForStop(0);
+            assertEquals(Bundle.RESOLVED, f.getState());
+            f.init();
+            assertEquals(1,f.getBundleContext().getServiceReferences(Resolver.class, null).size());
+            assertEquals(Bundle.STARTING, f.getState());
+            f.start();
+            assertEquals(Bundle.ACTIVE, f.getState());
+            f.stop();
+            f.waitForStop(0);
+        }
+        finally
+        {
+            deleteDir(cacheDir);
+        }
+    }
+
+    private static void deleteDir(File root) throws IOException
+    {
+        if (root.isDirectory())
+        {
+            for (File file : root.listFiles())
+            {
+                deleteDir(file);
+            }
+        }
+        assertTrue(root.delete());
+    }
+}
diff --git a/framework/src/test/java/org/apache/felix/framework/MultiReleaseVersionTest.java b/framework/src/test/java/org/apache/felix/framework/MultiReleaseVersionTest.java
index 27ba50f..be40789 100644
--- a/framework/src/test/java/org/apache/felix/framework/MultiReleaseVersionTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/MultiReleaseVersionTest.java
@@ -122,7 +122,7 @@
         return f;
     }
 
-    private static void deleteDir(File root) throws IOException
+    public static void deleteDir(File root) throws IOException
     {
         if (root.isDirectory())
         {
diff --git a/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java b/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java
index ce1167c..19d6d07 100644
--- a/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/ResourceLoadingTest.java
@@ -35,7 +35,6 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
 import org.osgi.framework.launch.Framework;
-import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.framework.wiring.BundleWiring;
 
 public class ResourceLoadingTest extends TestCase
@@ -80,7 +79,8 @@
         cacheDir = null;
     }
 
-    public void testResourceLoadingWithHash() throws Exception {
+    public void testResourceLoadingWithHash() throws Exception
+    {
         String bmf = "Bundle-SymbolicName: cap.bundle\n"
             + "Bundle-Version: 1.2.3.Blah\n"
             + "Bundle-ManifestVersion: 2\n"
@@ -104,24 +104,74 @@
         assertNotNull(testBundle.getResource(name));
         assertNotNull(testBundle.getEntry(name));
 
-        BufferedReader reader = new BufferedReader(new InputStreamReader(testBundle.getResource(name).openStream()));
-        assertEquals("This is a Test", reader.readLine());
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(testBundle.getResource(name).openStream())))
+        {
+            assertEquals("This is a Test", reader.readLine());
+        }
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(testBundle.getEntry(name).openStream())))
+        {
+            assertEquals("This is a Test", reader.readLine());
+        }
 
-        reader = new BufferedReader(new InputStreamReader(testBundle.getEntry(name).openStream()));
-        assertEquals("This is a Test", reader.readLine());
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(testBundle.adapt(BundleWiring.class).getClassLoader().getResourceAsStream(name))))
+        {
+            assertEquals("This is a Test", reader.readLine());
+        }
 
-        reader = new BufferedReader(new InputStreamReader(testBundle.adapt(BundleWiring.class).getClassLoader().getResourceAsStream(name)));
-        assertEquals("This is a Test", reader.readLine());
-
-        reader = new BufferedReader(new InputStreamReader(testBundle.adapt(BundleWiring.class).getClassLoader().getResource(name).openStream()));
-        assertEquals("This is a Test", reader.readLine());
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(testBundle.adapt(BundleWiring.class).getClassLoader().getResource(name).openStream())))
+        {
+            assertEquals("This is a Test", reader.readLine());
+        }
 
         URL url = testBundle.adapt(BundleWiring.class).getClassLoader().getResource(name);
 
         URL testURL = new URL(url.getProtocol() + "://" +  url.getHost() + ":" +  url.getPort() + "/" + name);
 
-        reader = new BufferedReader(new InputStreamReader(testURL.openStream()));
-        assertEquals("This is a Test", reader.readLine());
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(testURL.openStream())))
+        {
+            assertEquals("This is a Test", reader.readLine());
+        }
+    }
+
+    public void testResourceLoadingWithDirectory() throws Exception
+    {
+        String bmf = "Bundle-SymbolicName: cap.bundle\n"
+                + "Bundle-Version: 1.2.3.Blah\n"
+                + "Bundle-ManifestVersion: 2\n"
+                + "Import-Package: org.osgi.framework\n";
+        File bundleFile = File.createTempFile("felix-bundle", ".jar", tempDir);
+
+        Manifest mf = new Manifest(new ByteArrayInputStream(bmf.getBytes("utf-8")));
+        mf.getMainAttributes().putValue("Manifest-Version", "1.0");
+        JarOutputStream os = new JarOutputStream(new FileOutputStream(bundleFile), mf);
+
+        String name = "bla/bli/blub";
+        os.putNextEntry(new ZipEntry("bla/"));
+        os.putNextEntry(new ZipEntry("bla/bli/"));
+        os.putNextEntry(new ZipEntry(name));
+        os.write("This is a Test".getBytes());
+        os.close();
+
+        Bundle testBundle = felix.getBundleContext().installBundle(bundleFile.toURI().toASCIIString());
+
+        testBundle.start();
+
+        assertEquals(Bundle.ACTIVE, testBundle.getState());
+        assertTrue(testBundle.getResource("bla").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getEntry("bla").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getResource("bla/").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getEntry("bla/").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getResource("bla/bli").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getEntry("bla/bli").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/bli").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getResource("bla/bli/").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getEntry("bla/bli/").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/bli/").toExternalForm().endsWith("/"));
+        assertTrue(testBundle.getResource("bla/bli/blub").toExternalForm().endsWith("/blub"));
+        assertTrue(testBundle.getEntry("bla/bli/blub").toExternalForm().endsWith("/blub"));
+        assertTrue(testBundle.adapt(BundleWiring.class).getClassLoader().getResource("bla/bli/blub").toExternalForm().endsWith("/blub"));
     }
 
     private static void deleteDir(File root) throws IOException
diff --git a/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java b/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java
index fc83cb1..5dbfb74 100644
--- a/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java
@@ -114,15 +114,15 @@
 
         output.close();
 
-        BundleArchive archive = cache.create(1, 1, "slip", new FileInputStream(bundle));
+        BundleArchive archive = cache.create(1, 1, "slip", new FileInputStream(bundle), null);
 
         testNoZipSlip(archive);
 
-        archive = cache.create(1, 1, bundle.toURI().toURL().toString(), null);
+        archive = cache.create(1, 1, bundle.toURI().toURL().toString(), null, null);
 
         testNoZipSlip(archive);
 
-        archive = cache.create(1, 1, "reference:" + bundle.toURI().toURL().toString(), null);
+        archive = cache.create(1, 1, "reference:" + bundle.toURI().toURL().toString(), null, null);
 
         testNoZipSlip(archive);
 
@@ -134,7 +134,7 @@
         test.createNewFile();
         test.deleteOnExit();
 
-        archive = cache.create(1, 1, "reference:" + dir.toURI().toURL().toString(), null);
+        archive = cache.create(1, 1, "reference:" + dir.toURI().toURL().toString(), null, null);
 
         testNoZipSlip(archive);
     }
@@ -172,7 +172,7 @@
 
     private void testBundle(String location, File file) throws Exception
     {
-        BundleArchive archive = cache.create(1, 1, location, file != null ? new FileInputStream(file) : null);
+        BundleArchive archive = cache.create(1, 1, location, file != null ? new FileInputStream(file) : null, null);
 
         assertNotNull(archive);
 
diff --git a/framework/src/test/java/org/apache/felix/framework/util/manifestparser/ManifestParserTest.java b/framework/src/test/java/org/apache/felix/framework/util/manifestparser/ManifestParserTest.java
index c95e021..93db1ce 100644
--- a/framework/src/test/java/org/apache/felix/framework/util/manifestparser/ManifestParserTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/util/manifestparser/ManifestParserTest.java
@@ -28,6 +28,9 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.felix.framework.BundleRevisionImpl;
+import org.apache.felix.framework.cache.ConnectContentContent;
+import org.apache.felix.framework.cache.Content;
 import org.apache.felix.framework.util.FelixConstants;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
@@ -35,6 +38,7 @@
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.Version;
+import org.osgi.framework.connect.ConnectContent;
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.namespace.NativeNamespace;
 import org.osgi.framework.wiring.BundleCapability;
@@ -62,7 +66,7 @@
     {
         Map<String, Object> headers = new HashMap<String, Object>();
         headers.put(Constants.BUNDLE_MANIFESTVERSION, "2");
-        headers.put(Constants.BUNDLE_SYMBOLICNAME, "abc;singleton:=true");
+        headers.put(Constants.BUNDLE_SYMBOLICNAME, "abc;singleton:=true;foo=bar;" + IdentityNamespace.CAPABILITY_TAGS_ATTRIBUTE + "=test");
         headers.put(Constants.BUNDLE_VERSION, "1.2.3.something");
         String copyright = "(c) 2013 Apache Software Foundation";
         headers.put(Constants.BUNDLE_COPYRIGHT, copyright);
@@ -72,7 +76,13 @@
         headers.put(Constants.BUNDLE_DOCURL, docurl);
         String license = "http://www.apache.org/licenses/LICENSE-2.0";
         headers.put("Bundle-License", license);
-        ManifestParser mp = new ManifestParser(null, null, null, headers);
+
+        BundleRevisionImpl mockBundleRevision = mock(BundleRevisionImpl.class);
+
+        Content connectContent = mock(ConnectContentContent.class);
+        when(mockBundleRevision.getContent()).thenReturn(connectContent);
+
+        ManifestParser mp = new ManifestParser(null, null, mockBundleRevision, headers);
 
         BundleCapability ic = findCapability(mp.getCapabilities(), IdentityNamespace.IDENTITY_NAMESPACE);
         assertEquals("abc", ic.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE));
@@ -82,6 +92,8 @@
         assertEquals(description, ic.getAttributes().get(IdentityNamespace.CAPABILITY_DESCRIPTION_ATTRIBUTE));
         assertEquals(docurl, ic.getAttributes().get(IdentityNamespace.CAPABILITY_DOCUMENTATION_ATTRIBUTE));
         assertEquals(license, ic.getAttributes().get(IdentityNamespace.CAPABILITY_LICENSE_ATTRIBUTE));
+        assertEquals(Arrays.asList("test", ConnectContent.TAG_OSGI_CONNECT), ic.getAttributes().get(IdentityNamespace.CAPABILITY_TAGS_ATTRIBUTE));
+        assertEquals("bar", ic.getAttributes().get("foo"));
 
         assertEquals(1, ic.getDirectives().size());
         assertEquals("true", ic.getDirectives().get(IdentityNamespace.CAPABILITY_SINGLETON_DIRECTIVE));
@@ -97,7 +109,10 @@
         		"osgi.native.osversion:Version=\"7.0\";"+
         		"osgi.native.processor:List<String>=\"x86-64,amd64,em64t,x86_64\";"+
         		"osgi.native.language=\"en\"");
-        BundleRevision mockBundleRevision = mock(BundleRevision.class);
+
+        BundleRevisionImpl mockBundleRevision = mock(BundleRevisionImpl.class);
+
+        when(mockBundleRevision.getContent()).thenReturn(null);
         when(mockBundleRevision.getSymbolicName()).thenReturn(FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME);
     	
         ManifestParser mp = new ManifestParser(null, null, mockBundleRevision, headers);
@@ -123,7 +138,9 @@
         headers.put(Constants.REQUIRE_CAPABILITY,
                 "com.example.other;theList:List<String>=\"one,two,three\";theLong:Long=999");
 
-        BundleRevision mockBundleRevision = mock(BundleRevision.class);
+        BundleRevisionImpl mockBundleRevision = mock(BundleRevisionImpl.class);
+
+        when(mockBundleRevision.getContent()).thenReturn(null);
 
         when(mockBundleRevision.getSymbolicName()).thenReturn("com.example.test.sample");
 
@@ -154,7 +171,10 @@
         String[] languages = {"en", "se"};
         String selectionFilter = "(com.acme.windowing=win32)";
         NativeLibraryClause clause = new NativeLibraryClause(libraryFiles, osNames, processors, osVersions, languages, selectionFilter);
-        BundleRevision owner = mock(BundleRevision.class);
+
+        BundleRevisionImpl owner = mock(BundleRevisionImpl.class);
+
+        when(owner.getContent()).thenReturn(null);
         nativeLibraryClauses.add(clause);
         
         List<BundleRequirement> nativeBundleReq = ManifestParser.convertNativeCode(owner, nativeLibraryClauses, false);
diff --git a/http/itest/pom.xml b/http/itest/pom.xml
index 14ce638..12c60c9 100644
--- a/http/itest/pom.xml
+++ b/http/itest/pom.xml
@@ -35,7 +35,7 @@
         <pax.exam.version>4.13.1</pax.exam.version>
         <pax.url.aether.version>2.6.2</pax.url.aether.version>
         <http.servlet.api.version>1.1.2</http.servlet.api.version>
-        <http.jetty.version>4.1.3-SNAPSHOT</http.jetty.version>
+        <http.jetty.version>4.1.7-SNAPSHOT</http.jetty.version>
     </properties>
 
     <build>
diff --git a/http/jetty/pom.xml b/http/jetty/pom.xml
index 7b4c677..e5bfe87 100644
--- a/http/jetty/pom.xml
+++ b/http/jetty/pom.xml
@@ -30,7 +30,7 @@
     <description>This is an implementation of the R7 OSGi Http Service and the R7 OSGi Http Whiteboard Specification</description>
 
     <artifactId>org.apache.felix.http.jetty</artifactId>
-    <version>4.1.3-SNAPSHOT</version>
+    <version>4.1.7-SNAPSHOT</version>
     <packaging>bundle</packaging>
     
     <scm>
@@ -42,7 +42,7 @@
     
     <properties>
         <felix.java.version>8</felix.java.version>
-        <jetty.version>9.4.32.v20200930</jetty.version>
+        <jetty.version>9.4.38.v20210224</jetty.version>
     </properties>
 
     <build>
@@ -408,7 +408,7 @@
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
-            <version>2.6</version>
+            <version>2.8.0</version>
         </dependency>
   <!-- Testing -->
         <dependency>
diff --git a/http/jetty/src/main/java/org/apache/felix/http/jetty/ConnectorFactory.java b/http/jetty/src/main/java/org/apache/felix/http/jetty/ConnectorFactory.java
index 5de3a84..13a5c5c 100644
--- a/http/jetty/src/main/java/org/apache/felix/http/jetty/ConnectorFactory.java
+++ b/http/jetty/src/main/java/org/apache/felix/http/jetty/ConnectorFactory.java
@@ -52,6 +52,7 @@
      * active in Jetty servers must be stopped and removed from these Jetty
      * servers.
      *
+     * @param server The Jetty server object
      * @return A configured Jetty {@code Connector} instance.
      */
     Connector createConnector(Server server);
diff --git a/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java b/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
index a067dde..d887ef3 100644
--- a/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
+++ b/http/jetty/src/main/java/org/apache/felix/http/jetty/internal/JettyService.java
@@ -454,7 +454,7 @@
         HttpConnectionFactory connFactory = new HttpConnectionFactory();
         configureHttpConnectionFactory(connFactory);
 
-        SslContextFactory sslContextFactory = new SslContextFactory.Server();
+        SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
         configureSslContextFactory(sslContextFactory);
 
         ServerConnector connector = new ServerConnector(
@@ -498,7 +498,7 @@
         return startConnector(connector);
     }
 
-    private void configureSslContextFactory(final SslContextFactory connector)
+    private void configureSslContextFactory(final SslContextFactory.Server connector)
     {
         if (this.config.getKeystoreType() != null)
         {
diff --git a/http/sslfilter/pom.xml b/http/sslfilter/pom.xml
index 613b799..6030563 100644
--- a/http/sslfilter/pom.xml
+++ b/http/sslfilter/pom.xml
@@ -112,7 +112,7 @@
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-servlet</artifactId>
-          <version>9.4.32.v20200930</version>
+          <version>9.4.35.v20201120</version>
           <scope>test</scope>
         </dependency>
 
diff --git a/inventory/changelog.txt b/inventory/changelog.txt
index fb8d64d..191a312 100644
--- a/inventory/changelog.txt
+++ b/inventory/changelog.txt
@@ -1,3 +1,11 @@
+Changes in 1.1.0
+----------------
+** Improvement
+    * [FELIX-6375] - Require Java 8 as minimum version
+** Bug
+    * [FELIX-6371] - JSONConfigurationWriter does not escape backslash and other chars
+
+
 Changes in 1.0.6
 ----------------
 ** Bug
@@ -37,4 +45,4 @@
 
 ** Task
     * [FELIX-3874] - Create new status printer module
-    * [FELIX-3970] - Remove unneeded hashCode and equals methods from PrinterMode
\ No newline at end of file
+    * [FELIX-3970] - Remove unneeded hashCode and equals methods from PrinterMode
diff --git a/inventory/pom.xml b/inventory/pom.xml
index 4b0f06b..3fc303f 100644
--- a/inventory/pom.xml
+++ b/inventory/pom.xml
@@ -22,13 +22,13 @@
     <parent>
         <groupId>org.apache.felix</groupId>
         <artifactId>felix-parent</artifactId>
-        <version>4</version>
+        <version>7</version>
         <relativePath>../pom/pom.xml</relativePath>
     </parent>
 
     <artifactId>org.apache.felix.inventory</artifactId>
     <packaging>bundle</packaging>
-    <version>1.0.7-SNAPSHOT</version>
+    <version>1.1.0-SNAPSHOT</version>
 
     <name>Apache Felix Inventory</name>
     <description>Apache Felix Inventory provides some mechanisms to get the current state of the system and therefore provides an inventory of the system.</description>
@@ -45,14 +45,14 @@
                 <artifactId>maven-javadoc-plugin</artifactId>
                 <configuration>
                     <excludePackageNames>
-                        *.impl
+                        org.apache.felix.inventory.impl:org.apache.felix.inventory.impl.helper:org.apache.felix.inventory.impl.webconsole
                     </excludePackageNames>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
-                <version>3.3.0</version>
+                <version>5.1.1</version>
                 <extensions>true</extensions>
                     <configuration>
                     <instructions>
@@ -68,9 +68,6 @@
                             javax.servlet.http;resolution:=optional,
                             *
                         </Import-Package>
-                        <Export-Package>
-                            org.apache.felix.inventory
-                        </Export-Package>
                         <DynamicImport-Package>
                             javax.servlet, javax.servlet.http
                         </DynamicImport-Package>
@@ -108,6 +105,8 @@
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
+            <version>4.13.1</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
index 6d53789..419b601 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
@@ -37,18 +37,19 @@
  *
  * The adapter simplifies accessing and working with the inventory printer.
  */
-public class InventoryPrinterAdapter implements InventoryPrinterHandler, Comparable
+public class InventoryPrinterAdapter implements InventoryPrinterHandler, Comparable<InventoryPrinterAdapter>
 {
 
     /**
      * Comparator for adapters based on the service ranking.
      */
-    public static final Comparator RANKING_COMPARATOR = new Comparator()
+    public static final Comparator<InventoryPrinterAdapter> RANKING_COMPARATOR = new Comparator<InventoryPrinterAdapter>()
     {
 
-        public int compare(final Object o1, final Object o2)
+        @Override
+        public int compare(final InventoryPrinterAdapter o1, final InventoryPrinterAdapter o2)
         {
-            return ((InventoryPrinterAdapter) o1).description.compareTo(((InventoryPrinterAdapter) o2).description);
+            return o1.description.compareTo(o2.description);
         }
     };
 
@@ -77,18 +78,20 @@
             final Object value = this.description.getServiceReference().getProperty(InventoryPrinter.WEBCONSOLE);
             if (value == null || !"false".equalsIgnoreCase(value.toString()))
             {
-                final Dictionary props = new Hashtable();
+                final Dictionary<String, Object> props = new Hashtable<>();
                 props.put(ConsoleConstants.PLUGIN_LABEL, "status-" + this.description.getName());
                 props.put(ConsoleConstants.PLUGIN_TITLE, this.description.getTitle());
                 props.put(ConsoleConstants.PLUGIN_CATEGORY, ConsoleConstants.WEB_CONSOLE_CATEGORY);
                 this.registration = context.registerService(ConsoleConstants.INTERFACE_SERVLET, new ServiceFactory()
                 {
 
+                    @Override
                     public void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object service)
                     {
                         // nothing to do
                     }
 
+                    @Override
                     public Object getService(final Bundle bundle, final ServiceRegistration registration)
                     {
                         return new WebConsolePlugin(manager, description.getName());
@@ -111,6 +114,7 @@
     /**
      * The human readable title for the inventory printer.
      */
+    @Override
     public String getTitle()
     {
         return this.description.getTitle();
@@ -119,6 +123,7 @@
     /**
      * The unique name of the printer.
      */
+    @Override
     public String getName()
     {
         return this.description.getName();
@@ -127,6 +132,7 @@
     /**
      * All supported formats.
      */
+    @Override
     public Format[] getFormats()
     {
         return this.description.getFormats();
@@ -136,6 +142,7 @@
      * @see org.apache.felix.inventory.ZipAttachmentProvider#addAttachments(java.util.zip.ZipOutputStream,
      *      java.lang.String)
      */
+    @Override
     public void addAttachments(final ZipOutputStream zos, final String namePrefix) throws IOException
     {
         if (printer instanceof ZipAttachmentProvider)
@@ -147,6 +154,7 @@
     /**
      * Whether the printer supports this format.
      */
+    @Override
     public boolean supports(final Format format)
     {
         for (int i = 0; i < this.description.getFormats().length; i++)
@@ -163,6 +171,7 @@
      * @see org.apache.felix.inventory.InventoryPrinter#print(org.apache.felix.inventory.Format,
      *      java.io.PrintWriter)
      */
+    @Override
     public void print(final PrintWriter printWriter, final Format format, final boolean isZip)
     {
         if (this.supports(format))
@@ -176,21 +185,28 @@
         return this.description;
     }
 
-    public int compareTo(final Object spa)
+    @Override
+    public int compareTo(final InventoryPrinterAdapter spa)
     {
-        return this.description.getSortKey().compareTo(((InventoryPrinterAdapter) spa).description.getSortKey());
+        return this.description.getSortKey().compareTo(spa.description.getSortKey());
     }
 
+    @Override
     public int hashCode()
     {
         return this.description.getSortKey().hashCode();
     }
 
+    @Override
     public boolean equals(final Object spa)
     {
+        if ( !(spa instanceof InventoryPrinterAdapter)) {
+            return false;
+        }
         return this.description.getSortKey().equals(((InventoryPrinterAdapter) spa).description.getSortKey());
     }
 
+    @Override
     public String toString()
     {
         return printer.getClass() + "(" + super.toString() + ")";
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterDescription.java b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterDescription.java
index c2fe3fa..fc2e4bf 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterDescription.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterDescription.java
@@ -18,15 +18,17 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import org.apache.felix.inventory.InventoryPrinter;
+import java.util.List;
+
 import org.apache.felix.inventory.Format;
+import org.apache.felix.inventory.InventoryPrinter;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
 /**
  * Helper class for a configuration printer.
  */
-public class InventoryPrinterDescription implements Comparable
+public class InventoryPrinterDescription implements Comparable<InventoryPrinterDescription>
 {
 
     private final ServiceReference reference;
@@ -58,7 +60,7 @@
         else if (formatsCfg instanceof String[])
         {
             final String[] formatsCfgArray = (String[]) formatsCfg;
-            final ArrayList formatList = new ArrayList();
+            final List<Format> formatList = new ArrayList<>();
             for (int i = 0; i < formatsCfgArray.length; i++)
             {
                 final Format format = Format.valueOf(formatsCfgArray[i]);
@@ -69,7 +71,7 @@
             }
             if (!formatList.isEmpty())
             {
-                formats = (Format[]) formatList.toArray(new Format[formatList.size()]);
+                formats = formatList.toArray(new Format[formatList.size()]);
             }
         }
 
@@ -146,21 +148,25 @@
     /**
      * @see java.lang.Comparable#compareTo(java.lang.Object)
      */
-    public int compareTo(final Object spa)
+    @Override
+    public int compareTo(final InventoryPrinterDescription spa)
     {
-        return this.reference.compareTo(((InventoryPrinterDescription) spa).reference);
+        return this.reference.compareTo(spa.reference);
     }
 
+    @Override
     public boolean equals(final Object obj)
     {
         return this.reference.equals(obj);
     }
 
+    @Override
     public int hashCode()
     {
         return this.reference.hashCode();
     }
 
+    @Override
     public String toString()
     {
         return "InventoryPrinterDescription [title=" + title + ", name=" + name + ", formats=" + Arrays.asList(formats)
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
index 327caf6..abd7508 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
@@ -25,7 +25,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeSet;
 
@@ -46,23 +45,22 @@
  * based on their name. If more than one printer with the same name
  * is registered, the one with highest service ranking is used.
  */
-public class InventoryPrinterManagerImpl implements ServiceTrackerCustomizer
+public class InventoryPrinterManagerImpl implements ServiceTrackerCustomizer<InventoryPrinter, InventoryPrinter>
 {
 
     /** Bundle Context . */
     private final BundleContext bundleContext;
 
     /** Service tracker for Inventory printers. */
-    private final ServiceTracker cfgPrinterTracker;
+    private final ServiceTracker<InventoryPrinter, InventoryPrinter> cfgPrinterTracker;
 
     /**
-     * All adapters mapped by their name. Type of the map: String,
-     * List<InventoryPrinterAdapter>
+     * All adapters mapped by their name.
      */
-    private final Map allAdapters = new HashMap();
+    private final Map<String, List<InventoryPrinterAdapter>> allAdapters = new HashMap<>();
 
-    /** Used adapters. Type of the set: InventoryPrinterAdapter */
-    private final Set usedAdapters = new TreeSet();
+    /** Used adapters. */
+    private final Set<InventoryPrinterAdapter> usedAdapters = new TreeSet<>();
 
     /** Registration for the web console. */
     private final ServiceRegistration pluginRegistration;
@@ -77,20 +75,22 @@
     public InventoryPrinterManagerImpl(final BundleContext btx) throws InvalidSyntaxException
     {
         this.bundleContext = btx;
-        this.cfgPrinterTracker = new ServiceTracker(this.bundleContext, InventoryPrinter.SERVICE, this);
+        this.cfgPrinterTracker = new ServiceTracker<>(this.bundleContext, InventoryPrinter.class, this);
         this.cfgPrinterTracker.open();
 
-        final Dictionary props = new Hashtable();
+        final Dictionary<String, Object> props = new Hashtable<>();
         props.put(ConsoleConstants.PLUGIN_LABEL, ConsoleConstants.NAME);
         props.put(ConsoleConstants.PLUGIN_TITLE, ConsoleConstants.TITLE);
         props.put(ConsoleConstants.PLUGIN_CATEGORY, ConsoleConstants.WEB_CONSOLE_CATEGORY);
         this.pluginRegistration = btx.registerService(ConsoleConstants.INTERFACE_SERVLET, new ServiceFactory()
         {
+            @Override
             public void ungetService(final Bundle bundle, final ServiceRegistration registration, final Object service)
             {
                 // nothing to do
             }
 
+            @Override
             public Object getService(final Bundle bundle, final ServiceRegistration registration)
             {
                 return new DefaultWebConsolePlugin(InventoryPrinterManagerImpl.this);
@@ -121,12 +121,13 @@
     /**
      * @see org.osgi.util.tracker.ServiceTrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
      */
-    public Object addingService(final ServiceReference reference)
+    @Override
+    public InventoryPrinter addingService(final ServiceReference<InventoryPrinter> reference)
     {
-        final Object obj = this.bundleContext.getService(reference);
+        final InventoryPrinter obj = this.bundleContext.getService(reference);
         if (obj != null)
         {
-            this.addService(reference, (InventoryPrinter) obj);
+            this.addService(reference, obj);
         }
 
         return obj;
@@ -136,23 +137,25 @@
      * @see org.osgi.util.tracker.ServiceTrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference,
      *      java.lang.Object)
      */
-    public void modifiedService(final ServiceReference reference, final Object service)
+    @Override
+    public void modifiedService(final ServiceReference<InventoryPrinter> reference, final InventoryPrinter service)
     {
         this.removeService(reference);
-        this.addService(reference, (InventoryPrinter) service);
+        this.addService(reference, service);
     }
 
     /**
      * @see org.osgi.util.tracker.ServiceTrackerCustomizer#removedService(org.osgi.framework.ServiceReference,
      *      java.lang.Object)
      */
-    public void removedService(final ServiceReference reference, final Object service)
+    @Override
+    public void removedService(final ServiceReference<InventoryPrinter> reference, final InventoryPrinter service)
     {
         this.removeService(reference);
         this.bundleContext.ungetService(reference);
     }
 
-    private void addService(final ServiceReference reference, final InventoryPrinter obj)
+    private void addService(final ServiceReference<InventoryPrinter> reference, final InventoryPrinter obj)
     {
         final InventoryPrinterDescription desc = new InventoryPrinterDescription(reference);
         final InventoryPrinterAdapter adapter = new InventoryPrinterAdapter(desc, obj);
@@ -163,17 +166,17 @@
         final String key = adapter.getName();
         synchronized (this.allAdapters)
         {
-            List list = (List) this.allAdapters.get(key);
+            List<InventoryPrinterAdapter> list = this.allAdapters.get(key);
             final InventoryPrinterAdapter first;
             if (list == null)
             {
-                list = new LinkedList();
+                list = new LinkedList<>();
                 this.allAdapters.put(key, list);
                 first = null;
             }
             else
             {
-                first = (InventoryPrinterAdapter) list.get(0);
+                first = list.get(0);
             }
             list.add(adapter);
             Collections.sort(list, InventoryPrinterAdapter.RANKING_COMPARATOR);
@@ -210,19 +213,19 @@
         }
     }
 
-    private void removeService(final ServiceReference reference)
+    private void removeService(final ServiceReference<InventoryPrinter> reference)
     {
         synchronized (this.allAdapters)
         {
-            final Iterator i = this.allAdapters.entrySet().iterator();
+            final Iterator<Map.Entry<String, List<InventoryPrinterAdapter>>> i = this.allAdapters.entrySet().iterator();
             while (i.hasNext())
             {
-                final Map.Entry entry = (Entry) i.next();
-                final Iterator iter = ((List) entry.getValue()).iterator();
+                final Map.Entry<String, List<InventoryPrinterAdapter>> entry = i.next();
+                final Iterator<InventoryPrinterAdapter> iter = entry.getValue().iterator();
                 boolean removed = false;
                 while (iter.hasNext())
                 {
-                    final InventoryPrinterAdapter adapter = (InventoryPrinterAdapter) iter.next();
+                    final InventoryPrinterAdapter adapter = iter.next();
                     if (adapter.getDescription().getServiceReference().equals(reference))
                     {
                         iter.remove();
@@ -232,7 +235,7 @@
                 }
                 if (removed)
                 {
-                    if (((List) entry.getValue()).size() == 0)
+                    if (entry.getValue().size() == 0)
                     {
                         i.remove();
                     }
@@ -244,10 +247,10 @@
         InventoryPrinterAdapter adapterToUnregister = null;
         synchronized (this.usedAdapters)
         {
-            final Iterator iter = this.usedAdapters.iterator();
+            final Iterator<InventoryPrinterAdapter> iter = this.usedAdapters.iterator();
             while (iter.hasNext())
             {
-                final InventoryPrinterAdapter adapter = (InventoryPrinterAdapter) iter.next();
+                final InventoryPrinterAdapter adapter = iter.next();
                 if (adapter.getDescription().getServiceReference().equals(reference))
                 {
                     iter.remove();
@@ -275,20 +278,20 @@
      */
     public InventoryPrinterHandler[] getHandlers(final Format format)
     {
-        final List result = new ArrayList();
+        final List<InventoryPrinterAdapter> result = new ArrayList<>();
         synchronized (this.usedAdapters)
         {
-            final Iterator i = this.usedAdapters.iterator();
+            final Iterator<InventoryPrinterAdapter> i = this.usedAdapters.iterator();
             while (i.hasNext())
             {
-                final InventoryPrinterAdapter printer = (InventoryPrinterAdapter) i.next();
+                final InventoryPrinterAdapter printer = i.next();
                 if (format == null || printer.supports(format))
                 {
                     result.add(printer);
                 }
             }
         }
-        return (InventoryPrinterHandler[]) result.toArray(new InventoryPrinterHandler[result.size()]);
+        return result.toArray(new InventoryPrinterHandler[result.size()]);
     }
 
     /**
@@ -300,10 +303,10 @@
     {
         synchronized (this.usedAdapters)
         {
-            final Iterator i = this.usedAdapters.iterator();
+            final Iterator<InventoryPrinterAdapter> i = this.usedAdapters.iterator();
             while (i.hasNext())
             {
-                final InventoryPrinterAdapter printer = (InventoryPrinterAdapter) i.next();
+                final InventoryPrinterAdapter printer = i.next();
                 if (name.equals(printer.getName()))
                 {
                     return printer;
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java b/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java
index b21547b..5900f0d 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java
@@ -27,7 +27,6 @@
  */
 public class JSONConfigurationWriter extends ConfigurationWriter
 {
-
     private boolean wrapJSON;
 
     private boolean startLine;
@@ -71,6 +70,7 @@
     // IE has an issue with white-space:pre in our case so, we write
     // <br/> instead of [CR]LF to get the line break. This also works
     // in other browsers.
+    @Override
     public void println()
     {
         if (wrapJSON)
@@ -93,6 +93,7 @@
     // delegation to the write() method. So we need to override this, to
     // make
     // sure, that everything is escaped correctly
+    @Override
     public void print(final String str)
     {
         final char[] chars = str.toCharArray();
@@ -103,6 +104,7 @@
 
     // always delegate to write(char[], int, int) otherwise in some VM
     // it cause endless cycle and StackOverflowError
+    @Override
     public void write(final int character)
     {
         synchronized (oneChar)
@@ -112,8 +114,8 @@
         }
     }
 
-    // write the characters unmodified unless filtering is enabled in
-    // which case the writeFiltered(String) method is called for filtering
+    // write the characters unmodified unless filtering is enabled
+    @Override
     public void write(char[] chars, int off, int len)
     {
         if (this.wrapJSON)
@@ -125,14 +127,14 @@
             }
 
             String v = new String(chars, off, len);
-            StringTokenizer st = new StringTokenizer(v, "\r\n\"", true);
+            StringTokenizer st = new StringTokenizer(v, "\r\n\"\\\t\b\f", true);
             while (st.hasMoreTokens())
             {
                 String t = st.nextToken();
                 if (t.length() == 1)
                 {
                     char c = t.charAt(0);
-                    if (c == '\r')
+                    if (c == '\r' || c == '\f' || c == '\t' || c == '\b')
                     {
                         // ignore
                     }
@@ -141,7 +143,7 @@
                         this.println();
                         this.startLine();
                     }
-                    else if (c == '"')
+                    else if (c == '"' || c == '\\')
                     {
                         super.write('\\');
                         super.write(c);
@@ -165,6 +167,7 @@
 
     // write the string unmodified unless filtering is enabled in
     // which case the writeFiltered(String) method is called for filtering
+    @Override
     public void write(final String string, final int off, final int len)
     {
         write(string.toCharArray(), off, len);
diff --git a/inventory/src/test/java/org/apache/felix/inventory/FormatTest.java b/inventory/src/test/java/org/apache/felix/inventory/FormatTest.java
index 5d3131c..54a00ef 100644
--- a/inventory/src/test/java/org/apache/felix/inventory/FormatTest.java
+++ b/inventory/src/test/java/org/apache/felix/inventory/FormatTest.java
@@ -18,12 +18,14 @@
  */
 package org.apache.felix.inventory;
 
+import org.junit.Test;
+
 import junit.framework.TestCase;
 
-public class FormatTest extends TestCase
+public class FormatTest
 {
 
-    public void test_valueOf()
+    @Test public void test_valueOf()
     {
         TestCase.assertSame(Format.TEXT, Format.valueOf("TEXT"));
         TestCase.assertSame(Format.JSON, Format.valueOf("JSON"));
@@ -40,14 +42,14 @@
         TestCase.assertNull(Format.valueOf("unsupported_name"));
     }
 
-    public void test_toString()
+    @Test public void test_toString()
     {
         TestCase.assertEquals("TEXT", Format.TEXT.toString());
         TestCase.assertEquals("JSON", Format.JSON.toString());
         TestCase.assertEquals("HTML", Format.HTML.toString());
     }
 
-    public void test_equals()
+    @Test public void test_equals()
     {
         TestCase.assertTrue(Format.TEXT.equals(Format.TEXT));
         TestCase.assertFalse(Format.TEXT.equals(Format.JSON));
diff --git a/inventory/src/test/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriterTest.java b/inventory/src/test/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriterTest.java
new file mode 100644
index 0000000..8754b2a
--- /dev/null
+++ b/inventory/src/test/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriterTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.felix.inventory.impl.helper;
+
+import java.io.StringWriter;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JSONConfigurationWriterTest {
+
+    @Test public void test_escaping() {
+        final StringWriter out = new StringWriter();
+        final JSONConfigurationWriter w = new JSONConfigurationWriter(out);
+        w.startJSONWrapper();
+        w.write("abcd\\\n1\t2\f3\b4\"5end");
+        w.endJSONWrapper();
+        w.close();
+
+        final String expected = "[" + System.lineSeparator()
+                + "    \"abcd\\\\\"," + System.lineSeparator()
+                + "    \"1234\\\"5end\"]" + System.lineSeparator();
+
+        Assert.assertEquals("Escaped JSON", expected, out.toString());
+
+    }
+}
diff --git a/log/src/main/java/org/apache/felix/log/ConfigurationListenerImpl.java b/log/src/main/java/org/apache/felix/log/ConfigurationListenerImpl.java
index a90eb7c..2f7dc86 100644
--- a/log/src/main/java/org/apache/felix/log/ConfigurationListenerImpl.java
+++ b/log/src/main/java/org/apache/felix/log/ConfigurationListenerImpl.java
@@ -27,6 +27,7 @@
 import java.util.Dictionary;
 import java.util.List;
 
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Filter;
@@ -86,12 +87,17 @@
             m_caReference = caReference;
             m_ca = m_context.getService(m_caReference);
 
+            final Bundle bundle = m_caReference.getBundle();
+            if ( bundle == null )
+            {
+                throw new IllegalStateException("Service already unregistered again");
+            }
             try {
-                m_caClass = m_caReference.getBundle().loadClass(CONFIGURATION_ADMIN_CLASS);
+                m_caClass = bundle.loadClass(CONFIGURATION_ADMIN_CLASS);
                 m_caGetConfiguration = m_caClass.getMethod("getConfiguration", String.class, String.class);
                 m_caListConfigurations = m_caClass.getMethod("listConfigurations", String.class);
 
-                m_configurationClass = m_caReference.getBundle().loadClass(CONFIGURATION_CLASS);
+                m_configurationClass = bundle.loadClass(CONFIGURATION_CLASS);
                 m_configurationGetProperties = m_configurationClass.getMethod("getProperties");
                 Method configurationGetProcessedProperties = null;
                 try {
@@ -103,11 +109,11 @@
                 }
                 m_configurationGetProcessedProperties = configurationGetProcessedProperties;
 
-                m_ceClass = m_caReference.getBundle().loadClass(CONFIGURATION_EVENT_CLASS);
+                m_ceClass = bundle.loadClass(CONFIGURATION_EVENT_CLASS);
                 m_ceGetPid = m_ceClass.getMethod("getPid");
                 m_ceGetType = m_ceClass.getMethod("getType");
 
-                m_clClass = m_caReference.getBundle().loadClass(CONFIGURATION_LISTENER_CLASS);
+                m_clClass = bundle.loadClass(CONFIGURATION_LISTENER_CLASS);
                 m_clConfigurationEvent = m_clClass.getMethod("configurationEvent", m_ceClass);
             }
             catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
diff --git a/log/src/main/java/org/apache/felix/log/Log.java b/log/src/main/java/org/apache/felix/log/Log.java
index 73c1040..1172372 100644
--- a/log/src/main/java/org/apache/felix/log/Log.java
+++ b/log/src/main/java/org/apache/felix/log/Log.java
@@ -42,17 +42,19 @@
 final class Log implements BundleListener, FrameworkListener, ServiceListener
 {
     /** The first log entry. */
-    private LogNode m_head;
+    private volatile LogNode m_head;
     /** The last log entry. */
-    private LogNode m_tail;
+    private volatile LogNode m_tail;
     /** The log size. */
-    private int m_size;
+    private volatile int m_size;
     /** The log listener thread. */
-    private LogListenerThread listenerThread;
+    private volatile LogListenerThread listenerThread;
     /** The maximum size for the log. */
     private final int m_maxSize;
     /** Whether or not to store debug messages. */
     private final boolean m_storeDebug;
+    /** Active flag */
+    private volatile boolean active = true;
 
     /**
      * Create a new instance.
@@ -68,8 +70,9 @@
     /**
      * Close the log.
      */
-    void close()
+    synchronized void close()
     {
+        active = false;
         if (listenerThread != null)
         {
             listenerThread.shutdown();
@@ -98,6 +101,10 @@
      */
     synchronized void addEntry(final LogEntry entry)
     {
+        if ( !active )
+        {
+            return;
+        }
         if (m_maxSize != 0)
         {
             // add the entry to the historic log
@@ -152,14 +159,17 @@
      */
     synchronized void addListener(final LogListener listener)
     {
-        if (listenerThread == null)
+        if ( active )
         {
-            // create a new listener thread if necessary:
-            // the listener thread only runs if there are any registered listeners
-            listenerThread = new LogListenerThread();
-            listenerThread.start();
+            if (listenerThread == null)
+            {
+                // create a new listener thread if necessary:
+                // the listener thread only runs if there are any registered listeners
+                listenerThread = new LogListenerThread();
+                listenerThread.start();
+            }
+            listenerThread.addListener(listener);
         }
-        listenerThread.addListener(listener);
     }
 
     /**
diff --git a/main.distribution/NOTICE b/main.distribution/NOTICE
index 0901170..f072a43 100644
--- a/main.distribution/NOTICE
+++ b/main.distribution/NOTICE
@@ -1,5 +1,5 @@
 Apache Felix Main Distribution
-Copyright 2017 The Apache Software Foundation
+Copyright 2020 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/main.distribution/doc/changelog.txt b/main.distribution/doc/changelog.txt
index 1510d2c..09d7f15 100644
--- a/main.distribution/doc/changelog.txt
+++ b/main.distribution/doc/changelog.txt
@@ -1,3 +1,19 @@
+Changes from 6.0.4 to 7.0.0
+---------------------------
+
+** Improvement
+    * Update to latest framework and main version 7.0.0
+
+Changes from 6.0.3 to 6.0.4
+---------------------------
+
+** Improvement
+    * Update to latest framework and main version 6.0.4
+    * Update to latest gogo runtime 1.1.4
+    * Update to latest gogo.jline 1.1.8
+    * Update to latest jline 3.13.2
+    * Update to latest jansi 1.18
+
 Changes from 6.0.2 to 6.0.3
 ---------------------------
 
diff --git a/main.distribution/doc/changelog_framework.txt b/main.distribution/doc/changelog_framework.txt
index 4da82c6..b333393 100644
--- a/main.distribution/doc/changelog_framework.txt
+++ b/main.distribution/doc/changelog_framework.txt
@@ -1,3 +1,27 @@
+Changes from 6.0.4 to 7.0.0
+---------------------------
+
+** Improvement
+    * [FELIX-6369] - Implement R8 core spec
+    * [FELIX-6175] - default.properties resource file would conflict with other libraries
+
+** Bug
+    * [FELIX-5975] - URLHandlersStreamHandlerProxy - OPEN_CONNECTION_PROXY null
+    * [FELIX-6163] - ServiceTracker should not use System.currentTimeMillis() to check timeouts
+    * [FELIX-6184] - NoClassDefFoundError: jdk/internal/reflect/ConstructorAccessorImpl with Oracle JDK 11.0.3
+    * [FELIX-6294] - Missing trailing slash with Bundle.getResource() for directory entry
+
+Changes from 6.0.3 to 6.0.4
+---------------------------
+
+** Bug
+    * [FELIX-6178] - org.osgi.framework.Bundle#getServicesInUse returns services with usage count = 0
+    * [FELIX-6222] - Support for os.name Capability is missing for Windows Server 2019
+    * [FELIX-6297] - unclosed InputStream on Bundle.start
+    * [FELIX-6318] - Tiny thread-safety bug in BundleWiringImpl
+    * [FELIX-6326] - Cannot read bundled resources with hash in the filename
+    * [FELIX-6331] - Race condition in unget service from service factory
+
 Changes from 6.0.2 to 6.0.3
 ---------------------------
 
diff --git a/main.distribution/doc/changelog_gogo.command.txt b/main.distribution/doc/changelog_gogo.command.txt
index 8cdf240..d04d38a 100644
--- a/main.distribution/doc/changelog_gogo.command.txt
+++ b/main.distribution/doc/changelog_gogo.command.txt
@@ -1,4 +1,48 @@
-Changes from 0.10.0 to 0.12.0
+Changes from 1.1.0 to 1.1.2
+---------------------------
+Improvement
+    [FELIX-6038] - pull Java 7 support back in for gogo runtime,shell and console
+
+Changes from 1.0.2 to 1.1.0
+---------------------------
+Bug
+    [FELIX-5143] - Gogo Command bundle should not include org.osgi.service.log classes
+    [FELIX-5958] - gogo command exports org.osgi.service.log
+
+New Feature
+    [FELIX-5835] - Upgrade to JDK 8
+    [FELIX-5836] - Upgrade to OSGi r6
+
+Improvement
+    [FELIX-5969] - remove transitive dependencies from gogo command
+    [FELIX-5970] - Add requirement & capabilities model so gogo can be resolved
+    [FELIX-5999] - cleanup compiler warnings
+    [FELIX-6002] - Remove legacy code in Gogo Command
+    [FELIX-6003] - Add some resolver checks to make sure @RequireGogo annotation works for both jline and shell
+    [FELIX-6007] - create a gogo bom
+
+Changes from 1.0.0 to 1.0.2
+---------------------------
+** Bug
+    * [FELIX-5392] - Gogo-command has mandatory dependency on bundlerepository
+
+Changes from 0.16.0 to 1.0.0
+----------------------------
+** Task
+    * [FELIX-5378] - [gogo] Upgrade packages and bundle to 1.0.0
+
+Changes from 0.14.0 to 0.16.0
+-----------------------------
+** Improvement
+    * FELIX-5021 [GOGO] Use system bundle to find bundles
+    * FELIX-5009 Relative URIs would be nice for install and update
+    * FELIX-5008 gogo usage messages could be less confusing
+    * FELIX-3499 felix:cd command works only with relative paths
+
+** Bug
+    * FELIX-4969 cd refuses to leave initial directory
+
+Changes from 0.12.0 to 0.14.0
 -----------------------------
 
 * Fix a NPE with the obr:info command
diff --git a/main.distribution/doc/changelog_gogo.runtime.txt b/main.distribution/doc/changelog_gogo.runtime.txt
index 8518b00..b351261 100644
--- a/main.distribution/doc/changelog_gogo.runtime.txt
+++ b/main.distribution/doc/changelog_gogo.runtime.txt
@@ -1,4 +1,89 @@
-Changes 0.14.0 to 0.16.0
+Changes from 1.1.2 to 1.1.4
+---------------------------
+Improvement
+    [FELIX-5963] - Gogo runtime should use named executor threads
+    [FELIX-6038] - pull Java 7 support back in for gogo runtime,shell and console
+
+Changes 1.1.0 to 1.1.2
+----------------------
+Improvement
+    [FELIX-5970] - Add requirement & capabilities model so gogo can be resolved
+    [FELIX-5999] - cleanup compiler warnings
+    [FELIX-6001] - cleanup compiler warnings
+    [FELIX-6003] - Add some resolver checks to make sure @RequireGogo annotation works for both jline and shell
+    [FELIX-6007] - create a gogo bom
+
+Changes 1.0.12 to 1.1.0
+-----------------------
+New Feature
+    [FELIX-5835] - Upgrade to JDK 8
+    [FELIX-5836] - Upgrade to OSGi r6
+
+Improvement
+    [FELIX-5855] - Support array subscript in expander
+    [FELIX-5856] - Coercion between Object[] and List
+    [FELIX-5857] - Provide a context classloader on the session to help with class loading
+
+Changes 1.0.10 to 1.0.12
+------------------------
+Bug
+    [FELIX-5805] - [gogo][runtime] OOM caused by endless loop when parsing "]"
+    [FELIX-5821] - [gogo][runtime] Hitting Ctrl+C may kill the console output thread
+
+Improvement
+    [FELIX-5726] - Thread create by gogo should be named
+
+Changes 1.0.8 to 1.0.10
+-----------------------
+Bug
+    [FELIX-5706] - Unable to access DTO fields using reflection
+
+Improvement
+    [FELIX-5715] - Central point to allow customization of security related checks
+
+Changes 1.0.6 to 1.0.8
+----------------------
+Bug
+    [FELIX-5637] - [gogo][runtime] Error throwns by commands are swallowed and lost
+    [FELIX-5655] - Possible NPE in Expression.isNumber when passing an empty string
+    [FELIX-5656] - [gogo][runtime] The Expander does not correctly support octal values
+
+Changes 1.0.4 to 1.0.6
+----------------------
+Bug
+    [FELIX-5599] - Allow reusing a closure from a parent session
+
+Improvement
+    [FELIX-5633] - [gogo][runtime] The file name generation should take ~ into account
+    [FELIX-5634] - [gogo][runtime] The file name generation may loop into subtrees for nothing
+
+Changes 1.0.2 to 1.0.4
+----------------------
+Bug
+    [FELIX-5462] - [gogo][runtime] Unable to add a converter using reflection
+    [FELIX-5465] - [gogo][runtime] No way to concatenate arrays
+    [FELIX-5486] - [gogo][runtime] Avoid unnecessary conversions from strings to booleans/integers
+    [FELIX-5541] - ArrayIndexOutOfBoundsException in the parser
+
+Changes 1.0.0 to 1.0.2
+----------------------
+Bug
+    [FELIX-5433] - Interrupting a job should interrupt its children
+    [FELIX-5440] - [gogo] Do not print results at end of pipe
+    [FELIX-5441] - [gogo] Do not print stack traces when inspection can not access fields
+
+Changes 0.16.2 to 1.0.0
+-----------------------
+New Feature
+    [FELIX-5272] - New gogo features
+
+Improvement
+    [FELIX-4970] - all felix poms should advertise their SCM
+
+Task
+    [FELIX-5378] - [gogo] Upgrade packages and bundle to 1.0.0
+
+Changes 0.14.0 to 0.16.2
 ------------------------
 
 ** Bug
@@ -11,7 +96,7 @@
 ------------------------
 
 ** Bug
-    * [FELIX-4637] - Gogo can't cope without several commands with defined service.ranking 
+    * [FELIX-4637] - Gogo can't cope without several commands with defined service.ranking
 
 ** New Feature
     * [FELIX-4671] - Provide an expression parser
diff --git a/main.distribution/doc/changelog_main.txt b/main.distribution/doc/changelog_main.txt
index cf62b91..604909a 100644
--- a/main.distribution/doc/changelog_main.txt
+++ b/main.distribution/doc/changelog_main.txt
@@ -1,3 +1,19 @@
+Changes from 6.0.4 to 7.0.0
+---------------------------
+
+** Improvement
+    * Update to latest framework version 7.0.0
+
+Changes from 6.0.3 to 6.0.4
+---------------------------
+
+** Improvement
+    * Update to latest framework version 6.0.4
+    * Update to latest gogo runtime 1.1.4
+    * Update to latest gogo.jline 1.1.8
+    * Update to latest jline 3.13.2
+    * Update to latest jansi 1.18
+
 Changes from 6.0.2 to 6.0.3
 ---------------------------
 
diff --git a/main.distribution/doc/changelog_resolver.txt b/main.distribution/doc/changelog_resolver.txt
index 21cedbb..38eb6c6 100644
--- a/main.distribution/doc/changelog_resolver.txt
+++ b/main.distribution/doc/changelog_resolver.txt
@@ -1,3 +1,10 @@
+2.0.2
+-----
+
+** Bug
+    * [FELIX-6140] - possible deadlock in ResolverImpl.EnhancedExecutor.await()
+    * [FELIX-6212] - Issues with uses capability checking with split packages and reexport
+
 2.0.0
 -----
 
diff --git a/main.distribution/pom.xml b/main.distribution/pom.xml
index 35190ec..4040976 100644
--- a/main.distribution/pom.xml
+++ b/main.distribution/pom.xml
@@ -27,22 +27,23 @@
   <packaging>pom</packaging>
   <name>Apache Felix Main Distribution</name>
   <artifactId>org.apache.felix.main.distribution</artifactId>
-  <version>6.1.0-SNAPSHOT</version>
+  <version>7.1.0-SNAPSHOT</version>
   <properties>
     <dollar>$</dollar>
-    <framework.version>6.0.3</framework.version>
-    <gogo.runtime.version>1.1.0</gogo.runtime.version>
-    <gogo.jline.shell.version>1.1.0</gogo.jline.shell.version>
-    <gogo.command.version>1.0.2</gogo.command.version>
-    <jline.version>3.7.0</jline.version>
+    <framework.version>7.0.0</framework.version>
+    <gogo.runtime.version>1.1.4</gogo.runtime.version>
+    <gogo.jline.shell.version>1.1.8</gogo.jline.shell.version>
+    <gogo.command.version>1.1.2</gogo.command.version>
+    <jline.version>3.13.2</jline.version>
     <obr.version>2.0.10</obr.version>
-    <jansi.version>1.17.1</jansi.version>
+    <jansi.version>1.18</jansi.version>
   </properties>
     <scm>
       <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
       <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
       <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
-    </scm>
+      <tag>HEAD</tag>
+  </scm>
   <build>
     <plugins>
       <plugin>
diff --git a/main/doc/changelog.txt b/main/doc/changelog.txt
index cf62b91..604909a 100644
--- a/main/doc/changelog.txt
+++ b/main/doc/changelog.txt
@@ -1,3 +1,19 @@
+Changes from 6.0.4 to 7.0.0
+---------------------------
+
+** Improvement
+    * Update to latest framework version 7.0.0
+
+Changes from 6.0.3 to 6.0.4
+---------------------------
+
+** Improvement
+    * Update to latest framework version 6.0.4
+    * Update to latest gogo runtime 1.1.4
+    * Update to latest gogo.jline 1.1.8
+    * Update to latest jline 3.13.2
+    * Update to latest jansi 1.18
+
 Changes from 6.0.2 to 6.0.3
 ---------------------------
 
diff --git a/main/pom.xml b/main/pom.xml
index 0d0bded..e84ed78 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -20,35 +20,37 @@
  <parent>
     <groupId>org.apache.felix</groupId>
     <artifactId>felix-parent</artifactId>
-    <version>5</version>
+    <version>6</version>
     <relativePath>../pom/pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <packaging>bundle</packaging>
   <name>Apache Felix Main</name>
   <artifactId>org.apache.felix.main</artifactId>
-  <version>6.1.0-SNAPSHOT</version>
+  <version>7.1.0-SNAPSHOT</version>
     <scm>
       <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
       <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
       <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
-    </scm>
+      <tag>HEAD</tag>
+  </scm>
   <dependencies>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>org.apache.felix.framework</artifactId>
-      <version>6.1.0-SNAPSHOT</version>
+      <version>7.1.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
   <properties>
     <log.level>4</log.level>
+    <felix.java.version>8</felix.java.version>
     <dollar>$</dollar>
-    <gogo.runtime.version>1.1.0</gogo.runtime.version>
-    <gogo.jline.shell.version>1.1.0</gogo.jline.shell.version>
-    <gogo.command.version>1.0.2</gogo.command.version>
-    <jline.version>3.7.0</jline.version>
+    <gogo.runtime.version>1.1.4</gogo.runtime.version>
+    <gogo.jline.shell.version>1.1.8</gogo.jline.shell.version>
+    <gogo.command.version>1.1.2</gogo.command.version>
+    <jline.version>3.13.2</jline.version>
     <obr.version>2.0.10</obr.version>
-    <jansi.version>1.17.1</jansi.version>
+    <jansi.version>1.18</jansi.version>
   </properties>
   <profiles>
     <profile>
@@ -62,18 +64,72 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>animal-sniffer-maven-plugin</artifactId>
         <configuration>
-          <target>1.5</target>
-          <source>1.5</source>
+          <skip>true</skip>
         </configuration>
-      </plugin>
+     </plugin>
+     <plugin>
+        <groupId>org.moditect</groupId>
+        <artifactId>moditect-maven-plugin</artifactId>
+        <version>1.0.0.RC1</version>
+        <executions>
+          <execution>
+            <id>add-module-infos</id>
+            <phase>package</phase>
+            <goals>
+              <goal>add-module-info</goal>
+            </goals>
+            <configuration>
+              <module>
+              <moduleInfoSource>
+                open module org.apache.felix.main {
+                    requires jdk.unsupported;
 
+                    exports org.apache.felix.framework.ext;
+                    exports org.osgi.dto;
+                    exports org.osgi.framework;
+                    exports org.osgi.framework.connect;
+                    exports org.osgi.framework.dto;
+                    exports org.osgi.framework.hooks.bundle;
+                    exports org.osgi.framework.hooks.resolver;
+                    exports org.osgi.framework.hooks.service;
+                    exports org.osgi.framework.hooks.weaving;
+                    exports org.osgi.framework.launch;
+                    exports org.osgi.framework.namespace;
+                    exports org.osgi.framework.startlevel;
+                    exports org.osgi.framework.startlevel.dto;
+                    exports org.osgi.framework.wiring;
+                    exports org.osgi.framework.wiring.dto;
+                    exports org.osgi.resource;
+                    exports org.osgi.resource.dto;
+                    exports org.osgi.service.condition;
+                    exports org.osgi.service.packageadmin;
+                    exports org.osgi.service.resolver;
+                    exports org.osgi.service.startlevel;
+                    exports org.osgi.service.url;
+                    exports org.osgi.util.tracker;
+                    provides org.osgi.framework.launch.FrameworkFactory with
+                      org.apache.felix.framework.FrameworkFactory;
+                    provides org.osgi.framework.connect.ConnectFrameworkFactory with
+                      org.apache.felix.framework.FrameworkFactory;
+
+                    uses org.apache.felix.framework.ext.ClassPathExtenderFactory;
+                    uses org.osgi.framework.connect.FrameworkUtilHelper;
+                    }
+                </moduleInfoSource>
+                <mainClass>org.apache.felix.main.Main</mainClass>
+              </module>
+              <overwriteExistingFiles>true</overwriteExistingFiles>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.5.0</version>
+        <version>5.1.1</version>
         <extensions>true</extensions>
         <configuration>
           <instructions>
@@ -83,7 +139,7 @@
             <Bundle-Name>Apache Felix</Bundle-Name>
             <Bundle-Description>OSGi R6 framework.</Bundle-Description>
             <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
-            <Embed-Dependency>*;artifactId=org.apache.felix.framework;inline=true</Embed-Dependency>
+            <Embed-Dependency>*;artifactId=org.apache.felix.framework;inline=default.properties|org/**|META-INF/services/**</Embed-Dependency>
             <Private-Package>org.apache.felix.main.*</Private-Package>
             <Export-Package>!org.osgi.service.log, !org.osgi.service.obr, org.osgi.*</Export-Package>
             <Import-Package>!*</Import-Package>
@@ -189,11 +245,11 @@
         </executions>
       </plugin>
       <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-javadoc-plugin</artifactId>
-            <configuration>
-                <failOnError>false</failOnError>
-            </configuration>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <failOnError>false</failOnError>
+        </configuration>
       </plugin>
     </plugins>
     <resources>
diff --git a/main/src/main/appended-resources/META-INF/NOTICE b/main/src/main/appended-resources/META-INF/NOTICE
index d4d1ad8..246e269 100644
--- a/main/src/main/appended-resources/META-INF/NOTICE
+++ b/main/src/main/appended-resources/META-INF/NOTICE
@@ -1,4 +1,4 @@
 This product includes software developed at
 The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2015).
+Copyright (c) OSGi Alliance (2000, 2020).
 Licensed under the Apache License 2.0.
diff --git a/metatype/changelog.txt b/metatype/changelog.txt
index 9253af5..a831bef 100644
--- a/metatype/changelog.txt
+++ b/metatype/changelog.txt
@@ -1,3 +1,9 @@
+Changes in 1.2.4
+----------------
+** Bug
+    * [FELIX-6009] - Metatype AD empty String default value
+
+
 Changes in 1.2.2
 ----------------
 ** Bug
diff --git a/metatype/pom.xml b/metatype/pom.xml
index e8092e1..3e31fe8 100644
--- a/metatype/pom.xml
+++ b/metatype/pom.xml
@@ -33,7 +33,7 @@
     <description>
         Implementation of the OSGi Metatype Service Specification 1.4
     </description>
-    <version>1.2.3-SNAPSHOT</version>
+    <version>1.2.5-SNAPSHOT</version>
     <dependencies>
         <dependency>
             <groupId>org.osgi</groupId>
@@ -82,7 +82,8 @@
         <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
         <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
         <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
-    </scm>
+      <tag>HEAD</tag>
+  </scm>
 
     <build>
         <plugins>
diff --git a/metatype/src/main/java/org/apache/felix/metatype/AD.java b/metatype/src/main/java/org/apache/felix/metatype/AD.java
index 1a2ff9a..a726a20 100644
--- a/metatype/src/main/java/org/apache/felix/metatype/AD.java
+++ b/metatype/src/main/java/org/apache/felix/metatype/AD.java
@@ -224,7 +224,7 @@
      * NOTE: this method is depending on the value of {@link #getCardinality()}! Make sure that the
      * cardinality is properly set <b>before</b> calling this method.
      * </p>
-     * 
+     *
      * @param defaultValue the default value to set, as encoded string-value (using comma's as separator), can be <code>null</code>.
      */
     public void setDefaultValue(String defaultValue)
@@ -314,8 +314,8 @@
             return new String[] { "" };
         }
 
-        List strings = new ArrayList();
-        StringBuffer sb = new StringBuffer();
+        List<String> strings = new ArrayList<>();
+        StringBuilder sb = new StringBuilder();
 
         int length = listString.length();
         boolean escaped = false;
@@ -383,7 +383,7 @@
         // Always add the last string, as it contains everything after the last comma...
         strings.add(sb.toString());
 
-        return (String[]) strings.toArray(new String[strings.size()]);
+        return strings.toArray(new String[strings.size()]);
     }
 
     protected Comparable convertToType(final String value)
@@ -477,6 +477,7 @@
             value = Boolean.valueOf(boolValue).booleanValue();
         }
 
+        @Override
         public int compareTo(Object obj)
         {
             ComparableBoolean cb = (ComparableBoolean) obj;
diff --git a/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java b/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java
index 60b35a0..a6224af 100644
--- a/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java
+++ b/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java
@@ -27,29 +27,29 @@
 /**
  * Provides various validation routines used by the {@link AD#validate(String)}
  * method.
- * 
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 final class ADValidator
 {
     /**
-     * Validates a given input string according to the type specified by the given attribute 
+     * Validates a given input string according to the type specified by the given attribute
      * definition.
      * <p>
      * The validation is done in the following way:
      * </p>
      * <ul>
-     * <li>If the input is undefined (ie. <code>null</code>), and the attribute is mandatory, the 
-     * validation fails due to a missing value. If the attribute is optional, the input is 
+     * <li>If the input is undefined (ie. <code>null</code>), and the attribute is mandatory, the
+     * validation fails due to a missing value. If the attribute is optional, the input is
      * accepted;</li>
      * <li>If the input represents a <em>boolean</em> value, it is tested whether it is defined (in
      * case of non-zero cardinality) and represents either <tt>"true"</tt> or <tt>"false"</tt>. The
      * minimum and maximum parameters are <b>not</b> used in this validation;</li>
-     * <li>If the input represents a <em>character</em> value, it is tested whether it is defined 
-     * (in case of non-zero cardinality). The character value must be defined within the character 
+     * <li>If the input represents a <em>character</em> value, it is tested whether it is defined
+     * (in case of non-zero cardinality). The character value must be defined within the character
      * range specified by the minimum and maximum parameters (if defined);</li>
      * <li>If the input represents a <em>numeric</em> value, it is tested whether it is defined (in
-     * case of non-zero cardinality). The numeric value must be defined within the numeric range 
+     * case of non-zero cardinality). The numeric value must be defined within the numeric range
      * specified by the minimum and maximum parameters (if defined);</li>
      * <li>If the input represents a <em>string</em> or <em>password</em>, it is tested whether it
      * is defined (in case of non-zero cardinality). The length of the string value must be in the
@@ -57,9 +57,9 @@
      * </ul>
      * <p>
      * For all types of attributes, if it defines option values, the input should be present as one
-     * of the defined option values. 
+     * of the defined option values.
      * </p>
-     * 
+     *
      * @param ad
      *            the attribute definition to use in the validation;
      * @param rawInput
@@ -122,7 +122,7 @@
 
     /**
      * Searches for a given search value in a given array of options.
-     * 
+     *
      * @param searchValue
      *            the value to search for;
      * @param optionValues
@@ -152,7 +152,7 @@
 
     /**
      * Parses a given string value into a numeric type.
-     * 
+     *
      * @param type
      *            the type to parse;
      * @param value
@@ -195,7 +195,7 @@
     /**
      * Parses a given string value as character, allowing <code>null</code>
      * -values and empty values to be given as input.
-     * 
+     *
      * @param value
      *            the value to parse as character, can be <code>null</code> or
      *            an empty value.
@@ -212,10 +212,10 @@
     }
 
     /**
-     * Parses a given string value as numeric value, allowing 
-     * <code>null</code>-values and invalid numeric values to be given as 
+     * Parses a given string value as numeric value, allowing
+     * <code>null</code>-values and invalid numeric values to be given as
      * input.
-     * 
+     *
      * @param type the type of number, should only be a numeric type;
      * @param value
      *            the value to parse as integer, can be <code>null</code> or a
@@ -241,7 +241,7 @@
 
     /**
      * Validates a given input string as boolean value.
-     * 
+     *
      * @param ad
      *            the attribute definition to use in the validation;
      * @param input
@@ -278,7 +278,7 @@
 
     /**
      * Validates a given input string as character value.
-     * 
+     *
      * @param ad
      *            the attribute definition to use in the validation;
      * @param input
@@ -332,7 +332,7 @@
 
     /**
      * Validates a given input string as numeric value.
-     * 
+     *
      * @param ad
      *            the attribute definition to use in the validation;
      * @param input
@@ -387,7 +387,7 @@
 
     /**
      * Validates a given input string as string (or password).
-     * 
+     *
      * @param ad
      *            the attribute definition to use in the validation;
      * @param input
@@ -406,12 +406,9 @@
         for (int i = 0; i < input.length; i++)
         {
             String value = input[i];
-            int length = (value == null) ? 0 : value.length();
-
-            if (ad.isRequired() && ((value == null) || (length == 0)))
+            final int length = value == null ? 0 : value.length();
+            if (ad.isRequired() && value == null)
             {
-                // Possible if the cardinality != 0 and input was something like
-                // "0,,1"...
                 return AD.VALIDATE_MISSING;
             }
             // Check whether the minimum length is adhered for all values...
diff --git a/metatype/src/test/java/org/apache/felix/metatype/ADTest.java b/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
index c830cfe..aa82648 100644
--- a/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
+++ b/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
@@ -21,10 +21,10 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import junit.framework.TestCase;
-
 import org.osgi.service.metatype.AttributeDefinition;
 
+import junit.framework.TestCase;
+
 /**
  * The <code>ADTest</code> class tests the static helper methods of the
  * {@link AD} class.
@@ -255,11 +255,9 @@
         ad.setDefaultValue("");
         assertArrayEquals(new String[] { "" }, ad.getDefaultValue());
 
-        // corner case: in case of required values, an empty default makes no sense
-        // for single values, hence that the empty default is coerced into null...
         ad.setRequired(true);
         ad.setDefaultValue("");
-        assertNull(ad.getDefaultValue());
+        assertArrayEquals(new String[] { "" }, ad.getDefaultValue());
     }
 
     /**
@@ -284,11 +282,9 @@
         ad.setDefaultValue("");
         assertArrayEquals(new String[] { "" }, ad.getDefaultValue());
 
-        // corner case: in case of required values, an empty default is coerced
-        // into a empty array...
         ad.setRequired(true);
         ad.setDefaultValue("");
-        assertArrayEquals(new String[0], ad.getDefaultValue());
+        assertArrayEquals(new String[] {""}, ad.getDefaultValue());
     }
 
     private static void assertArrayEquals(String[] a, String[] b)
@@ -299,4 +295,12 @@
             assertEquals(a[i], b[i]);
         }
     }
+
+    public void testSplitList() {
+        final String[] array = AD.splitList("321, , 123");
+        assertEquals(3, array.length);
+        assertEquals("321", array[0]);
+        assertEquals("", array[1]);
+        assertEquals("123", array[2]);
+    }
 }
diff --git a/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java b/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java
index 33c02c3..5b7c11d 100644
--- a/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java
+++ b/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java
@@ -27,7 +27,7 @@
 
 /**
  * Test cases for {@link ADValidator}.
- * 
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class ADValidatorTest extends TestCase
@@ -150,7 +150,7 @@
         // adhere maximal values
         assertEquals("", ADValidator.validate(ad, "c, d, e"));
 
-        Map options = new HashMap();
+        Map<String, String> options = new HashMap<>();
         options.put("b", "B");
         options.put("c", "C");
         options.put("d", "D");
@@ -349,18 +349,19 @@
 
         // optional value
         assertEquals("", ADValidator.validate(ad, null));
-        // 2nd value is missing; but that's ok
+        // 2nd value is empty; but that's ok
         assertEquals("", ADValidator.validate(ad, "321, , 123"));
 
         ad.setRequired(true);
         ad.setMin("3");
 
+
         // mandatory value
         assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
-        // 2nd value is missing
-        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "321, , 123"));
         // 2nd value is too short
         assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "321,12,123"));
+        // 2nd value is empty and therefore too short
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "321, , 123"));
         // adhere minimum lengths
         assertEquals("", ADValidator.validate(ad, "123, 123, 123"));
         // adhere maximum lengths
diff --git a/resolver/doc/changelog.txt b/resolver/doc/changelog.txt
index 21cedbb..38eb6c6 100644
--- a/resolver/doc/changelog.txt
+++ b/resolver/doc/changelog.txt
@@ -1,3 +1,10 @@
+2.0.2
+-----
+
+** Bug
+    * [FELIX-6140] - possible deadlock in ResolverImpl.EnhancedExecutor.await()
+    * [FELIX-6212] - Issues with uses capability checking with split packages and reexport
+
 2.0.0
 -----
 
diff --git a/resolver/pom.xml b/resolver/pom.xml
index 96f6802..76942f6 100644
--- a/resolver/pom.xml
+++ b/resolver/pom.xml
@@ -35,6 +35,7 @@
      <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
      <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
      <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
+    <tag>HEAD</tag>
   </scm>
   <dependencies>
    <dependency>
diff --git a/resolver/src/main/appended-resources/META-INF/NOTICE b/resolver/src/main/appended-resources/META-INF/NOTICE
index d4d1ad8..246e269 100644
--- a/resolver/src/main/appended-resources/META-INF/NOTICE
+++ b/resolver/src/main/appended-resources/META-INF/NOTICE
@@ -1,4 +1,4 @@
 This product includes software developed at
 The OSGi Alliance (http://www.osgi.org/).
-Copyright (c) OSGi Alliance (2000, 2015).
+Copyright (c) OSGi Alliance (2000, 2020).
 Licensed under the Apache License 2.0.
diff --git a/scr/changelog.txt b/scr/changelog.txt
index 7b64209..26f9371 100644
--- a/scr/changelog.txt
+++ b/scr/changelog.txt
@@ -1,3 +1,31 @@
+Changes in 2.1.26
+-----------------
+** Bug
+    * [FELIX-6352] - SCR should protect against unregistered IllegalStateException for its ConfigurationListener registrations
+    * [FELIX-6361] - IllegalArgumentException possible from LoggerFactory.getLogger(Bundle, String, Class<L>)
+    * [FELIX-6353] - Constructor injection: activation with optional reference fails if service not available
+    * [FELIX-6351] - EventDispatcher: Error during dispatch. (java.lang.IllegalStateException: Service already unregistered.)
+    * [FELIX-6349] - Possible NullPointerException on modified event in DependencyManager
+
+Changes in 2.1.24
+-----------------
+** Bug
+    * [FELIX-6327] - NoSuchElementException can occur with SingleDynamicCustomizer when services are removed
+    * [FELIX-6315] - Factory components are eagerly deactivated
+    * [FELIX-6325] - OSGi log package is mandatory but imported as optional
+
+Changes in 2.1.22
+-----------------
+** Bug
+    * [FELIX-6314] - NullPointerException in SingleComponentManager.disposeImplementationObject
+    * [FELIX-6108] - SCR activation log-messages cannot be disabled with R7 LogService
+    * [FELIX-6274] - Potential Class Space problems with multiple Log Service APIs
+    * [FELIX-6317] - dynamic greedy optional/mandatory references can get wrong service ranking
+    * [FELIX-6161] - SCR: Method of resolving references limits Service ListenerHook implementations
+** Improvement
+    * [FELIX-6307] - SCR logging uses null name for logger in LogServiceEnabledLogger.getLogger()
+    * [FELIX-6293] - Apache Felix SCR Logging
+
 Changes in 2.1.20
 -----------------
 ** Bug
diff --git a/scr/pom.xml b/scr/pom.xml
index c4cff2d..fa63fe9 100644
--- a/scr/pom.xml
+++ b/scr/pom.xml
@@ -30,7 +30,7 @@
         Implementation of the Declarative Services specification 1.4
     </description>
     <artifactId>org.apache.felix.scr</artifactId>
-    <version>2.1.25-SNAPSHOT</version>
+    <version>2.1.27-SNAPSHOT</version>
     <scm>
         <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
         <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java
index 2ad3248..0e44eb0 100755
--- a/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java
@@ -296,7 +296,7 @@
                     }
                     if ( !refMetadata.isMultiple())
                     {
-                        if ( ref == null )
+                        if (ref == null && !refMetadata.isOptional())
                         {
                             throw new InstantiationException("Unable to get service for reference " + refMetadata.getName());
                         }
@@ -304,6 +304,10 @@
                     }
                     else
                     {
+                        if (refs.isEmpty() && !refMetadata.isOptional())
+                        {
+                            throw new InstantiationException("Unable to get service for reference " + refMetadata.getName());
+                        }
                         args[i] = refs;
                     }
                 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/logger/BundleLogger.java b/scr/src/main/java/org/apache/felix/scr/impl/logger/BundleLogger.java
index 6f9c6c2..6e6d652 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/logger/BundleLogger.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/logger/BundleLogger.java
@@ -25,7 +25,9 @@
  * an extended bundle. This avoids that all clients doing logging on behalf of
  * a component bundle need to pass in things like {@code BundleContext}.
  */
-public interface BundleLogger  extends InternalLogger  {
+public interface BundleLogger extends InternalLogger
+{
 
-	ComponentLogger component(Bundle m_bundle, String implementationClassName, String name);
+    ComponentLogger component(Bundle m_bundle, String implementationClassName,
+        String name);
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/logger/ComponentLogger.java b/scr/src/main/java/org/apache/felix/scr/impl/logger/ComponentLogger.java
index facf595..8d86ee4 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/logger/ComponentLogger.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/logger/ComponentLogger.java
@@ -23,6 +23,7 @@
  * This avoids avoids that all clients doing logging on behalf of a component need to
  * pass in things like {@code ComponentMetadata} or the component Id.
  */
-public interface ComponentLogger extends InternalLogger {
-	void setComponentId(long m_componentId);
+public interface ComponentLogger extends InternalLogger
+{
+    void setComponentId(long m_componentId);
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/logger/ExtLogManager.java b/scr/src/main/java/org/apache/felix/scr/impl/logger/ExtLogManager.java
index 1752987..759d63d 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/logger/ExtLogManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/logger/ExtLogManager.java
@@ -35,45 +35,54 @@
  * the bundle symbolic name + "." + component name
  * </ul>
  */
-class ExtLogManager extends ScrLogManager {
-	public static String	SCR_LOGGER_NAME		= "org.apache.felix.scr.impl";
-	public static String	SCR_LOGGER_PREFIX	= "org.apache.felix.scr.";
-	private final Bundle	bundle;
+class ExtLogManager extends ScrLogManager
+{
+    public static String SCR_LOGGER_NAME = "org.apache.felix.scr.impl";
+    public static String SCR_LOGGER_PREFIX = "org.apache.felix.scr.";
+    private final Bundle bundle;
 
-	ExtLogManager(BundleContext context, ScrConfiguration config) {
-		super(context, config);
-		this.bundle = context.getBundle();
-	}
+    ExtLogManager(BundleContext context, ScrConfiguration config)
+    {
+        super(context, config);
+        this.bundle = context.getBundle();
+    }
 
-	@Override
-	public ScrLogger scr() {
-		return getLogger(bundle, SCR_LOGGER_NAME, ScrLoggerFacade.class);
-	}
+    @Override
+    public ScrLogger scr()
+    {
+        return getLogger(bundle, SCR_LOGGER_NAME, ScrLoggerFacade.class);
+    }
 
-	@Override
-	public BundleLogger bundle(Bundle bundle) {
-		return getLogger(bundle, SCR_LOGGER_PREFIX.concat(bundle.getSymbolicName()), ScrLoggerFacade.class);
-	}
+    @Override
+    public BundleLogger bundle(Bundle bundle)
+    {
+        return getLogger(bundle, SCR_LOGGER_PREFIX.concat(bundle.getSymbolicName()),
+            ScrLoggerFacade.class);
+    }
 
-	@Override
-	public ComponentLogger component(Bundle bundle, String implementationClass, String componentName) {
+    @Override
+    public ComponentLogger component(Bundle bundle, String implementationClass,
+        String componentName)
+    {
 
-		assert bundle != null;
-		assert bundle.getSymbolicName() != null : "scr requires recent bundles";
-		assert implementationClass != null;
-		assert componentName != null;
+        assert bundle != null;
+        assert bundle.getSymbolicName() != null : "scr requires recent bundles";
+        assert implementationClass != null;
+        assert componentName != null;
 
-		String loggerName = SCR_LOGGER_PREFIX.concat(bundle.getSymbolicName()).concat(".").concat(componentName);
-		ScrLoggerFacade logger = getLogger(bundle, loggerName, ScrLoggerFacade.class);
-		logger.setPrefix("["+componentName+"]");
-		return logger;
-	}
+        String loggerName = SCR_LOGGER_PREFIX.concat(bundle.getSymbolicName()).concat(
+            ".").concat(componentName);
+        ScrLoggerFacade logger = getLogger(bundle, loggerName, ScrLoggerFacade.class);
+        logger.setPrefix("[" + componentName + "]");
+        return logger;
+    }
 
-	String componentPrefix(ScrLoggerFacade slf, long id) {
-		assert slf.prefix != null; 
-		if ( slf.prefix.indexOf(')')<0)
-			return slf.prefix.replace("]", "(" + id + ")]");
-		else
-			return slf.prefix;
-	}
+    String componentPrefix(ScrLoggerFacade slf, long id)
+    {
+        assert slf.prefix != null;
+        if (slf.prefix.indexOf(')') < 0)
+            return slf.prefix.replace("]", "(" + id + ")]");
+        else
+            return slf.prefix;
+    }
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/logger/InternalLogger.java b/scr/src/main/java/org/apache/felix/scr/impl/logger/InternalLogger.java
index 4eca75f..a4851ce 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/logger/InternalLogger.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/logger/InternalLogger.java
@@ -28,83 +28,91 @@
  * this package, it could be private. However, then Level should be standalone,
  * which would change most files. So minimize the code change, it is kept public.
  */
-public interface InternalLogger {
-	/**
-	 * The level to log. This is aligned with the OSGi LogLevel
-	 */
-	public enum Level {
-		AUDIT {
-			boolean err() {
-				return true;
-			}
-		},
-		ERROR {
-			boolean err() {
-				return true;
-			}
-		},
-		WARN, INFO, DEBUG, TRACE;
+public interface InternalLogger
+{
+    /**
+     * The level to log. This is aligned with the OSGi LogLevel
+     */
+    public enum Level
+    {
+        AUDIT
+        {
+            boolean err()
+            {
+                return true;
+            }
+        },
+        ERROR
+        {
+            boolean err()
+            {
+                return true;
+            }
+        },
+        WARN, INFO, DEBUG, TRACE;
 
-		/**
-		 * Check if this log level is higher or the same of the other level.
-		 * 
-		 * @param other
-		 *                  the other level
-		 * @return true if the level other should be logged
-		 */
-		boolean implies(Level other) {
-			return ordinal() >= other.ordinal();
-		}
+        /**
+         * Check if this log level is higher or the same of the other level.
+         * 
+         * @param other
+         *                  the other level
+         * @return true if the level other should be logged
+         */
+        boolean implies(Level other)
+        {
+            return ordinal() >= other.ordinal();
+        }
 
-		boolean err() {
-			return false;
-		}
+        boolean err()
+        {
+            return false;
+        }
 
-	}
+    }
 
-	/**
-	 * Logs the message to an appropriate OSGi logger. If not such logger can be
-	 * found then it will log to stderr for ERROR & AUDIT messages and stdout
-	 * for other messages
-	 * 
-	 * @param level
-	 *                    only log when this level is implied by the current log
-	 *                    level
-	 * @param message
-	 *                    the message to log
-	 * @param ex
-	 *                    a Throwable or null
-	 */
-	void log(Level level, String message, Throwable ex);
+    /**
+     * Logs the message to an appropriate OSGi logger. If not such logger can be
+     * found then it will log to stderr for ERROR & AUDIT messages and stdout
+     * for other messages
+     * 
+     * @param level
+     *                    only log when this level is implied by the current log
+     *                    level
+     * @param message
+     *                    the message to log
+     * @param ex
+     *                    a Throwable or null
+     */
+    void log(Level level, String message, Throwable ex);
 
-	/**
-	 * Formats the message using the {@link MessageFormat} class, i.e. with {}
-	 * place holders for the args. It then calls
-	 * {@link #log(Level, String, Throwable)}.
-	 * 
-	 * @param level
-	 *                    only log when this level is implied by the current log
-	 *                    level
-	 * @param message
-	 *                    the message to log
-	 * @param ex
-	 *                    a Throwable or null
-	 * @param args
-	 *                    the arguments to the {@link MessageFormat} formatting
-	 */
-	void log(Level level, String message, Throwable ex, Object... args);
+    /**
+     * Formats the message using the {@link MessageFormat} class, i.e. with {}
+     * place holders for the args. It then calls
+     * {@link #log(Level, String, Throwable)}.
+     * 
+     * @param level
+     *                    only log when this level is implied by the current log
+     *                    level
+     * @param message
+     *                    the message to log
+     * @param ex
+     *                    a Throwable or null
+     * @param args
+     *                    the arguments to the {@link MessageFormat} formatting
+     */
+    void log(Level level, String message, Throwable ex, Object... args);
 
-	/**
-	 * Answer true if the current logging level is enabled for the given level.
-	 * For stdout/stderr fallback the logging level is defined by the
-	 * {@link ScrConfiguration#getLogLevel()}. If there is an OSGi logger
-	 * available then the logger name will define the log level via
-	 * {@link LoggerAdmin}.
-	 *
-	 * @param level
-	 *                  the level to check
-	 * @return true if the given log level is enabled
-	 */
-	boolean isLogEnabled(Level level);
+    /**
+     * Answer true if the current logging level is enabled for the given level.
+     * For stdout/stderr fallback the logging level is defined by the
+     * {@link ScrConfiguration#getLogLevel()}. If there is an OSGi logger
+     * available then the logger name will define the log level via
+     * {@link LoggerAdmin}.
+     *
+     * @param level
+     *                  the level to check
+     * @return true if the given log level is enabled
+     */
+    boolean isLogEnabled(Level level);
 
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/logger/LogManager.java b/scr/src/main/java/org/apache/felix/scr/impl/logger/LogManager.java
index d5cd008..027f4a6 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/logger/LogManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/logger/LogManager.java
@@ -45,192 +45,246 @@
  * The LogDomain represents every bundle. Per LogDomain, we keep the facades. If the factory goes,
  * we reset the facades.
  */
-class LogManager extends ServiceTracker<Object, Object> implements BundleListener {
+class LogManager extends ServiceTracker<Object, Object> implements BundleListener
+{
 
     private static final String LOGGER_FACTORY_CLASS_NAME = "org.osgi.service.log.LoggerFactory";
 
-	final BundleContext	scrContext;
-	final AtomicBoolean	closed	= new AtomicBoolean(false);
+    final BundleContext scrContext;
+    final AtomicBoolean closed = new AtomicBoolean(false);
 
-	/*
-	 * Locks access to guarded fields
-	 */
-	class Lock {
-		final Map<Bundle, LogDomain>	domains	= new HashMap<>();
-		int								trackingCount;
-		Object					factory;
-		int								ranking=0;
+    /*
+     * Locks access to guarded fields
+     */
+    class Lock
+    {
+        final Map<Bundle, LogDomain> domains = new HashMap<>();
+        int trackingCount;
+        Object factory;
+        int ranking = 0;
 
-		synchronized LogDomain getLogDomain(Bundle bundle) {
-			LogDomain domain = domains.get(bundle);
-			if (domain == null) {
-				domain = new LogDomain(bundle);
-				domains.put(bundle, domain);
-			}
-			return domain;
-		}
+        synchronized LogDomain getLogDomain(Bundle bundle)
+        {
+            LogDomain domain = domains.get(bundle);
+            if (domain == null)
+            {
+                domain = new LogDomain(bundle);
+                domains.put(bundle, domain);
+            }
+            return domain;
+        }
 
-		synchronized void removedFactory(Object service) {
-			if (this.factory == service) {
-				this.factory = null;
-				reset();
-			}
-		}
+        synchronized void removedFactory(Object service)
+        {
+            if (this.factory == service)
+            {
+                this.factory = null;
+                reset();
+            }
+        }
 
-		synchronized void setFactory(int ranking, Object service) {
-			if (this.factory == null) {
-				this.factory = service;
-				this.ranking = ranking;
-			} else if (this.ranking < ranking) {
-				this.factory = service;
-				this.ranking = ranking;
-				reset();
-			}
-		}
+        synchronized void setFactory(int ranking, Object service)
+        {
+            if (this.factory == null)
+            {
+                this.factory = service;
+                this.ranking = ranking;
+            }
+            else if (this.ranking < ranking)
+            {
+                this.factory = service;
+                this.ranking = ranking;
+                reset();
+            }
+        }
 
-		synchronized void reset() {
-			for (LogDomain domain : domains.values()) {
-				domain.reset();
-			}
-		}
+        synchronized void reset()
+        {
+            for (LogDomain domain : domains.values())
+            {
+                domain.reset();
+            }
+        }
 
-		synchronized Object getLogger(LoggerFacade facade, Bundle bundle, String name) {
-			if (factory == null)
-				return facade.logger = null;
-			else
-				return facade.logger = ((LoggerFactory) factory).getLogger(bundle, name, Logger.class);
-		}
+        synchronized Object getLogger(LoggerFacade facade, Bundle bundle, String name)
+        {
+            if (factory == null)
+            {
+                return facade.logger = null;
+            }
+            else
+            {
+                try
+                {
+                    return facade.logger = ((LoggerFactory) factory).getLogger(bundle,
+                        name, Logger.class);
+                }
+                catch (IllegalArgumentException e)
+                {
+                    // The bundle probably got uninstalled or somehow unresolved,
+                    // fallback to the SCR bundle's logger
+                    return ((LoggerFactory) factory).getLogger(context.getBundle(), name,
+                        Logger.class);
+                }
+            }
+        }
 
-		synchronized LogDomain remove(Bundle bundle) {
-			return domains.remove(bundle);
-		}
+        synchronized LogDomain remove(Bundle bundle)
+        {
+            return domains.remove(bundle);
+        }
 
-		synchronized void close() {
-			reset();
-			domains.clear();
-		}
+        synchronized void close()
+        {
+            reset();
+            domains.clear();
+        }
 
-	}
+    }
 
-	final Lock lock = new Lock();
+    final Lock lock = new Lock();
 
-	LogManager(BundleContext context) {
-		super(context, LOGGER_FACTORY_CLASS_NAME, null);
-		this.scrContext = context;
-		scrContext.addBundleListener(this);
-	}
+    LogManager(BundleContext context)
+    {
+        super(context, LOGGER_FACTORY_CLASS_NAME, null);
+        this.scrContext = context;
+        scrContext.addBundleListener(this);
+    }
 
-	@Override
-	public Object addingService(ServiceReference<Object> reference) {
-		Object service = super.addingService(reference);
-		Integer ranking = (Integer) reference.getProperty(Constants.SERVICE_RANKING);
-		if (ranking == null)
-			ranking = 0;
-		lock.setFactory(ranking, service);
-		return service;
-	}
+    @Override
+    public Object addingService(ServiceReference<Object> reference)
+    {
+        Object service = super.addingService(reference);
+        Integer ranking = (Integer) reference.getProperty(Constants.SERVICE_RANKING);
+        if (ranking == null)
+            ranking = 0;
+        lock.setFactory(ranking, service);
+        return service;
+    }
 
-	@Override
-	public void removedService(ServiceReference<Object> reference, Object service) {
-		super.removedService(reference, service);
-		lock.removedFactory(service);
-	}
+    @Override
+    public void removedService(ServiceReference<Object> reference, Object service)
+    {
+        super.removedService(reference, service);
+        lock.removedFactory(service);
+    }
 
-	<T> T getLogger(Bundle bundle, String name, Class<T> type) {
-		return type.cast(lock.getLogDomain(bundle).getLogger(name));
-	}
+    <T> T getLogger(Bundle bundle, String name, Class<T> type)
+    {
+        return type.cast(lock.getLogDomain(bundle).getLogger(name));
+    }
 
-	@SuppressWarnings("resource")
-	@Override
-	public void bundleChanged(BundleEvent event) {
-		if (event.getType() == BundleEvent.STOPPED && !closed.get()) {
-			LogDomain domain = lock.remove(event.getBundle());
-			if (domain != null) {
-				domain.close();
-			}
-		}
-	}
+    @SuppressWarnings("resource")
+    @Override
+    public void bundleChanged(BundleEvent event)
+    {
+        if (event.getType() == BundleEvent.STOPPED && !closed.get())
+        {
+            LogDomain domain = lock.remove(event.getBundle());
+            if (domain != null)
+            {
+                domain.close();
+            }
+        }
+    }
 
-	/*
-	 * Tracks a bundle's LoggerFactory service
-	 */
-	class LogDomain
-			implements Closeable {
+    /*
+     * Tracks a bundle's LoggerFactory service
+     */
+    class LogDomain implements Closeable
+    {
 
-		private final Bundle			bundle;
-		private final Set<LoggerFacade>	facades	= new HashSet<>();
+        private final Bundle bundle;
+        private final Set<LoggerFacade> facades = new HashSet<>();
 
-		LogDomain(Bundle bundle) {
-			this.bundle = bundle;
-		}
+        LogDomain(Bundle bundle)
+        {
+            this.bundle = bundle;
+        }
 
-		private void reset() {
-			synchronized (facades) {
-				for (LoggerFacade facade : facades) {
-					facade.reset();
-				}
-			}
-		}
+        private void reset()
+        {
+            synchronized (facades)
+            {
+                for (LoggerFacade facade : facades)
+                {
+                    facade.reset();
+                }
+            }
+        }
 
-		LoggerFacade getLogger(String name) {
-			LoggerFacade facade = createLoggerFacade(this, name);
-			synchronized (facades) {
-				facades.add(facade);
-			}
-			return facade;
-		}
+        LoggerFacade getLogger(String name)
+        {
+            LoggerFacade facade = createLoggerFacade(this, name);
+            synchronized (facades)
+            {
+                facades.add(facade);
+            }
+            return facade;
+        }
 
-		@Override
-		public void close() {
-			reset();
-		}
+        @Override
+        public void close()
+        {
+            reset();
+        }
 
-	}
+    }
 
-	class LoggerFacade {
-		private final String	name;
-		private final LogDomain	domain;
-		volatile Object			logger;
-		volatile String			prefix;
+    class LoggerFacade
+    {
+        private final String name;
+        private final LogDomain domain;
+        volatile Object logger;
+        volatile String prefix;
 
-		LoggerFacade(LogDomain logDomain, String name) {
-			this.domain = logDomain;
-			this.name = name;
-		}
+        LoggerFacade(LogDomain logDomain, String name)
+        {
+            this.domain = logDomain;
+            this.name = name;
+        }
 
-		void reset() {
-			logger = null;
-		}
+        void reset()
+        {
+            logger = null;
+        }
 
-		Object getLogger() {
-			Object l = this.logger;
-			if (l == null) {
-				l = lock.getLogger(this, domain.bundle, name);
-			}
-			return l;
-		}
+        Object getLogger()
+        {
+            Object l = this.logger;
+            if (l == null)
+            {
+                l = lock.getLogger(this, domain.bundle, name);
+            }
+            return l;
+        }
 
-		Bundle getBundle() {
-			return domain.bundle;
-		}
+        Bundle getBundle()
+        {
+            return domain.bundle;
+        }
 
-		String getName() {
-			return name;
-		}
+        String getName()
+        {
+            return name;
+        }
 
-	}
+    }
 
-	public void close() {
-		if (closed.compareAndSet(false, true)) {
-			lock.close();
-			super.close();
-			this.context.removeBundleListener(this);
-		}
-	}
+    public void close()
+    {
+        if (closed.compareAndSet(false, true))
+        {
+            lock.close();
+            super.close();
+            this.context.removeBundleListener(this);
+        }
+    }
 
-	LoggerFacade createLoggerFacade(LogDomain logDomain, String name) {
-		assert !closed.get();
-		return new LoggerFacade(logDomain, name);
-	}
+    LoggerFacade createLoggerFacade(LogDomain logDomain, String name)
+    {
+        assert !closed.get();
+        return new LoggerFacade(logDomain, name);
+    }
 
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogManager.java b/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogManager.java
index 1aa1f70..56e88b5 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogManager.java
@@ -36,268 +36,322 @@
  * {@link ExtLogManager} implements the extension behavior. The {@link #scr()}
  * method makes this distinction based on the configuration.
  */
-public class ScrLogManager extends LogManager {
+public class ScrLogManager extends LogManager
+{
 
-	private final Bundle			bundle;
-	private final ScrConfiguration	config;
+    private final Bundle bundle;
+    private final ScrConfiguration config;
 
-	/**
-	 * Get a new log manager based on the configuration.
-	 * 
-	 * @param context
-	 *                    the bundle context of the SCR bundle
-	 * @param config
-	 *                    the SCR configuration
-	 * @return a proper ScrLogManager
-	 */
+    /**
+     * Get a new log manager based on the configuration.
+     * 
+     * @param context
+     *                    the bundle context of the SCR bundle
+     * @param config
+     *                    the SCR configuration
+     * @return a proper ScrLogManager
+     */
 
-	public static ScrLogger scr(BundleContext context, ScrConfiguration config) {
+    public static ScrLogger scr(BundleContext context, ScrConfiguration config)
+    {
         ScrLogManager manager;
-		if (config.isLogExtension())
+        if (config.isLogExtension())
             manager = new ExtLogManager(context, config);
-		else
+        else
             manager = new ScrLogManager(context, config);
         manager.open();
         return manager.scr();
-	}
+    }
 
-	ScrLogManager(BundleContext context, ScrConfiguration config) {
-		super(context);
-		this.config = config;
-		this.bundle = context.getBundle();
-	}
+    ScrLogManager(BundleContext context, ScrConfiguration config)
+    {
+        super(context);
+        this.config = config;
+        this.bundle = context.getBundle();
+    }
 
-	/**
-	 * This logger is used for the main code of SCR. This will use the SCR
-	 * bundle & the {@link Logger#ROOT_LOGGER_NAME}
-	 * 
-	 * @return an Scr Logger.
-	 */
-	public ScrLogger scr() {
-		ScrLoggerFacade scrl = super.getLogger(bundle, Logger.ROOT_LOGGER_NAME, ScrLoggerFacade.class);
-		scrl.setPrefix(getBundleIdentifier(bundle));
-		return scrl;
-	}
+    /**
+     * This logger is used for the main code of SCR. This will use the SCR
+     * bundle & the {@link Logger#ROOT_LOGGER_NAME}
+     * 
+     * @return an Scr Logger.
+     */
+    public ScrLogger scr()
+    {
+        ScrLoggerFacade scrl = super.getLogger(bundle, Logger.ROOT_LOGGER_NAME,
+            ScrLoggerFacade.class);
+        scrl.setPrefix(getBundleIdentifier(bundle));
+        return scrl;
+    }
 
-	/**
-	 * This logger is used for the logging on a per bundle basis. This will use
-	 * the target bundle & the {@link Logger#ROOT_LOGGER_NAME}
-	 * 
-	 * @param bundle
-	 *                   the target bundle
-	 * @return a logger suitable to log bundle entries
-	 */
-	public BundleLogger bundle(Bundle bundle) {
-		ScrLoggerFacade logger = getLogger(bundle, Logger.ROOT_LOGGER_NAME, ScrLoggerFacade.class);
-		logger.setPrefix(getBundleIdentifier(bundle));
-		return logger;
-	}
+    /**
+     * This logger is used for the logging on a per bundle basis. This will use
+     * the target bundle & the {@link Logger#ROOT_LOGGER_NAME}
+     * 
+     * @param bundle
+     *                   the target bundle
+     * @return a logger suitable to log bundle entries
+     */
+    public BundleLogger bundle(Bundle bundle)
+    {
+        ScrLoggerFacade logger = getLogger(bundle, Logger.ROOT_LOGGER_NAME,
+            ScrLoggerFacade.class);
+        logger.setPrefix(getBundleIdentifier(bundle));
+        return logger;
+    }
 
-	/**
-	 * This logger is used for the logging on a per bundle basis. This will use
-	 * the target bundle & the implementation class as logger name.
-	 * 
-	 * @param bundle
-	 *                   the target bundle
-	 * @return a logger suitable to log bundle entries
-	 */
-	public ComponentLogger component(Bundle bundle, String implementationClass, String name) {
+    /**
+     * This logger is used for the logging on a per bundle basis. This will use
+     * the target bundle & the implementation class as logger name.
+     * 
+     * @param bundle
+     *                   the target bundle
+     * @return a logger suitable to log bundle entries
+     */
+    public ComponentLogger component(Bundle bundle, String implementationClass,
+        String name)
+    {
 
-		// assert bundle != null;
-		// assert bundle.getSymbolicName() != null : "scr requires recent
-		// bundles";
-		// assert implementationClass != null;
-		// assert name != null;
+        // assert bundle != null;
+        // assert bundle.getSymbolicName() != null : "scr requires recent
+        // bundles";
+        // assert implementationClass != null;
+        // assert name != null;
 
-		ScrLoggerFacade facade = getLogger(bundle, implementationClass, ScrLoggerFacade.class);
-		facade.setComponentId(-1);
-		return (ComponentLogger) facade;
-	}
+        ScrLoggerFacade facade = getLogger(bundle, implementationClass,
+            ScrLoggerFacade.class);
+        facade.setComponentId(-1);
+        return (ComponentLogger) facade;
+    }
 
-	class ScrLoggerFacade extends LoggerFacade implements InternalLogger, ScrLogger, BundleLogger, ComponentLogger {
-		ScrLoggerFacade(LogDomain logDomain, String name) {
-			super(logDomain, name);
-		}
+    class ScrLoggerFacade extends LoggerFacade implements InternalLogger, ScrLogger, BundleLogger, ComponentLogger
+    {
+        ScrLoggerFacade(LogDomain logDomain, String name)
+        {
+            super(logDomain, name);
+        }
 
-		@Override
-		public void setComponentId(long id) {
-			setPrefix(componentPrefix(this, id));
-		}
+        @Override
+        public void setComponentId(long id)
+        {
+            setPrefix(componentPrefix(this, id));
+        }
 
-		public boolean isLogEnabled(Level level) {
+        public boolean isLogEnabled(Level level)
+        {
 
-			// assert !closed.get();
+            // assert !closed.get();
 
-			Object checkLogger = getLogger();
-			if (checkLogger != null) {
-			    Logger logger = (Logger) checkLogger;
-				switch (level) {
-				case AUDIT:
-					return true;
-				case ERROR:
-					return logger.isErrorEnabled();
-				case WARN:
-					return logger.isWarnEnabled();
-				case INFO:
-					return logger.isInfoEnabled();
-				case TRACE:
-					return logger.isTraceEnabled();
-				case DEBUG:
-				default:
-					return logger.isDebugEnabled();
-				}
-			} else {
-				return getLogLevel().implies(level);
-			}
-		}
+            Object checkLogger = getLogger();
+            if (checkLogger != null)
+            {
+                Logger logger = (Logger) checkLogger;
+                switch (level)
+                {
+                    case AUDIT:
+                        return true;
+                    case ERROR:
+                        return logger.isErrorEnabled();
+                    case WARN:
+                        return logger.isWarnEnabled();
+                    case INFO:
+                        return logger.isInfoEnabled();
+                    case TRACE:
+                        return logger.isTraceEnabled();
+                    case DEBUG:
+                    default:
+                        return logger.isDebugEnabled();
+                }
+            }
+            else
+            {
+                return getLogLevel().implies(level);
+            }
+        }
 
-		@Override
-		public void log(Level level, String format, Throwable ex, Object... arguments) {
-			if (isLogEnabled(level))
-				log0(level, format(format, arguments), ex);
-		}
+        @Override
+        public void log(Level level, String format, Throwable ex, Object... arguments)
+        {
+            if (isLogEnabled(level))
+                log0(level, format(format, arguments), ex);
+        }
 
-		@Override
-		public void log(Level level, String message, Throwable ex) {
-			if (isLogEnabled(level))
-				log0(level, message, ex);
-		}
+        @Override
+        public void log(Level level, String message, Throwable ex)
+        {
+            if (isLogEnabled(level))
+                log0(level, message, ex);
+        }
 
-		void log0(Level level, String message, Throwable ex) {
-			if (prefix != null && prefix.length() > 0) {
-				message = prefix.concat(" ").concat(message);
-			}
-			Object checkLogger = getLogger();
-			if (checkLogger != null) {
-			    Logger logger = (Logger) checkLogger;
-				if (ex == null) {
-					switch (level) {
-					case AUDIT:
-						logger.audit(message);
-						break;
-					case ERROR:
-						logger.error(message);
-						break;
-					case WARN:
-						logger.warn(message);
-						break;
-					case INFO:
-						logger.info(message);
-						break;
-					case TRACE:
-						logger.trace(message);
-						break;
-					case DEBUG:
-					default:
-						logger.debug(message);
-					}
-				} else {
-					switch (level) {
-					case AUDIT:
-						logger.audit(message, ex);
-						break;
-					case ERROR:
-						logger.error(message, ex);
-						break;
-					case WARN:
-						logger.warn(message, ex);
-						break;
-					case INFO:
-						logger.info(message, ex);
-						break;
-					case TRACE:
-						logger.trace(message, ex);
-						break;
-					case DEBUG:
-					default:
-						logger.debug(message, ex);
-					}
-				}
-			} else {
-				StringWriter buf = new StringWriter();
-				String l = String.format("%-5s", level);
-				buf.append(l).append(" : ").append(message);
-				if (ex != null) {
-					try (PrintWriter pw = new PrintWriter(buf)) {
-						pw.println();
-						ex.printStackTrace(pw);
-					}
-				}
+        void log0(Level level, String message, Throwable ex)
+        {
+            if (prefix != null && prefix.length() > 0)
+            {
+                message = prefix.concat(" ").concat(message);
+            }
+            Object checkLogger = getLogger();
+            if (checkLogger != null)
+            {
+                Logger logger = (Logger) checkLogger;
+                if (ex == null)
+                {
+                    switch (level)
+                    {
+                        case AUDIT:
+                            logger.audit(message);
+                            break;
+                        case ERROR:
+                            logger.error(message);
+                            break;
+                        case WARN:
+                            logger.warn(message);
+                            break;
+                        case INFO:
+                            logger.info(message);
+                            break;
+                        case TRACE:
+                            logger.trace(message);
+                            break;
+                        case DEBUG:
+                        default:
+                            logger.debug(message);
+                    }
+                }
+                else
+                {
+                    switch (level)
+                    {
+                        case AUDIT:
+                            logger.audit(message, ex);
+                            break;
+                        case ERROR:
+                            logger.error(message, ex);
+                            break;
+                        case WARN:
+                            logger.warn(message, ex);
+                            break;
+                        case INFO:
+                            logger.info(message, ex);
+                            break;
+                        case TRACE:
+                            logger.trace(message, ex);
+                            break;
+                        case DEBUG:
+                        default:
+                            logger.debug(message, ex);
+                    }
+                }
+            }
+            else
+            {
+                StringWriter buf = new StringWriter();
+                String l = String.format("%-5s", level);
+                buf.append(l).append(" : ").append(message);
+                if (ex != null)
+                {
+                    try (PrintWriter pw = new PrintWriter(buf))
+                    {
+                        pw.println();
+                        ex.printStackTrace(pw);
+                    }
+                }
 
-				@SuppressWarnings("resource")
-				PrintStream out = level.err() ? System.err : System.out;
-				out.println(buf);
-			}
-		}
+                @SuppressWarnings("resource")
+                PrintStream out = level.err() ? System.err : System.out;
+                out.println(buf);
+            }
+        }
 
-		void setPrefix(String prefix) {
-			this.prefix = prefix;
-		}
+        void setPrefix(String prefix)
+        {
+            this.prefix = prefix;
+        }
 
-		@Override
-		public ComponentLogger component(Bundle bundle, String implementationClassName, String name) {
-			// assert !closed.get();
-			return ScrLogManager.this.component(bundle, implementationClassName, name);
-		}
+        @Override
+        public ComponentLogger component(Bundle bundle, String implementationClassName,
+            String name)
+        {
+            // assert !closed.get();
+            return ScrLogManager.this.component(bundle, implementationClassName, name);
+        }
 
-		@Override
-		public BundleLogger bundle(Bundle bundle) {
-			// assert !closed.get();
-			return ScrLogManager.this.bundle(bundle);
-		}
+        @Override
+        public BundleLogger bundle(Bundle bundle)
+        {
+            // assert !closed.get();
+            return ScrLogManager.this.bundle(bundle);
+        }
 
-		@Override
-		public void close() {
-			// assert !closed.get();
-			ScrLogManager.this.close();
-		}
-	};
+        @Override
+        public void close()
+        {
+            // assert !closed.get();
+            ScrLogManager.this.close();
+        }
+    };
 
-	LoggerFacade createLoggerFacade(LogDomain logDomain, String name) {
-		// assert !closed.get();
-		return new ScrLoggerFacade(logDomain, name);
-	}
+    LoggerFacade createLoggerFacade(LogDomain logDomain, String name)
+    {
+        // assert !closed.get();
+        return new ScrLoggerFacade(logDomain, name);
+    }
 
-	Level getLogLevel() {
-		return config.getLogLevel();
-	}
+    Level getLogLevel()
+    {
+        return config.getLogLevel();
+    }
 
-	String getBundleIdentifier(final Bundle bundle) {
-		final StringBuilder sb = new StringBuilder("bundle ");
+    String getBundleIdentifier(final Bundle bundle)
+    {
+        final StringBuilder sb = new StringBuilder("bundle ");
 
-		if (bundle.getSymbolicName() != null) {
-			sb.append(bundle.getSymbolicName());
-			sb.append(':');
-			sb.append(bundle.getVersion());
-			sb.append(" (");
-			sb.append(bundle.getBundleId());
-			sb.append(")");
-		} else {
-			sb.append(bundle.getBundleId());
-		}
+        if (bundle.getSymbolicName() != null)
+        {
+            sb.append(bundle.getSymbolicName());
+            sb.append(':');
+            sb.append(bundle.getVersion());
+            sb.append(" (");
+            sb.append(bundle.getBundleId());
+            sb.append(")");
+        }
+        else
+        {
+            sb.append(bundle.getBundleId());
+        }
 
-		return sb.toString();
-	}
+        return sb.toString();
+    }
 
-	String componentPrefix(ScrLoggerFacade slf, long id) {
-		if (id >= 0) {
-			return getBundleIdentifier(slf.getBundle()) + "[" + slf.getName() + "(" + id + ")] :";
-		} else {
-			return getBundleIdentifier(slf.getBundle()) + "[" + slf.getName() + "] :";
-		}
-	}
+    String componentPrefix(ScrLoggerFacade slf, long id)
+    {
+        if (id >= 0)
+        {
+            return getBundleIdentifier(slf.getBundle()) + "[" + slf.getName() + "(" + id
+                + ")] :";
+        }
+        else
+        {
+            return getBundleIdentifier(slf.getBundle()) + "[" + slf.getName() + "] :";
+        }
+    }
 
-	String format(final String pattern, final Object... arguments) {
-		if (arguments == null || arguments.length == 0) {
-			return pattern;
-		} else {
-			for (int i = 0; i < arguments.length; i++) {
-				if (arguments[i] instanceof Bundle) {
-					arguments[i] = getBundleIdentifier((Bundle) arguments[i]);
-				}
-			}
-			return MessageFormat.format(pattern, arguments);
-		}
-	}
+    String format(final String pattern, final Object... arguments)
+    {
+        if (arguments == null || arguments.length == 0)
+        {
+            return pattern;
+        }
+        else
+        {
+            for (int i = 0; i < arguments.length; i++)
+            {
+                if (arguments[i] instanceof Bundle)
+                {
+                    arguments[i] = getBundleIdentifier((Bundle) arguments[i]);
+                }
+            }
+            return MessageFormat.format(pattern, arguments);
+        }
+    }
 
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogger.java b/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogger.java
index cbf8a42..09f085a 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogger.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/logger/ScrLogger.java
@@ -24,15 +24,16 @@
 /**
  * Logger used by SCR main code
  */
-public interface ScrLogger extends InternalLogger {
+public interface ScrLogger extends InternalLogger
+{
 
-	/**
-	 * Create a bundle logger
-	 */
-	BundleLogger bundle(Bundle bundle);
+    /**
+     * Create a bundle logger
+     */
+    BundleLogger bundle(Bundle bundle);
 
-	/**
-	 * Close the log manager
-	 */
-	void close();
+    /**
+     * Close the log manager
+     */
+    void close();
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConstructorTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConstructorTest.java
index 1cba156..548a284 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConstructorTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConstructorTest.java
@@ -20,16 +20,24 @@
 
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import java.util.Collection;
 
 import org.apache.felix.scr.integration.components.ConstructorComponent;
+import org.apache.felix.scr.integration.components.ConstructorMultiReference;
+import org.apache.felix.scr.integration.components.ConstructorSingleReference;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceFactory;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
 
 import junit.framework.Assert;
@@ -49,6 +57,10 @@
         // paxRunnerVmOption = DEBUG_VM_OPTION;
     }
 
+    static final String SINGLE_REFERENCE = "SingleReference";
+    static final String MULTI_REFERENCE_A = "MultiReferenceA";
+    static final String MULTI_REFERENCE_B = "MultiReferenceB";
+    static final String MULTI_REFERENCE_C = "MultiReferenceC";
 
     @Test
     public void test_constructor_success() throws Exception
@@ -76,6 +88,8 @@
             Assert.assertEquals( "Nothing for filter: " + filter, 1, srs.size() );
             ServiceReference<S> sr = srs.iterator().next();
             assertNull(bundleContext.getService( sr ));
+            findComponentConfigurationByName(dto.description.name,
+                ComponentConfigurationDTO.FAILED_ACTIVATION);
         }
         catch ( InvalidSyntaxException e )
         {
@@ -101,9 +115,16 @@
     {
         final String componentname = "ConstructorComponent.refsingle";
 
-        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname, ComponentConfigurationDTO.SATISFIED);
+        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname,
+            ComponentConfigurationDTO.UNSATISFIED_REFERENCE);
         assertEquals(1, cc.description.init);
 
+        getDisabledConfigurationAndEnable(SINGLE_REFERENCE,
+            ComponentConfigurationDTO.SATISFIED);
+
+        cc = findComponentConfigurationByName(componentname,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
         ConstructorComponent cmp = this.getServiceFromConfiguration(cc, ConstructorComponent.class);
 
         final String msg = cmp.test();
@@ -112,17 +133,186 @@
     }
 
     @Test
+    public void test_constructor_singleRefOptional() throws Exception
+    {
+
+        final String componentname = "ConstructorComponent.refsingleoptional";
+        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
+
+        ConstructorComponent cmp1 = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
+        final String msg1 = cmp1.test();
+        assertEquals("Wrong activate message.", "ref is null", msg1);
+
+        getDisabledConfigurationAndEnable(SINGLE_REFERENCE,
+            ComponentConfigurationDTO.SATISFIED);
+
+        cc = findComponentConfigurationByName(componentname,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
+
+        ConstructorComponent cmp2 = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
+
+        final String msg2 = cmp2.test();
+        assertNull(msg2);
+        disableAndCheck(cc);
+    }
+
+    @Test
     public void test_constructor_multiRef() throws Exception
     {
         final String componentname = "ConstructorComponent.refmulti";
 
-        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname, ComponentConfigurationDTO.SATISFIED);
+        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname,
+            ComponentConfigurationDTO.UNSATISFIED_REFERENCE);
         assertEquals(1, cc.description.init);
 
-        ConstructorComponent cmp = this.getServiceFromConfiguration(cc, ConstructorComponent.class);
+        // disable in order to get all the refs enabled
+        disableAndCheck(cc);
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_A,
+            ComponentConfigurationDTO.SATISFIED);
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_B,
+            ComponentConfigurationDTO.SATISFIED);
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_C,
+            ComponentConfigurationDTO.SATISFIED);
+
+        cc = getDisabledConfigurationAndEnable(componentname,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
+
+        ConstructorComponent cmp = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
 
         final String msg = cmp.test();
         assertNull(msg);
         disableAndCheck( cc );
     }
+
+    @Test
+    public void test_constructor_multiRefOptional() throws Exception
+    {
+        final String componentname = "ConstructorComponent.refmultioptional";
+        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
+
+        ConstructorComponent cmp1 = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
+
+        final String msg1 = cmp1.test();
+        assertEquals("Wrong refs size.", "ref has size: 0", msg1);
+
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_A,
+            ComponentConfigurationDTO.SATISFIED);
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_B,
+            ComponentConfigurationDTO.SATISFIED);
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_C,
+            ComponentConfigurationDTO.SATISFIED);
+
+        ConstructorComponent cmp2 = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
+        assertTrue("Different component instances.", cmp1 == cmp2);
+
+        // not greedy so the collection of refs does not get updated.
+        final String msg2 = cmp2.test();
+        assertEquals("Wrong refs size.", "ref has size: 0", msg2);
+
+        disableAndCheck(cc);
+    }
+
+    @Test
+    public void test_constructor_multiRefOptionalGreedy() throws Exception
+    {
+        final String componentname = "ConstructorComponent.refmultioptionalgreedy";
+        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentname,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
+
+        ConstructorComponent cmp1 = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
+
+        final String msg1 = cmp1.test();
+        assertEquals("Wrong refs size.", "ref has size: 0", msg1);
+
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_A,
+            ComponentConfigurationDTO.SATISFIED);
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_B,
+            ComponentConfigurationDTO.SATISFIED);
+        getDisabledConfigurationAndEnable(MULTI_REFERENCE_C,
+            ComponentConfigurationDTO.SATISFIED);
+
+        ConstructorComponent cmp2 = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
+
+        assertFalse("Same component instances.", cmp1 == cmp2);
+
+        // greedy so the collection of refs does should be updated.
+        final String msg2 = cmp2.test();
+        assertNull(msg2);
+
+        disableAndCheck(cc);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test_constructor_failGetService() throws Exception
+    {
+        ServiceFactory<?> failFactory = new ServiceFactory<Object>()
+        {
+            @Override
+            public Object getService(Bundle bundle,
+                ServiceRegistration<Object> registration)
+            {
+                throw new ServiceException("Testing failed get service.");
+            }
+
+            @Override
+            public void ungetService(Bundle bundle,
+                ServiceRegistration<Object> registration, Object service)
+            {
+                // nothing to do
+            }
+        };
+
+        bundleContext.registerService(ConstructorSingleReference.class,
+            (ServiceFactory<ConstructorSingleReference>) failFactory, null);
+        bundleContext.registerService(ConstructorMultiReference.class,
+            (ServiceFactory<ConstructorMultiReference>) failFactory, null);
+
+        // try mandatory components first
+        doTestMandatoryFailGetService("ConstructorComponent.refsingle");
+        doTestMandatoryFailGetService("ConstructorComponent.refmulti");
+
+        // try the optional components second
+        doTestOptionalFailGetService("ConstructorComponent.refsingleoptional",
+            "ref is null");
+        doTestOptionalFailGetService("ConstructorComponent.refmultioptional",
+            "ref has size: 0");
+    }
+
+    private void doTestOptionalFailGetService(String componentName, String expectedMsg)
+        throws Exception
+    {
+        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentName,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
+
+        ConstructorComponent cmp1 = this.getServiceFromConfiguration(cc,
+            ConstructorComponent.class);
+
+        final String msg1 = cmp1.test();
+        assertEquals("Wrong refs size.", expectedMsg, msg1);
+    }
+
+    private void doTestMandatoryFailGetService(String componentName)
+        throws Exception
+    {
+        ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(componentName,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(1, cc.description.init);
+        failGetServiceFromConfiguration(cc, ConstructorComponent.class);
+    }
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorComponent.java b/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorComponent.java
index 1a1d5de..1938e87 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorComponent.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorComponent.java
@@ -120,7 +120,7 @@
         }
         if ( ((List)ref).size() != 3)
         {
-            return "ref has wrong size: " + ((List)ref).size();
+            return "ref has size: " + ((List) ref).size();
         }
         final List<String> names = new ArrayList<>(Arrays.asList("a", "b", "c"));
         for(final Object obj : (List)ref)
diff --git a/scr/src/test/resources/integration_test_constructor.xml b/scr/src/test/resources/integration_test_constructor.xml
index 872bf5c..457a3eb 100644
--- a/scr/src/test/resources/integration_test_constructor.xml
+++ b/scr/src/test/resources/integration_test_constructor.xml
@@ -62,29 +62,66 @@
                    parameter="0"/>
     </scr:component>
 
+    <!-- Use constructor - optional reference - greedy used to force new construction -->
+    <scr:component name="ConstructorComponent.refsingleoptional" enabled="false" activate="activator"
+                   init="1">
+        <implementation class="org.apache.felix.scr.integration.components.ConstructorComponent" />
+        <service factory="false">
+            <provide interface="org.apache.felix.scr.integration.components.ConstructorComponent"/>
+        </service>
+        <reference interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"
+                   cardinality="0..1"
+                   parameter="0"
+                   policy-option="greedy"/>
+    </scr:component>
+
+    <!-- Use constructor - optional multi reference -->
+    <scr:component name="ConstructorComponent.refmultioptional" enabled="false" activate="activator"
+                   init="1">
+        <implementation class="org.apache.felix.scr.integration.components.ConstructorComponent" />
+        <service factory="false">
+            <provide interface="org.apache.felix.scr.integration.components.ConstructorComponent"/>
+        </service>
+        <reference interface="org.apache.felix.scr.integration.components.ConstructorMultiReference"
+                   cardinality="0..n"
+                   parameter="0"/>
+    </scr:component>
+
+    <scr:component name="ConstructorComponent.refmultioptionalgreedy" enabled="false" activate="activator"
+                   init="1">
+        <implementation class="org.apache.felix.scr.integration.components.ConstructorComponent" />
+        <service factory="false">
+            <provide interface="org.apache.felix.scr.integration.components.ConstructorComponent"/>
+        </service>
+        <reference interface="org.apache.felix.scr.integration.components.ConstructorMultiReference"
+                   cardinality="0..n"
+                   parameter="0"
+                   policy-option="greedy"/>
+    </scr:component>
+
     <!-- References -->
-    <scr:component name="SingleReference" activate="activator">
+    <scr:component name="SingleReference" enabled="false" activate="activator">
         <implementation class="org.apache.felix.scr.integration.components.ConstructorSingleReference" />
         <service factory="false">
             <provide interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"/>
         </service>
         <property name="name" value="single"/>
     </scr:component>
-    <scr:component name="MultiReferenceA" activate="activator">
+    <scr:component name="MultiReferenceA" enabled="false" activate="activator">
         <implementation class="org.apache.felix.scr.integration.components.ConstructorMultiReference" />
         <service factory="false">
             <provide interface="org.apache.felix.scr.integration.components.ConstructorMultiReference"/>
         </service>
         <property name="name" value="a"/>
     </scr:component>
-    <scr:component name="MultiReferenceB" activate="activator">
+    <scr:component name="MultiReferenceB" enabled="false" activate="activator">
         <implementation class="org.apache.felix.scr.integration.components.ConstructorMultiReference" />
         <service factory="false">
             <provide interface="org.apache.felix.scr.integration.components.ConstructorMultiReference"/>
         </service>
         <property name="name" value="b"/>
     </scr:component>
-    <scr:component name="MultiReferenceC" activate="activator">
+    <scr:component name="MultiReferenceC" enabled="false" activate="activator">
         <implementation class="org.apache.felix.scr.integration.components.ConstructorMultiReference" />
         <service factory="false">
             <provide interface="org.apache.felix.scr.integration.components.ConstructorMultiReference"/>
diff --git a/utils/pom.xml b/utils/pom.xml
index c63306c..f15e5d8 100644
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -27,14 +27,15 @@
     <modelVersion>4.0.0</modelVersion>
     <name>Apache Felix Utils</name>
     <description>Utility classes for OSGi.</description>
-    <version>1.11.5-SNAPSHOT</version>
+    <version>1.11.7-SNAPSHOT</version>
     <artifactId>org.apache.felix.utils</artifactId>
 
     <scm>
         <connection>scm:git:https://github.com/apache/felix-dev.git</connection>
         <developerConnection>scm:git:https://github.com/apache/felix-dev.git</developerConnection>
         <url>https://gitbox.apache.org/repos/asf?p=felix-dev.git</url>
-    </scm>
+      <tag>HEAD</tag>
+  </scm>
 
     <properties>
         <felix.java.version>7</felix.java.version>
diff --git a/utils/src/main/java/org/apache/felix/utils/resource/ResourceBuilder.java b/utils/src/main/java/org/apache/felix/utils/resource/ResourceBuilder.java
index a2cec7f..a269300 100644
--- a/utils/src/main/java/org/apache/felix/utils/resource/ResourceBuilder.java
+++ b/utils/src/main/java/org/apache/felix/utils/resource/ResourceBuilder.java
@@ -309,17 +309,14 @@
                 clause.attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE, VersionRange.parseVersionRange(v.toString()));
             }
 
-            // Verify java.* is not imported, nor any duplicate imports.
+            // Verify no duplicate imports, nor '.' or empty packages.
             for (String pkgName : clause.paths) {
                 if (!dupeSet.contains(pkgName)) {
-                    // Verify that java.* packages are not imported.
-                    if (pkgName.startsWith("java.")) {
-                        throw new BundleException("Importing java.* packages not allowed: " + pkgName);
                     // The character "." has no meaning in the OSGi spec except
                     // when placed on the bundle class path. Some people, however,
                     // mistakenly think it means the default package when imported
                     // or exported. This is not correct. It is invalid.
-                    } else if (pkgName.equals(".")) {
+                    if (pkgName.equals(".")) {
                         throw new BundleException("Importing '.' is invalid.");
                     // Make sure a package name was specified.
                     } else if (pkgName.length() == 0) {
diff --git a/utils/src/test/java/org/apache/felix/utils/resource/ResourceBuilderTest.java b/utils/src/test/java/org/apache/felix/utils/resource/ResourceBuilderTest.java
new file mode 100644
index 0000000..eb8bcfe
--- /dev/null
+++ b/utils/src/test/java/org/apache/felix/utils/resource/ResourceBuilderTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.felix.utils.resource;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ResourceBuilderTest {
+    @Test
+    public void testImportJavaPackage() throws Exception {
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Bundle-ManifestVersion", "2");
+        headers.put("Bundle-SymbolicName", "foo");
+        headers.put("Import-Package", "java.util");
+        ResourceBuilder.build("http://foo", headers);
+    }
+}
diff --git a/webconsole/changelog.txt b/webconsole/changelog.txt
index e00b512..9ccd352 100644
--- a/webconsole/changelog.txt
+++ b/webconsole/changelog.txt
@@ -1,6 +1,17 @@
-Changes in 4.5.6
+Changes in 4.6.2
 ----------------
 ** Bug
+    * [FELIX-6375] - Configuration Admin Service not available with org.apache.felix.webconsole_4.6.0.all
+    * [FELIX-6392] - Webconsole configadmin javascript error: Uncaught TypeError: parsers is undefined
+
+
+Changes in 4.6.0
+----------------
+** Improvement
+    * [FELIX-6366] - Update to jQuery 3.5.1 and jQuery migrate 3.3.0
+    * [FELIX-6363] - Simplify updating of OSGi configurations through REST API
+    * [FELIX-6370] - Provide a User interface for checks within plugins
+** Bug
     * [FELIX-6341] - ConfigAdmin - deleting a configuration logs a string that should be translated
     * [FELIX-6328] - Web Console (All In One) imports javax.portlet via fileupload
 
diff --git a/webconsole/pom.xml b/webconsole/pom.xml
index 085b56c..c5738f0 100644
--- a/webconsole/pom.xml
+++ b/webconsole/pom.xml
@@ -28,7 +28,7 @@
 
     <artifactId>org.apache.felix.webconsole</artifactId>
     <packaging>bundle</packaging>
-    <version>4.5.5-SNAPSHOT</version>
+    <version>4.6.1-SNAPSHOT</version>
 
     <name>Apache Felix Web Management Console</name>
     <description>
@@ -39,9 +39,9 @@
     
     <properties>
         <webconsole.exports>
-            org.apache.felix.webconsole;version=3.3.0;provide:=true,
-            org.apache.felix.webconsole.bundleinfo;version=1.0.0;provide:=true,
-            org.apache.felix.webconsole.i18n;version=1.0.0;provide:=true
+            org.apache.felix.webconsole;provide:=true,
+            org.apache.felix.webconsole.bundleinfo;provide:=true,
+            org.apache.felix.webconsole.i18n;provide:=true
         </webconsole.exports>
     </properties>
 
@@ -112,8 +112,10 @@
                         <Export-Package>
                             ${webconsole.exports}
                         </Export-Package>
+                        <!-- Import-Package header is also used for the all bundle -->
                         <Import-Package>
                             javax.servlet.*;version="[2.4,4)",
+                            !javax.portlet,
                             !org.apache.felix.bundlerepository,
                             !org.osgi.service.obr,
                             !org.osgi.service.cm,
@@ -125,6 +127,7 @@
                             !org.osgi.service.wireadmin,
                             *
                         </Import-Package>
+                        <!-- DynamicImport-Package header is also used for the all bundle -->
                         <DynamicImport-Package>
                             org.apache.felix.bundlerepository;version="[2.0,3)",
                             org.osgi.service.obr;version="[1.0,2)",
@@ -145,6 +148,14 @@
                         </_removeheaders>
                     </instructions>
                 </configuration>
+                <executions>
+                    <execution>
+                        <id>baseline</id>
+                        <goals>
+                            <goal>baseline</goal>
+                        </goals>
+                    </execution>
+                </executions>
             </plugin>
             <plugin>
                 <artifactId>maven-javadoc-plugin</artifactId>
@@ -163,8 +174,8 @@
                     </includes>
                     <excludes>
                         <exclude>src/main/appended-resources/**</exclude>
-                        <exclude>src/main/resources/res/lib/jquery-3.4.1.js</exclude>
-                        <exclude>src/main/resources/res/lib/jquery-migrate-3.1.0.js</exclude>
+                        <exclude>src/main/resources/res/lib/jquery-3.5.1.js</exclude>
+                        <exclude>src/main/resources/res/lib/jquery-migrate-3.3.0.js</exclude>
                         <exclude>src/main/resources/res/lib/jquery-ui-1.12.1.js</exclude>
                         <exclude>src/main/resources/res/lib/jquery-ui-i18n-1.12.1.js</exclude>
                         <exclude>src/main/resources/res/lib/autosize.min.js</exclude>
@@ -230,7 +241,6 @@
                                            commons-fileupload;inline=true,
                                            commons-io;inline=true
                                        </Embed-Dependency>
-                                       <Import-Package>!javax.portlet,*</Import-Package>                            
                                        <_removeheaders>
                                            Embed-Dependency,Private-Package,Include-Resource
                                        </_removeheaders>
@@ -263,7 +273,7 @@
                 <dependency>
                     <groupId>org.apache.felix</groupId>
                     <artifactId>org.apache.felix.inventory</artifactId>
-                    <version>1.0.0</version>
+                    <version>1.1.0-SNAPSHOT</version>
                     <scope>provided</scope>
                 </dependency>
             </dependencies>
@@ -331,6 +341,13 @@
 
     <dependencies>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.annotation.versioning</artifactId>
+            <version>1.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
             <version>2.4</version>
diff --git a/webconsole/src/main/debug-resources/res/lib/jquery-3.4.1.js b/webconsole/src/main/debug-resources/res/lib/jquery-3.5.1.js
old mode 100755
new mode 100644
similarity index 91%
rename from webconsole/src/main/debug-resources/res/lib/jquery-3.4.1.js
rename to webconsole/src/main/debug-resources/res/lib/jquery-3.5.1.js
index 773ad95..5093733
--- a/webconsole/src/main/debug-resources/res/lib/jquery-3.4.1.js
+++ b/webconsole/src/main/debug-resources/res/lib/jquery-3.5.1.js
@@ -1,5 +1,5 @@
 /*!
- * jQuery JavaScript Library v3.4.1
+ * jQuery JavaScript Library v3.5.1
  * https://jquery.com/
  *
  * Includes Sizzle.js
@@ -9,7 +9,7 @@
  * Released under the MIT license
  * https://jquery.org/license
  *
- * Date: 2019-05-01T21:04Z
+ * Date: 2020-05-04T22:49Z
  */
 ( function( global, factory ) {
 
@@ -47,13 +47,16 @@
 
 var arr = [];
 
-var document = window.document;
-
 var getProto = Object.getPrototypeOf;
 
 var slice = arr.slice;
 
-var concat = arr.concat;
+var flat = arr.flat ? function( array ) {
+	return arr.flat.call( array );
+} : function( array ) {
+	return arr.concat.apply( [], array );
+};
+
 
 var push = arr.push;
 
@@ -86,6 +89,8 @@
 	};
 
 
+var document = window.document;
+
 
 
 	var preservedScriptAttributes = {
@@ -142,7 +147,7 @@
 
 
 var
-	version = "3.4.1",
+	version = "3.5.1",
 
 	// Define a local copy of jQuery
 	jQuery = function( selector, context ) {
@@ -150,11 +155,7 @@
 		// The jQuery object is actually just the init constructor 'enhanced'
 		// Need init if jQuery is called (just allow error to be thrown if not included)
 		return new jQuery.fn.init( selector, context );
-	},
-
-	// Support: Android <=4.0 only
-	// Make sure we trim BOM and NBSP
-	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
+	};
 
 jQuery.fn = jQuery.prototype = {
 
@@ -220,6 +221,18 @@
 		return this.eq( -1 );
 	},
 
+	even: function() {
+		return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+			return ( i + 1 ) % 2;
+		} ) );
+	},
+
+	odd: function() {
+		return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+			return i % 2;
+		} ) );
+	},
+
 	eq: function( i ) {
 		var len = this.length,
 			j = +i + ( i < 0 ? len : 0 );
@@ -353,9 +366,10 @@
 		return true;
 	},
 
-	// Evaluates a script in a global context
-	globalEval: function( code, options ) {
-		DOMEval( code, { nonce: options && options.nonce } );
+	// Evaluates a script in a provided context; falls back to the global one
+	// if not specified.
+	globalEval: function( code, options, doc ) {
+		DOMEval( code, { nonce: options && options.nonce }, doc );
 	},
 
 	each: function( obj, callback ) {
@@ -379,13 +393,6 @@
 		return obj;
 	},
 
-	// Support: Android <=4.0 only
-	trim: function( text ) {
-		return text == null ?
-			"" :
-			( text + "" ).replace( rtrim, "" );
-	},
-
 	// results is for internal usage only
 	makeArray: function( arr, results ) {
 		var ret = results || [];
@@ -472,7 +479,7 @@
 		}
 
 		// Flatten any nested arrays
-		return concat.apply( [], ret );
+		return flat( ret );
 	},
 
 	// A global GUID counter for objects
@@ -489,7 +496,7 @@
 
 // Populate the class2type map
 jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
-function( i, name ) {
+function( _i, name ) {
 	class2type[ "[object " + name + "]" ] = name.toLowerCase();
 } );
 
@@ -511,17 +518,16 @@
 }
 var Sizzle =
 /*!
- * Sizzle CSS Selector Engine v2.3.4
+ * Sizzle CSS Selector Engine v2.3.5
  * https://sizzlejs.com/
  *
  * Copyright JS Foundation and other contributors
  * Released under the MIT license
  * https://js.foundation/
  *
- * Date: 2019-04-08
+ * Date: 2020-03-14
  */
-(function( window ) {
-
+( function( window ) {
 var i,
 	support,
 	Expr,
@@ -561,59 +567,70 @@
 	},
 
 	// Instance methods
-	hasOwn = ({}).hasOwnProperty,
+	hasOwn = ( {} ).hasOwnProperty,
 	arr = [],
 	pop = arr.pop,
-	push_native = arr.push,
+	pushNative = arr.push,
 	push = arr.push,
 	slice = arr.slice,
+
 	// Use a stripped-down indexOf as it's faster than native
 	// https://jsperf.com/thor-indexof-vs-for/5
 	indexOf = function( list, elem ) {
 		var i = 0,
 			len = list.length;
 		for ( ; i < len; i++ ) {
-			if ( list[i] === elem ) {
+			if ( list[ i ] === elem ) {
 				return i;
 			}
 		}
 		return -1;
 	},
 
-	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" +
+		"ismap|loop|multiple|open|readonly|required|scoped",
 
 	// Regular expressions
 
 	// http://www.w3.org/TR/css3-selectors/#whitespace
 	whitespace = "[\\x20\\t\\r\\n\\f]",
 
-	// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
-	identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
+	// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
+	identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
+		"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",
 
 	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
 	attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+
 		// Operator (capture 2)
 		"*([*^$|!~]?=)" + whitespace +
-		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
-		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
-		"*\\]",
+
+		// "Attribute values must be CSS identifiers [capture 5]
+		// or strings [capture 3 or capture 4]"
+		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
+		whitespace + "*\\]",
 
 	pseudos = ":(" + identifier + ")(?:\\((" +
+
 		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
 		// 1. quoted (capture 3; capture 4 or capture 5)
 		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+
 		// 2. simple (capture 6)
 		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+
 		// 3. anything else (capture 2)
 		".*" +
 		")\\)|)",
 
 	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
 	rwhitespace = new RegExp( whitespace + "+", "g" ),
-	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" +
+		whitespace + "+$", "g" ),
 
 	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
-	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace +
+		"*" ),
 	rdescend = new RegExp( whitespace + "|>" ),
 
 	rpseudo = new RegExp( pseudos ),
@@ -625,14 +642,16 @@
 		"TAG": new RegExp( "^(" + identifier + "|[*])" ),
 		"ATTR": new RegExp( "^" + attributes ),
 		"PSEUDO": new RegExp( "^" + pseudos ),
-		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
-			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
-			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
+			whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
+			whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
 		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+
 		// For use in libraries implementing .is()
 		// We use this for POS matching in `select`
-		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
-			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+		"needsContext": new RegExp( "^" + whitespace +
+			"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+			"*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
 	},
 
 	rhtml = /HTML$/i,
@@ -648,18 +667,21 @@
 
 	// CSS escapes
 	// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
-	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
-	funescape = function( _, escaped, escapedWhitespace ) {
-		var high = "0x" + escaped - 0x10000;
-		// NaN means non-codepoint
-		// Support: Firefox<24
-		// Workaround erroneous numeric interpretation of +"0x"
-		return high !== high || escapedWhitespace ?
-			escaped :
+	runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ),
+	funescape = function( escape, nonHex ) {
+		var high = "0x" + escape.slice( 1 ) - 0x10000;
+
+		return nonHex ?
+
+			// Strip the backslash prefix from a non-hex escape sequence
+			nonHex :
+
+			// Replace a hexadecimal escape sequence with the encoded Unicode code point
+			// Support: IE <=11+
+			// For values outside the Basic Multilingual Plane (BMP), manually construct a
+			// surrogate pair
 			high < 0 ?
-				// BMP codepoint
 				String.fromCharCode( high + 0x10000 ) :
-				// Supplemental Plane codepoint (surrogate pair)
 				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
 	},
 
@@ -675,7 +697,8 @@
 			}
 
 			// Control characters and (dependent upon position) numbers get escaped as code points
-			return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+			return ch.slice( 0, -1 ) + "\\" +
+				ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
 		}
 
 		// Other potentially-special ASCII characters get backslash-escaped
@@ -700,18 +723,20 @@
 // Optimize for push.apply( _, NodeList )
 try {
 	push.apply(
-		(arr = slice.call( preferredDoc.childNodes )),
+		( arr = slice.call( preferredDoc.childNodes ) ),
 		preferredDoc.childNodes
 	);
+
 	// Support: Android<4.0
 	// Detect silently failing push.apply
+	// eslint-disable-next-line no-unused-expressions
 	arr[ preferredDoc.childNodes.length ].nodeType;
 } catch ( e ) {
 	push = { apply: arr.length ?
 
 		// Leverage slice if possible
 		function( target, els ) {
-			push_native.apply( target, slice.call(els) );
+			pushNative.apply( target, slice.call( els ) );
 		} :
 
 		// Support: IE<9
@@ -719,8 +744,9 @@
 		function( target, els ) {
 			var j = target.length,
 				i = 0;
+
 			// Can't trust NodeList.length
-			while ( (target[j++] = els[i++]) ) {}
+			while ( ( target[ j++ ] = els[ i++ ] ) ) {}
 			target.length = j - 1;
 		}
 	};
@@ -744,24 +770,21 @@
 
 	// Try to shortcut find operations (as opposed to filters) in HTML documents
 	if ( !seed ) {
-
-		if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
-			setDocument( context );
-		}
+		setDocument( context );
 		context = context || document;
 
 		if ( documentIsHTML ) {
 
 			// If the selector is sufficiently simple, try using a "get*By*" DOM method
 			// (excepting DocumentFragment context, where the methods don't exist)
-			if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+			if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {
 
 				// ID selector
-				if ( (m = match[1]) ) {
+				if ( ( m = match[ 1 ] ) ) {
 
 					// Document context
 					if ( nodeType === 9 ) {
-						if ( (elem = context.getElementById( m )) ) {
+						if ( ( elem = context.getElementById( m ) ) ) {
 
 							// Support: IE, Opera, Webkit
 							// TODO: identify versions
@@ -780,7 +803,7 @@
 						// Support: IE, Opera, Webkit
 						// TODO: identify versions
 						// getElementById can match elements by name instead of ID
-						if ( newContext && (elem = newContext.getElementById( m )) &&
+						if ( newContext && ( elem = newContext.getElementById( m ) ) &&
 							contains( context, elem ) &&
 							elem.id === m ) {
 
@@ -790,12 +813,12 @@
 					}
 
 				// Type selector
-				} else if ( match[2] ) {
+				} else if ( match[ 2 ] ) {
 					push.apply( results, context.getElementsByTagName( selector ) );
 					return results;
 
 				// Class selector
-				} else if ( (m = match[3]) && support.getElementsByClassName &&
+				} else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&
 					context.getElementsByClassName ) {
 
 					push.apply( results, context.getElementsByClassName( m ) );
@@ -806,11 +829,11 @@
 			// Take advantage of querySelectorAll
 			if ( support.qsa &&
 				!nonnativeSelectorCache[ selector + " " ] &&
-				(!rbuggyQSA || !rbuggyQSA.test( selector )) &&
+				( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&
 
 				// Support: IE 8 only
 				// Exclude object elements
-				(nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) {
+				( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) {
 
 				newSelector = selector;
 				newContext = context;
@@ -819,27 +842,36 @@
 				// descendant combinators, which is not what we want.
 				// In such cases, we work around the behavior by prefixing every selector in the
 				// list with an ID selector referencing the scope context.
+				// The technique has to be used as well when a leading combinator is used
+				// as such selectors are not recognized by querySelectorAll.
 				// Thanks to Andrew Dupont for this technique.
-				if ( nodeType === 1 && rdescend.test( selector ) ) {
+				if ( nodeType === 1 &&
+					( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {
 
-					// Capture the context ID, setting it first if necessary
-					if ( (nid = context.getAttribute( "id" )) ) {
-						nid = nid.replace( rcssescape, fcssescape );
-					} else {
-						context.setAttribute( "id", (nid = expando) );
+					// Expand context for sibling selectors
+					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+						context;
+
+					// We can use :scope instead of the ID hack if the browser
+					// supports it & if we're not changing the context.
+					if ( newContext !== context || !support.scope ) {
+
+						// Capture the context ID, setting it first if necessary
+						if ( ( nid = context.getAttribute( "id" ) ) ) {
+							nid = nid.replace( rcssescape, fcssescape );
+						} else {
+							context.setAttribute( "id", ( nid = expando ) );
+						}
 					}
 
 					// Prefix every selector in the list
 					groups = tokenize( selector );
 					i = groups.length;
 					while ( i-- ) {
-						groups[i] = "#" + nid + " " + toSelector( groups[i] );
+						groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
+							toSelector( groups[ i ] );
 					}
 					newSelector = groups.join( "," );
-
-					// Expand context for sibling selectors
-					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
-						context;
 				}
 
 				try {
@@ -872,12 +904,14 @@
 	var keys = [];
 
 	function cache( key, value ) {
+
 		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
 		if ( keys.push( key + " " ) > Expr.cacheLength ) {
+
 			// Only keep the most recent entries
 			delete cache[ keys.shift() ];
 		}
-		return (cache[ key + " " ] = value);
+		return ( cache[ key + " " ] = value );
 	}
 	return cache;
 }
@@ -896,17 +930,19 @@
  * @param {Function} fn Passed the created element and returns a boolean result
  */
 function assert( fn ) {
-	var el = document.createElement("fieldset");
+	var el = document.createElement( "fieldset" );
 
 	try {
 		return !!fn( el );
-	} catch (e) {
+	} catch ( e ) {
 		return false;
 	} finally {
+
 		// Remove from its parent by default
 		if ( el.parentNode ) {
 			el.parentNode.removeChild( el );
 		}
+
 		// release memory in IE
 		el = null;
 	}
@@ -918,11 +954,11 @@
  * @param {Function} handler The method that will be applied
  */
 function addHandle( attrs, handler ) {
-	var arr = attrs.split("|"),
+	var arr = attrs.split( "|" ),
 		i = arr.length;
 
 	while ( i-- ) {
-		Expr.attrHandle[ arr[i] ] = handler;
+		Expr.attrHandle[ arr[ i ] ] = handler;
 	}
 }
 
@@ -944,7 +980,7 @@
 
 	// Check if b follows a
 	if ( cur ) {
-		while ( (cur = cur.nextSibling) ) {
+		while ( ( cur = cur.nextSibling ) ) {
 			if ( cur === b ) {
 				return -1;
 			}
@@ -972,7 +1008,7 @@
 function createButtonPseudo( type ) {
 	return function( elem ) {
 		var name = elem.nodeName.toLowerCase();
-		return (name === "input" || name === "button") && elem.type === type;
+		return ( name === "input" || name === "button" ) && elem.type === type;
 	};
 }
 
@@ -1015,7 +1051,7 @@
 					// Where there is no isDisabled, check manually
 					/* jshint -W018 */
 					elem.isDisabled !== !disabled &&
-						inDisabledFieldset( elem ) === disabled;
+					inDisabledFieldset( elem ) === disabled;
 			}
 
 			return elem.disabled === disabled;
@@ -1037,21 +1073,21 @@
  * @param {Function} fn
  */
 function createPositionalPseudo( fn ) {
-	return markFunction(function( argument ) {
+	return markFunction( function( argument ) {
 		argument = +argument;
-		return markFunction(function( seed, matches ) {
+		return markFunction( function( seed, matches ) {
 			var j,
 				matchIndexes = fn( [], seed.length, argument ),
 				i = matchIndexes.length;
 
 			// Match elements found at the specified indexes
 			while ( i-- ) {
-				if ( seed[ (j = matchIndexes[i]) ] ) {
-					seed[j] = !(matches[j] = seed[j]);
+				if ( seed[ ( j = matchIndexes[ i ] ) ] ) {
+					seed[ j ] = !( matches[ j ] = seed[ j ] );
 				}
 			}
-		});
-	});
+		} );
+	} );
 }
 
 /**
@@ -1073,7 +1109,7 @@
  */
 isXML = Sizzle.isXML = function( elem ) {
 	var namespace = elem.namespaceURI,
-		docElem = (elem.ownerDocument || elem).documentElement;
+		docElem = ( elem.ownerDocument || elem ).documentElement;
 
 	// Support: IE <=8
 	// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
@@ -1091,7 +1127,11 @@
 		doc = node ? node.ownerDocument || node : preferredDoc;
 
 	// Return early if doc is invalid or already selected
-	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+	// Support: IE 11+, Edge 17 - 18+
+	// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+	// two documents; shallow comparisons work.
+	// eslint-disable-next-line eqeqeq
+	if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {
 		return document;
 	}
 
@@ -1100,10 +1140,14 @@
 	docElem = document.documentElement;
 	documentIsHTML = !isXML( document );
 
-	// Support: IE 9-11, Edge
+	// Support: IE 9 - 11+, Edge 12 - 18+
 	// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
-	if ( preferredDoc !== document &&
-		(subWindow = document.defaultView) && subWindow.top !== subWindow ) {
+	// Support: IE 11+, Edge 17 - 18+
+	// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+	// two documents; shallow comparisons work.
+	// eslint-disable-next-line eqeqeq
+	if ( preferredDoc != document &&
+		( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
 
 		// Support: IE 11, Edge
 		if ( subWindow.addEventListener ) {
@@ -1115,25 +1159,36 @@
 		}
 	}
 
+	// Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,
+	// Safari 4 - 5 only, Opera <=11.6 - 12.x only
+	// IE/Edge & older browsers don't support the :scope pseudo-class.
+	// Support: Safari 6.0 only
+	// Safari 6.0 supports :scope but it's an alias of :root there.
+	support.scope = assert( function( el ) {
+		docElem.appendChild( el ).appendChild( document.createElement( "div" ) );
+		return typeof el.querySelectorAll !== "undefined" &&
+			!el.querySelectorAll( ":scope fieldset div" ).length;
+	} );
+
 	/* Attributes
 	---------------------------------------------------------------------- */
 
 	// Support: IE<8
 	// Verify that getAttribute really returns attributes and not properties
 	// (excepting IE8 booleans)
-	support.attributes = assert(function( el ) {
+	support.attributes = assert( function( el ) {
 		el.className = "i";
-		return !el.getAttribute("className");
-	});
+		return !el.getAttribute( "className" );
+	} );
 
 	/* getElement(s)By*
 	---------------------------------------------------------------------- */
 
 	// Check if getElementsByTagName("*") returns only elements
-	support.getElementsByTagName = assert(function( el ) {
-		el.appendChild( document.createComment("") );
-		return !el.getElementsByTagName("*").length;
-	});
+	support.getElementsByTagName = assert( function( el ) {
+		el.appendChild( document.createComment( "" ) );
+		return !el.getElementsByTagName( "*" ).length;
+	} );
 
 	// Support: IE<9
 	support.getElementsByClassName = rnative.test( document.getElementsByClassName );
@@ -1142,38 +1197,38 @@
 	// Check if getElementById returns elements by name
 	// The broken getElementById methods don't pick up programmatically-set names,
 	// so use a roundabout getElementsByName test
-	support.getById = assert(function( el ) {
+	support.getById = assert( function( el ) {
 		docElem.appendChild( el ).id = expando;
 		return !document.getElementsByName || !document.getElementsByName( expando ).length;
-	});
+	} );
 
 	// ID filter and find
 	if ( support.getById ) {
-		Expr.filter["ID"] = function( id ) {
+		Expr.filter[ "ID" ] = function( id ) {
 			var attrId = id.replace( runescape, funescape );
 			return function( elem ) {
-				return elem.getAttribute("id") === attrId;
+				return elem.getAttribute( "id" ) === attrId;
 			};
 		};
-		Expr.find["ID"] = function( id, context ) {
+		Expr.find[ "ID" ] = function( id, context ) {
 			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
 				var elem = context.getElementById( id );
 				return elem ? [ elem ] : [];
 			}
 		};
 	} else {
-		Expr.filter["ID"] =  function( id ) {
+		Expr.filter[ "ID" ] =  function( id ) {
 			var attrId = id.replace( runescape, funescape );
 			return function( elem ) {
 				var node = typeof elem.getAttributeNode !== "undefined" &&
-					elem.getAttributeNode("id");
+					elem.getAttributeNode( "id" );
 				return node && node.value === attrId;
 			};
 		};
 
 		// Support: IE 6 - 7 only
 		// getElementById is not reliable as a find shortcut
-		Expr.find["ID"] = function( id, context ) {
+		Expr.find[ "ID" ] = function( id, context ) {
 			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
 				var node, i, elems,
 					elem = context.getElementById( id );
@@ -1181,7 +1236,7 @@
 				if ( elem ) {
 
 					// Verify the id attribute
-					node = elem.getAttributeNode("id");
+					node = elem.getAttributeNode( "id" );
 					if ( node && node.value === id ) {
 						return [ elem ];
 					}
@@ -1189,8 +1244,8 @@
 					// Fall back on getElementsByName
 					elems = context.getElementsByName( id );
 					i = 0;
-					while ( (elem = elems[i++]) ) {
-						node = elem.getAttributeNode("id");
+					while ( ( elem = elems[ i++ ] ) ) {
+						node = elem.getAttributeNode( "id" );
 						if ( node && node.value === id ) {
 							return [ elem ];
 						}
@@ -1203,7 +1258,7 @@
 	}
 
 	// Tag
-	Expr.find["TAG"] = support.getElementsByTagName ?
+	Expr.find[ "TAG" ] = support.getElementsByTagName ?
 		function( tag, context ) {
 			if ( typeof context.getElementsByTagName !== "undefined" ) {
 				return context.getElementsByTagName( tag );
@@ -1218,12 +1273,13 @@
 			var elem,
 				tmp = [],
 				i = 0,
+
 				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
 				results = context.getElementsByTagName( tag );
 
 			// Filter out possible comments
 			if ( tag === "*" ) {
-				while ( (elem = results[i++]) ) {
+				while ( ( elem = results[ i++ ] ) ) {
 					if ( elem.nodeType === 1 ) {
 						tmp.push( elem );
 					}
@@ -1235,7 +1291,7 @@
 		};
 
 	// Class
-	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+	Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) {
 		if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
 			return context.getElementsByClassName( className );
 		}
@@ -1256,10 +1312,14 @@
 	// See https://bugs.jquery.com/ticket/13378
 	rbuggyQSA = [];
 
-	if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
+	if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {
+
 		// Build QSA regex
 		// Regex strategy adopted from Diego Perini
-		assert(function( el ) {
+		assert( function( el ) {
+
+			var input;
+
 			// Select is set to empty string on purpose
 			// This is to test IE's treatment of not explicitly
 			// setting a boolean content attribute,
@@ -1273,78 +1333,98 @@
 			// Nothing should be selected when empty strings follow ^= or $= or *=
 			// The test attribute must be unknown in Opera but "safe" for WinRT
 			// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
-			if ( el.querySelectorAll("[msallowcapture^='']").length ) {
+			if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) {
 				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
 			}
 
 			// Support: IE8
 			// Boolean attributes and "value" are not treated correctly
-			if ( !el.querySelectorAll("[selected]").length ) {
+			if ( !el.querySelectorAll( "[selected]" ).length ) {
 				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
 			}
 
 			// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
 			if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
-				rbuggyQSA.push("~=");
+				rbuggyQSA.push( "~=" );
+			}
+
+			// Support: IE 11+, Edge 15 - 18+
+			// IE 11/Edge don't find elements on a `[name='']` query in some cases.
+			// Adding a temporary attribute to the document before the selection works
+			// around the issue.
+			// Interestingly, IE 10 & older don't seem to have the issue.
+			input = document.createElement( "input" );
+			input.setAttribute( "name", "" );
+			el.appendChild( input );
+			if ( !el.querySelectorAll( "[name='']" ).length ) {
+				rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
+					whitespace + "*(?:''|\"\")" );
 			}
 
 			// Webkit/Opera - :checked should return selected option elements
 			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
 			// IE8 throws error here and will not see later tests
-			if ( !el.querySelectorAll(":checked").length ) {
-				rbuggyQSA.push(":checked");
+			if ( !el.querySelectorAll( ":checked" ).length ) {
+				rbuggyQSA.push( ":checked" );
 			}
 
 			// Support: Safari 8+, iOS 8+
 			// https://bugs.webkit.org/show_bug.cgi?id=136851
 			// In-page `selector#id sibling-combinator selector` fails
 			if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
-				rbuggyQSA.push(".#.+[+~]");
+				rbuggyQSA.push( ".#.+[+~]" );
 			}
-		});
 
-		assert(function( el ) {
+			// Support: Firefox <=3.6 - 5 only
+			// Old Firefox doesn't throw on a badly-escaped identifier.
+			el.querySelectorAll( "\\\f" );
+			rbuggyQSA.push( "[\\r\\n\\f]" );
+		} );
+
+		assert( function( el ) {
 			el.innerHTML = "<a href='' disabled='disabled'></a>" +
 				"<select disabled='disabled'><option/></select>";
 
 			// Support: Windows 8 Native Apps
 			// The type and name attributes are restricted during .innerHTML assignment
-			var input = document.createElement("input");
+			var input = document.createElement( "input" );
 			input.setAttribute( "type", "hidden" );
 			el.appendChild( input ).setAttribute( "name", "D" );
 
 			// Support: IE8
 			// Enforce case-sensitivity of name attribute
-			if ( el.querySelectorAll("[name=d]").length ) {
+			if ( el.querySelectorAll( "[name=d]" ).length ) {
 				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
 			}
 
 			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
 			// IE8 throws error here and will not see later tests
-			if ( el.querySelectorAll(":enabled").length !== 2 ) {
+			if ( el.querySelectorAll( ":enabled" ).length !== 2 ) {
 				rbuggyQSA.push( ":enabled", ":disabled" );
 			}
 
 			// Support: IE9-11+
 			// IE's :disabled selector does not pick up the children of disabled fieldsets
 			docElem.appendChild( el ).disabled = true;
-			if ( el.querySelectorAll(":disabled").length !== 2 ) {
+			if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
 				rbuggyQSA.push( ":enabled", ":disabled" );
 			}
 
+			// Support: Opera 10 - 11 only
 			// Opera 10-11 does not throw on post-comma invalid pseudos
-			el.querySelectorAll("*,:x");
-			rbuggyQSA.push(",.*:");
-		});
+			el.querySelectorAll( "*,:x" );
+			rbuggyQSA.push( ",.*:" );
+		} );
 	}
 
-	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+	if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||
 		docElem.webkitMatchesSelector ||
 		docElem.mozMatchesSelector ||
 		docElem.oMatchesSelector ||
-		docElem.msMatchesSelector) )) ) {
+		docElem.msMatchesSelector ) ) ) ) {
 
-		assert(function( el ) {
+		assert( function( el ) {
+
 			// Check to see if it's possible to do matchesSelector
 			// on a disconnected node (IE 9)
 			support.disconnectedMatch = matches.call( el, "*" );
@@ -1353,11 +1433,11 @@
 			// Gecko does not error, returns false instead
 			matches.call( el, "[s!='']:x" );
 			rbuggyMatches.push( "!=", pseudos );
-		});
+		} );
 	}
 
-	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
-	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
+	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
 
 	/* Contains
 	---------------------------------------------------------------------- */
@@ -1374,11 +1454,11 @@
 				adown.contains ?
 					adown.contains( bup ) :
 					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
-			));
+			) );
 		} :
 		function( a, b ) {
 			if ( b ) {
-				while ( (b = b.parentNode) ) {
+				while ( ( b = b.parentNode ) ) {
 					if ( b === a ) {
 						return true;
 					}
@@ -1407,7 +1487,11 @@
 		}
 
 		// Calculate position if both inputs belong to the same document
-		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+		// Support: IE 11+, Edge 17 - 18+
+		// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+		// two documents; shallow comparisons work.
+		// eslint-disable-next-line eqeqeq
+		compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?
 			a.compareDocumentPosition( b ) :
 
 			// Otherwise we know they are disconnected
@@ -1415,13 +1499,24 @@
 
 		// Disconnected nodes
 		if ( compare & 1 ||
-			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+			( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {
 
 			// Choose the first element that is related to our preferred document
-			if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+			// Support: IE 11+, Edge 17 - 18+
+			// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+			// two documents; shallow comparisons work.
+			// eslint-disable-next-line eqeqeq
+			if ( a == document || a.ownerDocument == preferredDoc &&
+				contains( preferredDoc, a ) ) {
 				return -1;
 			}
-			if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+
+			// Support: IE 11+, Edge 17 - 18+
+			// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+			// two documents; shallow comparisons work.
+			// eslint-disable-next-line eqeqeq
+			if ( b == document || b.ownerDocument == preferredDoc &&
+				contains( preferredDoc, b ) ) {
 				return 1;
 			}
 
@@ -1434,6 +1529,7 @@
 		return compare & 4 ? -1 : 1;
 	} :
 	function( a, b ) {
+
 		// Exit early if the nodes are identical
 		if ( a === b ) {
 			hasDuplicate = true;
@@ -1449,8 +1545,14 @@
 
 		// Parentless nodes are either documents or disconnected
 		if ( !aup || !bup ) {
-			return a === document ? -1 :
-				b === document ? 1 :
+
+			// Support: IE 11+, Edge 17 - 18+
+			// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+			// two documents; shallow comparisons work.
+			/* eslint-disable eqeqeq */
+			return a == document ? -1 :
+				b == document ? 1 :
+				/* eslint-enable eqeqeq */
 				aup ? -1 :
 				bup ? 1 :
 				sortInput ?
@@ -1464,26 +1566,32 @@
 
 		// Otherwise we need full lists of their ancestors for comparison
 		cur = a;
-		while ( (cur = cur.parentNode) ) {
+		while ( ( cur = cur.parentNode ) ) {
 			ap.unshift( cur );
 		}
 		cur = b;
-		while ( (cur = cur.parentNode) ) {
+		while ( ( cur = cur.parentNode ) ) {
 			bp.unshift( cur );
 		}
 
 		// Walk down the tree looking for a discrepancy
-		while ( ap[i] === bp[i] ) {
+		while ( ap[ i ] === bp[ i ] ) {
 			i++;
 		}
 
 		return i ?
+
 			// Do a sibling check if the nodes have a common ancestor
-			siblingCheck( ap[i], bp[i] ) :
+			siblingCheck( ap[ i ], bp[ i ] ) :
 
 			// Otherwise nodes in our document sort first
-			ap[i] === preferredDoc ? -1 :
-			bp[i] === preferredDoc ? 1 :
+			// Support: IE 11+, Edge 17 - 18+
+			// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+			// two documents; shallow comparisons work.
+			/* eslint-disable eqeqeq */
+			ap[ i ] == preferredDoc ? -1 :
+			bp[ i ] == preferredDoc ? 1 :
+			/* eslint-enable eqeqeq */
 			0;
 	};
 
@@ -1495,10 +1603,7 @@
 };
 
 Sizzle.matchesSelector = function( elem, expr ) {
-	// Set document vars if needed
-	if ( ( elem.ownerDocument || elem ) !== document ) {
-		setDocument( elem );
-	}
+	setDocument( elem );
 
 	if ( support.matchesSelector && documentIsHTML &&
 		!nonnativeSelectorCache[ expr + " " ] &&
@@ -1510,12 +1615,13 @@
 
 			// IE 9's matchesSelector returns false on disconnected nodes
 			if ( ret || support.disconnectedMatch ||
-					// As well, disconnected nodes are said to be in a document
-					// fragment in IE 9
-					elem.document && elem.document.nodeType !== 11 ) {
+
+				// As well, disconnected nodes are said to be in a document
+				// fragment in IE 9
+				elem.document && elem.document.nodeType !== 11 ) {
 				return ret;
 			}
-		} catch (e) {
+		} catch ( e ) {
 			nonnativeSelectorCache( expr, true );
 		}
 	}
@@ -1524,20 +1630,31 @@
 };
 
 Sizzle.contains = function( context, elem ) {
+
 	// Set document vars if needed
-	if ( ( context.ownerDocument || context ) !== document ) {
+	// Support: IE 11+, Edge 17 - 18+
+	// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+	// two documents; shallow comparisons work.
+	// eslint-disable-next-line eqeqeq
+	if ( ( context.ownerDocument || context ) != document ) {
 		setDocument( context );
 	}
 	return contains( context, elem );
 };
 
 Sizzle.attr = function( elem, name ) {
+
 	// Set document vars if needed
-	if ( ( elem.ownerDocument || elem ) !== document ) {
+	// Support: IE 11+, Edge 17 - 18+
+	// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+	// two documents; shallow comparisons work.
+	// eslint-disable-next-line eqeqeq
+	if ( ( elem.ownerDocument || elem ) != document ) {
 		setDocument( elem );
 	}
 
 	var fn = Expr.attrHandle[ name.toLowerCase() ],
+
 		// Don't get fooled by Object.prototype properties (jQuery #13807)
 		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
 			fn( elem, name, !documentIsHTML ) :
@@ -1547,13 +1664,13 @@
 		val :
 		support.attributes || !documentIsHTML ?
 			elem.getAttribute( name ) :
-			(val = elem.getAttributeNode(name)) && val.specified ?
+			( val = elem.getAttributeNode( name ) ) && val.specified ?
 				val.value :
 				null;
 };
 
 Sizzle.escape = function( sel ) {
-	return (sel + "").replace( rcssescape, fcssescape );
+	return ( sel + "" ).replace( rcssescape, fcssescape );
 };
 
 Sizzle.error = function( msg ) {
@@ -1576,7 +1693,7 @@
 	results.sort( sortOrder );
 
 	if ( hasDuplicate ) {
-		while ( (elem = results[i++]) ) {
+		while ( ( elem = results[ i++ ] ) ) {
 			if ( elem === results[ i ] ) {
 				j = duplicates.push( i );
 			}
@@ -1604,17 +1721,21 @@
 		nodeType = elem.nodeType;
 
 	if ( !nodeType ) {
+
 		// If no nodeType, this is expected to be an array
-		while ( (node = elem[i++]) ) {
+		while ( ( node = elem[ i++ ] ) ) {
+
 			// Do not traverse comment nodes
 			ret += getText( node );
 		}
 	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+
 		// Use textContent for elements
 		// innerText usage removed for consistency of new lines (jQuery #11153)
 		if ( typeof elem.textContent === "string" ) {
 			return elem.textContent;
 		} else {
+
 			// Traverse its children
 			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
 				ret += getText( elem );
@@ -1623,6 +1744,7 @@
 	} else if ( nodeType === 3 || nodeType === 4 ) {
 		return elem.nodeValue;
 	}
+
 	// Do not include comment or processing instruction nodes
 
 	return ret;
@@ -1650,19 +1772,21 @@
 
 	preFilter: {
 		"ATTR": function( match ) {
-			match[1] = match[1].replace( runescape, funescape );
+			match[ 1 ] = match[ 1 ].replace( runescape, funescape );
 
 			// Move the given value to match[3] whether quoted or unquoted
-			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+			match[ 3 ] = ( match[ 3 ] || match[ 4 ] ||
+				match[ 5 ] || "" ).replace( runescape, funescape );
 
-			if ( match[2] === "~=" ) {
-				match[3] = " " + match[3] + " ";
+			if ( match[ 2 ] === "~=" ) {
+				match[ 3 ] = " " + match[ 3 ] + " ";
 			}
 
 			return match.slice( 0, 4 );
 		},
 
 		"CHILD": function( match ) {
+
 			/* matches from matchExpr["CHILD"]
 				1 type (only|nth|...)
 				2 what (child|of-type)
@@ -1673,22 +1797,25 @@
 				7 sign of y-component
 				8 y of y-component
 			*/
-			match[1] = match[1].toLowerCase();
+			match[ 1 ] = match[ 1 ].toLowerCase();
 
-			if ( match[1].slice( 0, 3 ) === "nth" ) {
+			if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {
+
 				// nth-* requires argument
-				if ( !match[3] ) {
-					Sizzle.error( match[0] );
+				if ( !match[ 3 ] ) {
+					Sizzle.error( match[ 0 ] );
 				}
 
 				// numeric x and y parameters for Expr.filter.CHILD
 				// remember that false/true cast respectively to 0/1
-				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
-				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+				match[ 4 ] = +( match[ 4 ] ?
+					match[ 5 ] + ( match[ 6 ] || 1 ) :
+					2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) );
+				match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
 
-			// other types prohibit arguments
-			} else if ( match[3] ) {
-				Sizzle.error( match[0] );
+				// other types prohibit arguments
+			} else if ( match[ 3 ] ) {
+				Sizzle.error( match[ 0 ] );
 			}
 
 			return match;
@@ -1696,26 +1823,28 @@
 
 		"PSEUDO": function( match ) {
 			var excess,
-				unquoted = !match[6] && match[2];
+				unquoted = !match[ 6 ] && match[ 2 ];
 
-			if ( matchExpr["CHILD"].test( match[0] ) ) {
+			if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) {
 				return null;
 			}
 
 			// Accept quoted arguments as-is
-			if ( match[3] ) {
-				match[2] = match[4] || match[5] || "";
+			if ( match[ 3 ] ) {
+				match[ 2 ] = match[ 4 ] || match[ 5 ] || "";
 
 			// Strip excess characters from unquoted arguments
 			} else if ( unquoted && rpseudo.test( unquoted ) &&
+
 				// Get excess from tokenize (recursively)
-				(excess = tokenize( unquoted, true )) &&
+				( excess = tokenize( unquoted, true ) ) &&
+
 				// advance to the next closing parenthesis
-				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+				( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) {
 
 				// excess is a negative index
-				match[0] = match[0].slice( 0, excess );
-				match[2] = unquoted.slice( 0, excess );
+				match[ 0 ] = match[ 0 ].slice( 0, excess );
+				match[ 2 ] = unquoted.slice( 0, excess );
 			}
 
 			// Return only captures needed by the pseudo filter method (type and argument)
@@ -1728,7 +1857,9 @@
 		"TAG": function( nodeNameSelector ) {
 			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
 			return nodeNameSelector === "*" ?
-				function() { return true; } :
+				function() {
+					return true;
+				} :
 				function( elem ) {
 					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
 				};
@@ -1738,10 +1869,16 @@
 			var pattern = classCache[ className + " " ];
 
 			return pattern ||
-				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
-				classCache( className, function( elem ) {
-					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
-				});
+				( pattern = new RegExp( "(^|" + whitespace +
+					")" + className + "(" + whitespace + "|$)" ) ) && classCache(
+						className, function( elem ) {
+							return pattern.test(
+								typeof elem.className === "string" && elem.className ||
+								typeof elem.getAttribute !== "undefined" &&
+									elem.getAttribute( "class" ) ||
+								""
+							);
+				} );
 		},
 
 		"ATTR": function( name, operator, check ) {
@@ -1757,6 +1894,8 @@
 
 				result += "";
 
+				/* eslint-disable max-len */
+
 				return operator === "=" ? result === check :
 					operator === "!=" ? result !== check :
 					operator === "^=" ? check && result.indexOf( check ) === 0 :
@@ -1765,10 +1904,12 @@
 					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
 					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
 					false;
+				/* eslint-enable max-len */
+
 			};
 		},
 
-		"CHILD": function( type, what, argument, first, last ) {
+		"CHILD": function( type, what, _argument, first, last ) {
 			var simple = type.slice( 0, 3 ) !== "nth",
 				forward = type.slice( -4 ) !== "last",
 				ofType = what === "of-type";
@@ -1780,7 +1921,7 @@
 					return !!elem.parentNode;
 				} :
 
-				function( elem, context, xml ) {
+				function( elem, _context, xml ) {
 					var cache, uniqueCache, outerCache, node, nodeIndex, start,
 						dir = simple !== forward ? "nextSibling" : "previousSibling",
 						parent = elem.parentNode,
@@ -1794,7 +1935,7 @@
 						if ( simple ) {
 							while ( dir ) {
 								node = elem;
-								while ( (node = node[ dir ]) ) {
+								while ( ( node = node[ dir ] ) ) {
 									if ( ofType ?
 										node.nodeName.toLowerCase() === name :
 										node.nodeType === 1 ) {
@@ -1802,6 +1943,7 @@
 										return false;
 									}
 								}
+
 								// Reverse direction for :only-* (if we haven't yet done so)
 								start = dir = type === "only" && !start && "nextSibling";
 							}
@@ -1817,22 +1959,22 @@
 
 							// ...in a gzip-friendly way
 							node = parent;
-							outerCache = node[ expando ] || (node[ expando ] = {});
+							outerCache = node[ expando ] || ( node[ expando ] = {} );
 
 							// Support: IE <9 only
 							// Defend against cloned attroperties (jQuery gh-1709)
 							uniqueCache = outerCache[ node.uniqueID ] ||
-								(outerCache[ node.uniqueID ] = {});
+								( outerCache[ node.uniqueID ] = {} );
 
 							cache = uniqueCache[ type ] || [];
 							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
 							diff = nodeIndex && cache[ 2 ];
 							node = nodeIndex && parent.childNodes[ nodeIndex ];
 
-							while ( (node = ++nodeIndex && node && node[ dir ] ||
+							while ( ( node = ++nodeIndex && node && node[ dir ] ||
 
 								// Fallback to seeking `elem` from the start
-								(diff = nodeIndex = 0) || start.pop()) ) {
+								( diff = nodeIndex = 0 ) || start.pop() ) ) {
 
 								// When found, cache indexes on `parent` and break
 								if ( node.nodeType === 1 && ++diff && node === elem ) {
@@ -1842,16 +1984,18 @@
 							}
 
 						} else {
+
 							// Use previously-cached element index if available
 							if ( useCache ) {
+
 								// ...in a gzip-friendly way
 								node = elem;
-								outerCache = node[ expando ] || (node[ expando ] = {});
+								outerCache = node[ expando ] || ( node[ expando ] = {} );
 
 								// Support: IE <9 only
 								// Defend against cloned attroperties (jQuery gh-1709)
 								uniqueCache = outerCache[ node.uniqueID ] ||
-									(outerCache[ node.uniqueID ] = {});
+									( outerCache[ node.uniqueID ] = {} );
 
 								cache = uniqueCache[ type ] || [];
 								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
@@ -1861,9 +2005,10 @@
 							// xml :nth-child(...)
 							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
 							if ( diff === false ) {
+
 								// Use the same loop as above to seek `elem` from the start
-								while ( (node = ++nodeIndex && node && node[ dir ] ||
-									(diff = nodeIndex = 0) || start.pop()) ) {
+								while ( ( node = ++nodeIndex && node && node[ dir ] ||
+									( diff = nodeIndex = 0 ) || start.pop() ) ) {
 
 									if ( ( ofType ?
 										node.nodeName.toLowerCase() === name :
@@ -1872,12 +2017,13 @@
 
 										// Cache the index of each encountered element
 										if ( useCache ) {
-											outerCache = node[ expando ] || (node[ expando ] = {});
+											outerCache = node[ expando ] ||
+												( node[ expando ] = {} );
 
 											// Support: IE <9 only
 											// Defend against cloned attroperties (jQuery gh-1709)
 											uniqueCache = outerCache[ node.uniqueID ] ||
-												(outerCache[ node.uniqueID ] = {});
+												( outerCache[ node.uniqueID ] = {} );
 
 											uniqueCache[ type ] = [ dirruns, diff ];
 										}
@@ -1898,6 +2044,7 @@
 		},
 
 		"PSEUDO": function( pseudo, argument ) {
+
 			// pseudo-class names are case-insensitive
 			// http://www.w3.org/TR/selectors/#pseudo-classes
 			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
@@ -1917,15 +2064,15 @@
 			if ( fn.length > 1 ) {
 				args = [ pseudo, pseudo, "", argument ];
 				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
-					markFunction(function( seed, matches ) {
+					markFunction( function( seed, matches ) {
 						var idx,
 							matched = fn( seed, argument ),
 							i = matched.length;
 						while ( i-- ) {
-							idx = indexOf( seed, matched[i] );
-							seed[ idx ] = !( matches[ idx ] = matched[i] );
+							idx = indexOf( seed, matched[ i ] );
+							seed[ idx ] = !( matches[ idx ] = matched[ i ] );
 						}
-					}) :
+					} ) :
 					function( elem ) {
 						return fn( elem, 0, args );
 					};
@@ -1936,8 +2083,10 @@
 	},
 
 	pseudos: {
+
 		// Potentially complex pseudos
-		"not": markFunction(function( selector ) {
+		"not": markFunction( function( selector ) {
+
 			// Trim the selector passed to compile
 			// to avoid treating leading and trailing
 			// spaces as combinators
@@ -1946,39 +2095,40 @@
 				matcher = compile( selector.replace( rtrim, "$1" ) );
 
 			return matcher[ expando ] ?
-				markFunction(function( seed, matches, context, xml ) {
+				markFunction( function( seed, matches, _context, xml ) {
 					var elem,
 						unmatched = matcher( seed, null, xml, [] ),
 						i = seed.length;
 
 					// Match elements unmatched by `matcher`
 					while ( i-- ) {
-						if ( (elem = unmatched[i]) ) {
-							seed[i] = !(matches[i] = elem);
+						if ( ( elem = unmatched[ i ] ) ) {
+							seed[ i ] = !( matches[ i ] = elem );
 						}
 					}
-				}) :
-				function( elem, context, xml ) {
-					input[0] = elem;
+				} ) :
+				function( elem, _context, xml ) {
+					input[ 0 ] = elem;
 					matcher( input, null, xml, results );
+
 					// Don't keep the element (issue #299)
-					input[0] = null;
+					input[ 0 ] = null;
 					return !results.pop();
 				};
-		}),
+		} ),
 
-		"has": markFunction(function( selector ) {
+		"has": markFunction( function( selector ) {
 			return function( elem ) {
 				return Sizzle( selector, elem ).length > 0;
 			};
-		}),
+		} ),
 
-		"contains": markFunction(function( text ) {
+		"contains": markFunction( function( text ) {
 			text = text.replace( runescape, funescape );
 			return function( elem ) {
 				return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
 			};
-		}),
+		} ),
 
 		// "Whether an element is represented by a :lang() selector
 		// is based solely on the element's language value
@@ -1988,25 +2138,26 @@
 		// The identifier C does not have to be a valid language name."
 		// http://www.w3.org/TR/selectors/#lang-pseudo
 		"lang": markFunction( function( lang ) {
+
 			// lang value must be a valid identifier
-			if ( !ridentifier.test(lang || "") ) {
+			if ( !ridentifier.test( lang || "" ) ) {
 				Sizzle.error( "unsupported lang: " + lang );
 			}
 			lang = lang.replace( runescape, funescape ).toLowerCase();
 			return function( elem ) {
 				var elemLang;
 				do {
-					if ( (elemLang = documentIsHTML ?
+					if ( ( elemLang = documentIsHTML ?
 						elem.lang :
-						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+						elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {
 
 						elemLang = elemLang.toLowerCase();
 						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
 					}
-				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+				} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
 				return false;
 			};
-		}),
+		} ),
 
 		// Miscellaneous
 		"target": function( elem ) {
@@ -2019,7 +2170,9 @@
 		},
 
 		"focus": function( elem ) {
-			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+			return elem === document.activeElement &&
+				( !document.hasFocus || document.hasFocus() ) &&
+				!!( elem.type || elem.href || ~elem.tabIndex );
 		},
 
 		// Boolean properties
@@ -2027,16 +2180,20 @@
 		"disabled": createDisabledPseudo( true ),
 
 		"checked": function( elem ) {
+
 			// In CSS3, :checked should return both checked and selected elements
 			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
 			var nodeName = elem.nodeName.toLowerCase();
-			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+			return ( nodeName === "input" && !!elem.checked ) ||
+				( nodeName === "option" && !!elem.selected );
 		},
 
 		"selected": function( elem ) {
+
 			// Accessing this property makes selected-by-default
 			// options in Safari work properly
 			if ( elem.parentNode ) {
+				// eslint-disable-next-line no-unused-expressions
 				elem.parentNode.selectedIndex;
 			}
 
@@ -2045,6 +2202,7 @@
 
 		// Contents
 		"empty": function( elem ) {
+
 			// http://www.w3.org/TR/selectors/#empty-pseudo
 			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
 			//   but not by others (comment: 8; processing instruction: 7; etc.)
@@ -2058,7 +2216,7 @@
 		},
 
 		"parent": function( elem ) {
-			return !Expr.pseudos["empty"]( elem );
+			return !Expr.pseudos[ "empty" ]( elem );
 		},
 
 		// Element/input types
@@ -2082,39 +2240,40 @@
 
 				// Support: IE<8
 				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
-				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+				( ( attr = elem.getAttribute( "type" ) ) == null ||
+					attr.toLowerCase() === "text" );
 		},
 
 		// Position-in-collection
-		"first": createPositionalPseudo(function() {
+		"first": createPositionalPseudo( function() {
 			return [ 0 ];
-		}),
+		} ),
 
-		"last": createPositionalPseudo(function( matchIndexes, length ) {
+		"last": createPositionalPseudo( function( _matchIndexes, length ) {
 			return [ length - 1 ];
-		}),
+		} ),
 
-		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+		"eq": createPositionalPseudo( function( _matchIndexes, length, argument ) {
 			return [ argument < 0 ? argument + length : argument ];
-		}),
+		} ),
 
-		"even": createPositionalPseudo(function( matchIndexes, length ) {
+		"even": createPositionalPseudo( function( matchIndexes, length ) {
 			var i = 0;
 			for ( ; i < length; i += 2 ) {
 				matchIndexes.push( i );
 			}
 			return matchIndexes;
-		}),
+		} ),
 
-		"odd": createPositionalPseudo(function( matchIndexes, length ) {
+		"odd": createPositionalPseudo( function( matchIndexes, length ) {
 			var i = 1;
 			for ( ; i < length; i += 2 ) {
 				matchIndexes.push( i );
 			}
 			return matchIndexes;
-		}),
+		} ),
 
-		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+		"lt": createPositionalPseudo( function( matchIndexes, length, argument ) {
 			var i = argument < 0 ?
 				argument + length :
 				argument > length ?
@@ -2124,19 +2283,19 @@
 				matchIndexes.push( i );
 			}
 			return matchIndexes;
-		}),
+		} ),
 
-		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+		"gt": createPositionalPseudo( function( matchIndexes, length, argument ) {
 			var i = argument < 0 ? argument + length : argument;
 			for ( ; ++i < length; ) {
 				matchIndexes.push( i );
 			}
 			return matchIndexes;
-		})
+		} )
 	}
 };
 
-Expr.pseudos["nth"] = Expr.pseudos["eq"];
+Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ];
 
 // Add button/input type pseudos
 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
@@ -2167,37 +2326,39 @@
 	while ( soFar ) {
 
 		// Comma and first run
-		if ( !matched || (match = rcomma.exec( soFar )) ) {
+		if ( !matched || ( match = rcomma.exec( soFar ) ) ) {
 			if ( match ) {
+
 				// Don't consume trailing commas as valid
-				soFar = soFar.slice( match[0].length ) || soFar;
+				soFar = soFar.slice( match[ 0 ].length ) || soFar;
 			}
-			groups.push( (tokens = []) );
+			groups.push( ( tokens = [] ) );
 		}
 
 		matched = false;
 
 		// Combinators
-		if ( (match = rcombinators.exec( soFar )) ) {
+		if ( ( match = rcombinators.exec( soFar ) ) ) {
 			matched = match.shift();
-			tokens.push({
+			tokens.push( {
 				value: matched,
+
 				// Cast descendant combinators to space
-				type: match[0].replace( rtrim, " " )
-			});
+				type: match[ 0 ].replace( rtrim, " " )
+			} );
 			soFar = soFar.slice( matched.length );
 		}
 
 		// Filters
 		for ( type in Expr.filter ) {
-			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
-				(match = preFilters[ type ]( match ))) ) {
+			if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||
+				( match = preFilters[ type ]( match ) ) ) ) {
 				matched = match.shift();
-				tokens.push({
+				tokens.push( {
 					value: matched,
 					type: type,
 					matches: match
-				});
+				} );
 				soFar = soFar.slice( matched.length );
 			}
 		}
@@ -2214,6 +2375,7 @@
 		soFar.length :
 		soFar ?
 			Sizzle.error( selector ) :
+
 			// Cache the tokens
 			tokenCache( selector, groups ).slice( 0 );
 };
@@ -2223,7 +2385,7 @@
 		len = tokens.length,
 		selector = "";
 	for ( ; i < len; i++ ) {
-		selector += tokens[i].value;
+		selector += tokens[ i ].value;
 	}
 	return selector;
 }
@@ -2236,9 +2398,10 @@
 		doneName = done++;
 
 	return combinator.first ?
+
 		// Check against closest ancestor/preceding element
 		function( elem, context, xml ) {
-			while ( (elem = elem[ dir ]) ) {
+			while ( ( elem = elem[ dir ] ) ) {
 				if ( elem.nodeType === 1 || checkNonElements ) {
 					return matcher( elem, context, xml );
 				}
@@ -2253,7 +2416,7 @@
 
 			// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
 			if ( xml ) {
-				while ( (elem = elem[ dir ]) ) {
+				while ( ( elem = elem[ dir ] ) ) {
 					if ( elem.nodeType === 1 || checkNonElements ) {
 						if ( matcher( elem, context, xml ) ) {
 							return true;
@@ -2261,27 +2424,29 @@
 					}
 				}
 			} else {
-				while ( (elem = elem[ dir ]) ) {
+				while ( ( elem = elem[ dir ] ) ) {
 					if ( elem.nodeType === 1 || checkNonElements ) {
-						outerCache = elem[ expando ] || (elem[ expando ] = {});
+						outerCache = elem[ expando ] || ( elem[ expando ] = {} );
 
 						// Support: IE <9 only
 						// Defend against cloned attroperties (jQuery gh-1709)
-						uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
+						uniqueCache = outerCache[ elem.uniqueID ] ||
+							( outerCache[ elem.uniqueID ] = {} );
 
 						if ( skip && skip === elem.nodeName.toLowerCase() ) {
 							elem = elem[ dir ] || elem;
-						} else if ( (oldCache = uniqueCache[ key ]) &&
+						} else if ( ( oldCache = uniqueCache[ key ] ) &&
 							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
 
 							// Assign to newCache so results back-propagate to previous elements
-							return (newCache[ 2 ] = oldCache[ 2 ]);
+							return ( newCache[ 2 ] = oldCache[ 2 ] );
 						} else {
+
 							// Reuse newcache so results back-propagate to previous elements
 							uniqueCache[ key ] = newCache;
 
 							// A match means we're done; a fail means we have to keep checking
-							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+							if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
 								return true;
 							}
 						}
@@ -2297,20 +2462,20 @@
 		function( elem, context, xml ) {
 			var i = matchers.length;
 			while ( i-- ) {
-				if ( !matchers[i]( elem, context, xml ) ) {
+				if ( !matchers[ i ]( elem, context, xml ) ) {
 					return false;
 				}
 			}
 			return true;
 		} :
-		matchers[0];
+		matchers[ 0 ];
 }
 
 function multipleContexts( selector, contexts, results ) {
 	var i = 0,
 		len = contexts.length;
 	for ( ; i < len; i++ ) {
-		Sizzle( selector, contexts[i], results );
+		Sizzle( selector, contexts[ i ], results );
 	}
 	return results;
 }
@@ -2323,7 +2488,7 @@
 		mapped = map != null;
 
 	for ( ; i < len; i++ ) {
-		if ( (elem = unmatched[i]) ) {
+		if ( ( elem = unmatched[ i ] ) ) {
 			if ( !filter || filter( elem, context, xml ) ) {
 				newUnmatched.push( elem );
 				if ( mapped ) {
@@ -2343,14 +2508,18 @@
 	if ( postFinder && !postFinder[ expando ] ) {
 		postFinder = setMatcher( postFinder, postSelector );
 	}
-	return markFunction(function( seed, results, context, xml ) {
+	return markFunction( function( seed, results, context, xml ) {
 		var temp, i, elem,
 			preMap = [],
 			postMap = [],
 			preexisting = results.length,
 
 			// Get initial elements from seed or context
-			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+			elems = seed || multipleContexts(
+				selector || "*",
+				context.nodeType ? [ context ] : context,
+				[]
+			),
 
 			// Prefilter to get matcher input, preserving a map for seed-results synchronization
 			matcherIn = preFilter && ( seed || !selector ) ?
@@ -2358,6 +2527,7 @@
 				elems,
 
 			matcherOut = matcher ?
+
 				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
 				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
 
@@ -2381,8 +2551,8 @@
 			// Un-match failing elements by moving them back to matcherIn
 			i = temp.length;
 			while ( i-- ) {
-				if ( (elem = temp[i]) ) {
-					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+				if ( ( elem = temp[ i ] ) ) {
+					matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );
 				}
 			}
 		}
@@ -2390,25 +2560,27 @@
 		if ( seed ) {
 			if ( postFinder || preFilter ) {
 				if ( postFinder ) {
+
 					// Get the final matcherOut by condensing this intermediate into postFinder contexts
 					temp = [];
 					i = matcherOut.length;
 					while ( i-- ) {
-						if ( (elem = matcherOut[i]) ) {
+						if ( ( elem = matcherOut[ i ] ) ) {
+
 							// Restore matcherIn since elem is not yet a final match
-							temp.push( (matcherIn[i] = elem) );
+							temp.push( ( matcherIn[ i ] = elem ) );
 						}
 					}
-					postFinder( null, (matcherOut = []), temp, xml );
+					postFinder( null, ( matcherOut = [] ), temp, xml );
 				}
 
 				// Move matched elements from seed to results to keep them synchronized
 				i = matcherOut.length;
 				while ( i-- ) {
-					if ( (elem = matcherOut[i]) &&
-						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
+					if ( ( elem = matcherOut[ i ] ) &&
+						( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {
 
-						seed[temp] = !(results[temp] = elem);
+						seed[ temp ] = !( results[ temp ] = elem );
 					}
 				}
 			}
@@ -2426,14 +2598,14 @@
 				push.apply( results, matcherOut );
 			}
 		}
-	});
+	} );
 }
 
 function matcherFromTokens( tokens ) {
 	var checkContext, matcher, j,
 		len = tokens.length,
-		leadingRelative = Expr.relative[ tokens[0].type ],
-		implicitRelative = leadingRelative || Expr.relative[" "],
+		leadingRelative = Expr.relative[ tokens[ 0 ].type ],
+		implicitRelative = leadingRelative || Expr.relative[ " " ],
 		i = leadingRelative ? 1 : 0,
 
 		// The foundational matcher ensures that elements are reachable from top-level context(s)
@@ -2445,38 +2617,43 @@
 		}, implicitRelative, true ),
 		matchers = [ function( elem, context, xml ) {
 			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
-				(checkContext = context).nodeType ?
+				( checkContext = context ).nodeType ?
 					matchContext( elem, context, xml ) :
 					matchAnyContext( elem, context, xml ) );
+
 			// Avoid hanging onto element (issue #299)
 			checkContext = null;
 			return ret;
 		} ];
 
 	for ( ; i < len; i++ ) {
-		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
-			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+		if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {
+			matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
 		} else {
-			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+			matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
 
 			// Return special upon seeing a positional matcher
 			if ( matcher[ expando ] ) {
+
 				// Find the next relative operator (if any) for proper handling
 				j = ++i;
 				for ( ; j < len; j++ ) {
-					if ( Expr.relative[ tokens[j].type ] ) {
+					if ( Expr.relative[ tokens[ j ].type ] ) {
 						break;
 					}
 				}
 				return setMatcher(
 					i > 1 && elementMatcher( matchers ),
 					i > 1 && toSelector(
-						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
-						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+
+					// If the preceding token was a descendant combinator, insert an implicit any-element `*`
+					tokens
+						.slice( 0, i - 1 )
+						.concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
 					).replace( rtrim, "$1" ),
 					matcher,
 					i < j && matcherFromTokens( tokens.slice( i, j ) ),
-					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+					j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
 					j < len && toSelector( tokens )
 				);
 			}
@@ -2497,28 +2674,40 @@
 				unmatched = seed && [],
 				setMatched = [],
 				contextBackup = outermostContext,
+
 				// We must always have either seed elements or outermost context
-				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+				elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ),
+
 				// Use integer dirruns iff this is the outermost matcher
-				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+				dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),
 				len = elems.length;
 
 			if ( outermost ) {
-				outermostContext = context === document || context || outermost;
+
+				// Support: IE 11+, Edge 17 - 18+
+				// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+				// two documents; shallow comparisons work.
+				// eslint-disable-next-line eqeqeq
+				outermostContext = context == document || context || outermost;
 			}
 
 			// Add elements passing elementMatchers directly to results
 			// Support: IE<9, Safari
 			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
-			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+			for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {
 				if ( byElement && elem ) {
 					j = 0;
-					if ( !context && elem.ownerDocument !== document ) {
+
+					// Support: IE 11+, Edge 17 - 18+
+					// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+					// two documents; shallow comparisons work.
+					// eslint-disable-next-line eqeqeq
+					if ( !context && elem.ownerDocument != document ) {
 						setDocument( elem );
 						xml = !documentIsHTML;
 					}
-					while ( (matcher = elementMatchers[j++]) ) {
-						if ( matcher( elem, context || document, xml) ) {
+					while ( ( matcher = elementMatchers[ j++ ] ) ) {
+						if ( matcher( elem, context || document, xml ) ) {
 							results.push( elem );
 							break;
 						}
@@ -2530,8 +2719,9 @@
 
 				// Track unmatched elements for set filters
 				if ( bySet ) {
+
 					// They will have gone through all possible matchers
-					if ( (elem = !matcher && elem) ) {
+					if ( ( elem = !matcher && elem ) ) {
 						matchedCount--;
 					}
 
@@ -2555,16 +2745,17 @@
 			// numerically zero.
 			if ( bySet && i !== matchedCount ) {
 				j = 0;
-				while ( (matcher = setMatchers[j++]) ) {
+				while ( ( matcher = setMatchers[ j++ ] ) ) {
 					matcher( unmatched, setMatched, context, xml );
 				}
 
 				if ( seed ) {
+
 					// Reintegrate element matches to eliminate the need for sorting
 					if ( matchedCount > 0 ) {
 						while ( i-- ) {
-							if ( !(unmatched[i] || setMatched[i]) ) {
-								setMatched[i] = pop.call( results );
+							if ( !( unmatched[ i ] || setMatched[ i ] ) ) {
+								setMatched[ i ] = pop.call( results );
 							}
 						}
 					}
@@ -2605,13 +2796,14 @@
 		cached = compilerCache[ selector + " " ];
 
 	if ( !cached ) {
+
 		// Generate a function of recursive functions that can be used to check each element
 		if ( !match ) {
 			match = tokenize( selector );
 		}
 		i = match.length;
 		while ( i-- ) {
-			cached = matcherFromTokens( match[i] );
+			cached = matcherFromTokens( match[ i ] );
 			if ( cached[ expando ] ) {
 				setMatchers.push( cached );
 			} else {
@@ -2620,7 +2812,10 @@
 		}
 
 		// Cache the compiled function
-		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+		cached = compilerCache(
+			selector,
+			matcherFromGroupMatchers( elementMatchers, setMatchers )
+		);
 
 		// Save selector and tokenization
 		cached.selector = selector;
@@ -2640,7 +2835,7 @@
 select = Sizzle.select = function( selector, context, results, seed ) {
 	var i, tokens, token, type, find,
 		compiled = typeof selector === "function" && selector,
-		match = !seed && tokenize( (selector = compiled.selector || selector) );
+		match = !seed && tokenize( ( selector = compiled.selector || selector ) );
 
 	results = results || [];
 
@@ -2649,11 +2844,12 @@
 	if ( match.length === 1 ) {
 
 		// Reduce context if the leading compound selector is an ID
-		tokens = match[0] = match[0].slice( 0 );
-		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
-				context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
+		tokens = match[ 0 ] = match[ 0 ].slice( 0 );
+		if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
+			context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
 
-			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+			context = ( Expr.find[ "ID" ]( token.matches[ 0 ]
+				.replace( runescape, funescape ), context ) || [] )[ 0 ];
 			if ( !context ) {
 				return results;
 
@@ -2666,20 +2862,22 @@
 		}
 
 		// Fetch a seed set for right-to-left matching
-		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+		i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length;
 		while ( i-- ) {
-			token = tokens[i];
+			token = tokens[ i ];
 
 			// Abort if we hit a combinator
-			if ( Expr.relative[ (type = token.type) ] ) {
+			if ( Expr.relative[ ( type = token.type ) ] ) {
 				break;
 			}
-			if ( (find = Expr.find[ type ]) ) {
+			if ( ( find = Expr.find[ type ] ) ) {
+
 				// Search, expanding context for leading sibling combinators
-				if ( (seed = find(
-					token.matches[0].replace( runescape, funescape ),
-					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
-				)) ) {
+				if ( ( seed = find(
+					token.matches[ 0 ].replace( runescape, funescape ),
+					rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||
+						context
+				) ) ) {
 
 					// If seed is empty or no tokens remain, we can return early
 					tokens.splice( i, 1 );
@@ -2710,7 +2908,7 @@
 // One-time assignments
 
 // Sort stability
-support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;
 
 // Support: Chrome 14-35+
 // Always assume duplicates if they aren't passed to the comparison function
@@ -2721,58 +2919,59 @@
 
 // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
 // Detached nodes confoundingly follow *each other*
-support.sortDetached = assert(function( el ) {
+support.sortDetached = assert( function( el ) {
+
 	// Should return 1, but returns 4 (following)
-	return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
-});
+	return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1;
+} );
 
 // Support: IE<8
 // Prevent attribute/property "interpolation"
 // https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !assert(function( el ) {
+if ( !assert( function( el ) {
 	el.innerHTML = "<a href='#'></a>";
-	return el.firstChild.getAttribute("href") === "#" ;
-}) ) {
+	return el.firstChild.getAttribute( "href" ) === "#";
+} ) ) {
 	addHandle( "type|href|height|width", function( elem, name, isXML ) {
 		if ( !isXML ) {
 			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
 		}
-	});
+	} );
 }
 
 // Support: IE<9
 // Use defaultValue in place of getAttribute("value")
-if ( !support.attributes || !assert(function( el ) {
+if ( !support.attributes || !assert( function( el ) {
 	el.innerHTML = "<input/>";
 	el.firstChild.setAttribute( "value", "" );
 	return el.firstChild.getAttribute( "value" ) === "";
-}) ) {
-	addHandle( "value", function( elem, name, isXML ) {
+} ) ) {
+	addHandle( "value", function( elem, _name, isXML ) {
 		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
 			return elem.defaultValue;
 		}
-	});
+	} );
 }
 
 // Support: IE<9
 // Use getAttributeNode to fetch booleans when getAttribute lies
-if ( !assert(function( el ) {
-	return el.getAttribute("disabled") == null;
-}) ) {
+if ( !assert( function( el ) {
+	return el.getAttribute( "disabled" ) == null;
+} ) ) {
 	addHandle( booleans, function( elem, name, isXML ) {
 		var val;
 		if ( !isXML ) {
 			return elem[ name ] === true ? name.toLowerCase() :
-					(val = elem.getAttributeNode( name )) && val.specified ?
+				( val = elem.getAttributeNode( name ) ) && val.specified ?
 					val.value :
-				null;
+					null;
 		}
-	});
+	} );
 }
 
 return Sizzle;
 
-})( window );
+} )( window );
 
 
 
@@ -3141,7 +3340,7 @@
 	parents: function( elem ) {
 		return dir( elem, "parentNode" );
 	},
-	parentsUntil: function( elem, i, until ) {
+	parentsUntil: function( elem, _i, until ) {
 		return dir( elem, "parentNode", until );
 	},
 	next: function( elem ) {
@@ -3156,10 +3355,10 @@
 	prevAll: function( elem ) {
 		return dir( elem, "previousSibling" );
 	},
-	nextUntil: function( elem, i, until ) {
+	nextUntil: function( elem, _i, until ) {
 		return dir( elem, "nextSibling", until );
 	},
-	prevUntil: function( elem, i, until ) {
+	prevUntil: function( elem, _i, until ) {
 		return dir( elem, "previousSibling", until );
 	},
 	siblings: function( elem ) {
@@ -3169,7 +3368,13 @@
 		return siblings( elem.firstChild );
 	},
 	contents: function( elem ) {
-		if ( typeof elem.contentDocument !== "undefined" ) {
+		if ( elem.contentDocument != null &&
+
+			// Support: IE 11+
+			// <object> elements with no `data` attribute has an object
+			// `contentDocument` with a `null` prototype.
+			getProto( elem.contentDocument ) ) {
+
 			return elem.contentDocument;
 		}
 
@@ -3512,7 +3717,7 @@
 					var fns = arguments;
 
 					return jQuery.Deferred( function( newDefer ) {
-						jQuery.each( tuples, function( i, tuple ) {
+						jQuery.each( tuples, function( _i, tuple ) {
 
 							// Map tuples (progress, done, fail) to arguments (done, fail, progress)
 							var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
@@ -3965,7 +4170,7 @@
 			// ...except when executing function values
 			} else {
 				bulk = fn;
-				fn = function( elem, key, value ) {
+				fn = function( elem, _key, value ) {
 					return bulk.call( jQuery( elem ), value );
 				};
 			}
@@ -4000,7 +4205,7 @@
 	rdashAlpha = /-([a-z])/g;
 
 // Used by camelCase as callback to replace()
-function fcamelCase( all, letter ) {
+function fcamelCase( _all, letter ) {
 	return letter.toUpperCase();
 }
 
@@ -4528,27 +4733,6 @@
 			jQuery.css( elem, "display" ) === "none";
 	};
 
-var swap = function( elem, options, callback, args ) {
-	var ret, name,
-		old = {};
-
-	// Remember the old values, and insert the new ones
-	for ( name in options ) {
-		old[ name ] = elem.style[ name ];
-		elem.style[ name ] = options[ name ];
-	}
-
-	ret = callback.apply( elem, args || [] );
-
-	// Revert the old values
-	for ( name in options ) {
-		elem.style[ name ] = old[ name ];
-	}
-
-	return ret;
-};
-
-
 
 
 function adjustCSS( elem, prop, valueParts, tween ) {
@@ -4719,11 +4903,40 @@
 
 
 
-// We have to close these tags to support XHTML (#13200)
-var wrapMap = {
+( function() {
+	var fragment = document.createDocumentFragment(),
+		div = fragment.appendChild( document.createElement( "div" ) ),
+		input = document.createElement( "input" );
+
+	// Support: Android 4.0 - 4.3 only
+	// Check state lost if the name is set (#11217)
+	// Support: Windows Web Apps (WWA)
+	// `name` and `type` must use .setAttribute for WWA (#14901)
+	input.setAttribute( "type", "radio" );
+	input.setAttribute( "checked", "checked" );
+	input.setAttribute( "name", "t" );
+
+	div.appendChild( input );
+
+	// Support: Android <=4.1 only
+	// Older WebKit doesn't clone checked state correctly in fragments
+	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+	// Support: IE <=11 only
+	// Make sure textarea (and checkbox) defaultValue is properly cloned
+	div.innerHTML = "<textarea>x</textarea>";
+	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
 
 	// Support: IE <=9 only
-	option: [ 1, "<select multiple='multiple'>", "</select>" ],
+	// IE <=9 replaces <option> tags with their contents when inserted outside of
+	// the select element.
+	div.innerHTML = "<option></option>";
+	support.option = !!div.lastChild;
+} )();
+
+
+// We have to close these tags to support XHTML (#13200)
+var wrapMap = {
 
 	// XHTML parsers do not magically insert elements in the
 	// same way that tag soup parsers do. So we cannot shorten
@@ -4736,12 +4949,14 @@
 	_default: [ 0, "", "" ]
 };
 
-// Support: IE <=9 only
-wrapMap.optgroup = wrapMap.option;
-
 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
 wrapMap.th = wrapMap.td;
 
+// Support: IE <=9 only
+if ( !support.option ) {
+	wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ];
+}
+
 
 function getAll( context, tag ) {
 
@@ -4874,32 +5089,6 @@
 }
 
 
-( function() {
-	var fragment = document.createDocumentFragment(),
-		div = fragment.appendChild( document.createElement( "div" ) ),
-		input = document.createElement( "input" );
-
-	// Support: Android 4.0 - 4.3 only
-	// Check state lost if the name is set (#11217)
-	// Support: Windows Web Apps (WWA)
-	// `name` and `type` must use .setAttribute for WWA (#14901)
-	input.setAttribute( "type", "radio" );
-	input.setAttribute( "checked", "checked" );
-	input.setAttribute( "name", "t" );
-
-	div.appendChild( input );
-
-	// Support: Android <=4.1 only
-	// Older WebKit doesn't clone checked state correctly in fragments
-	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
-	// Support: IE <=11 only
-	// Make sure textarea (and checkbox) defaultValue is properly cloned
-	div.innerHTML = "<textarea>x</textarea>";
-	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
-} )();
-
-
 var
 	rkeyEvent = /^key/,
 	rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
@@ -5008,8 +5197,8 @@
 			special, handlers, type, namespaces, origType,
 			elemData = dataPriv.get( elem );
 
-		// Don't attach events to noData or text/comment nodes (but allow plain objects)
-		if ( !elemData ) {
+		// Only attach events to objects that accept data
+		if ( !acceptData( elem ) ) {
 			return;
 		}
 
@@ -5033,7 +5222,7 @@
 
 		// Init the element's event structure and main handler, if this is the first
 		if ( !( events = elemData.events ) ) {
-			events = elemData.events = {};
+			events = elemData.events = Object.create( null );
 		}
 		if ( !( eventHandle = elemData.handle ) ) {
 			eventHandle = elemData.handle = function( e ) {
@@ -5191,12 +5380,15 @@
 
 	dispatch: function( nativeEvent ) {
 
-		// Make a writable jQuery.Event from the native event object
-		var event = jQuery.event.fix( nativeEvent );
-
 		var i, j, ret, matched, handleObj, handlerQueue,
 			args = new Array( arguments.length ),
-			handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
+
+			// Make a writable jQuery.Event from the native event object
+			event = jQuery.event.fix( nativeEvent ),
+
+			handlers = (
+					dataPriv.get( this, "events" ) || Object.create( null )
+				)[ event.type ] || [],
 			special = jQuery.event.special[ event.type ] || {};
 
 		// Use the fix-ed jQuery.Event rather than the (read-only) native event
@@ -5771,13 +5963,6 @@
 
 var
 
-	/* eslint-disable max-len */
-
-	// See https://github.com/eslint/eslint/issues/3229
-	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
-
-	/* eslint-enable */
-
 	// Support: IE <=10 - 11, Edge 12 - 13 only
 	// In IE/Edge using regex groups here causes severe slowdowns.
 	// See https://connect.microsoft.com/IE/feedback/details/1736512/
@@ -5814,7 +5999,7 @@
 }
 
 function cloneCopyEvent( src, dest ) {
-	var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
+	var i, l, type, pdataOld, udataOld, udataCur, events;
 
 	if ( dest.nodeType !== 1 ) {
 		return;
@@ -5822,13 +6007,11 @@
 
 	// 1. Copy private data: events, handlers, etc.
 	if ( dataPriv.hasData( src ) ) {
-		pdataOld = dataPriv.access( src );
-		pdataCur = dataPriv.set( dest, pdataOld );
+		pdataOld = dataPriv.get( src );
 		events = pdataOld.events;
 
 		if ( events ) {
-			delete pdataCur.handle;
-			pdataCur.events = {};
+			dataPriv.remove( dest, "handle events" );
 
 			for ( type in events ) {
 				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
@@ -5864,7 +6047,7 @@
 function domManip( collection, args, callback, ignored ) {
 
 	// Flatten any nested arrays
-	args = concat.apply( [], args );
+	args = flat( args );
 
 	var fragment, first, scripts, hasScripts, node, doc,
 		i = 0,
@@ -5939,7 +6122,7 @@
 							if ( jQuery._evalUrl && !node.noModule ) {
 								jQuery._evalUrl( node.src, {
 									nonce: node.nonce || node.getAttribute( "nonce" )
-								} );
+								}, doc );
 							}
 						} else {
 							DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
@@ -5976,7 +6159,7 @@
 
 jQuery.extend( {
 	htmlPrefilter: function( html ) {
-		return html.replace( rxhtmlTag, "<$1></$2>" );
+		return html;
 	},
 
 	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
@@ -6238,6 +6421,27 @@
 		return view.getComputedStyle( elem );
 	};
 
+var swap = function( elem, options, callback ) {
+	var ret, name,
+		old = {};
+
+	// Remember the old values, and insert the new ones
+	for ( name in options ) {
+		old[ name ] = elem.style[ name ];
+		elem.style[ name ] = options[ name ];
+	}
+
+	ret = callback.call( elem );
+
+	// Revert the old values
+	for ( name in options ) {
+		elem.style[ name ] = old[ name ];
+	}
+
+	return ret;
+};
+
+
 var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
 
 
@@ -6295,7 +6499,7 @@
 	}
 
 	var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
-		reliableMarginLeftVal,
+		reliableTrDimensionsVal, reliableMarginLeftVal,
 		container = document.createElement( "div" ),
 		div = document.createElement( "div" );
 
@@ -6330,6 +6534,35 @@
 		scrollboxSize: function() {
 			computeStyleTests();
 			return scrollboxSizeVal;
+		},
+
+		// Support: IE 9 - 11+, Edge 15 - 18+
+		// IE/Edge misreport `getComputedStyle` of table rows with width/height
+		// set in CSS while `offset*` properties report correct values.
+		// Behavior in IE 9 is more subtle than in newer versions & it passes
+		// some versions of this test; make sure not to make it pass there!
+		reliableTrDimensions: function() {
+			var table, tr, trChild, trStyle;
+			if ( reliableTrDimensionsVal == null ) {
+				table = document.createElement( "table" );
+				tr = document.createElement( "tr" );
+				trChild = document.createElement( "div" );
+
+				table.style.cssText = "position:absolute;left:-11111px";
+				tr.style.height = "1px";
+				trChild.style.height = "9px";
+
+				documentElement
+					.appendChild( table )
+					.appendChild( tr )
+					.appendChild( trChild );
+
+				trStyle = window.getComputedStyle( tr );
+				reliableTrDimensionsVal = parseInt( trStyle.height ) > 3;
+
+				documentElement.removeChild( table );
+			}
+			return reliableTrDimensionsVal;
 		}
 	} );
 } )();
@@ -6454,7 +6687,7 @@
 		fontWeight: "400"
 	};
 
-function setPositiveNumber( elem, value, subtract ) {
+function setPositiveNumber( _elem, value, subtract ) {
 
 	// Any relative (+/-) values have already been
 	// normalized at this point
@@ -6559,17 +6792,26 @@
 	}
 
 
-	// Fall back to offsetWidth/offsetHeight when value is "auto"
-	// This happens for inline elements with no explicit setting (gh-3571)
-	// Support: Android <=4.1 - 4.3 only
-	// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
-	// Support: IE 9-11 only
-	// Also use offsetWidth/offsetHeight for when box sizing is unreliable
-	// We use getClientRects() to check for hidden/disconnected.
-	// In those cases, the computed value can be trusted to be border-box
+	// Support: IE 9 - 11 only
+	// Use offsetWidth/offsetHeight for when box sizing is unreliable.
+	// In those cases, the computed value can be trusted to be border-box.
 	if ( ( !support.boxSizingReliable() && isBorderBox ||
+
+		// Support: IE 10 - 11+, Edge 15 - 18+
+		// IE/Edge misreport `getComputedStyle` of table rows with width/height
+		// set in CSS while `offset*` properties report correct values.
+		// Interestingly, in some cases IE 9 doesn't suffer from this issue.
+		!support.reliableTrDimensions() && nodeName( elem, "tr" ) ||
+
+		// Fall back to offsetWidth/offsetHeight when value is "auto"
+		// This happens for inline elements with no explicit setting (gh-3571)
 		val === "auto" ||
+
+		// Support: Android <=4.1 - 4.3 only
+		// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
 		!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
+
+		// Make sure the element is visible & connected
 		elem.getClientRects().length ) {
 
 		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
@@ -6764,7 +7006,7 @@
 	}
 } );
 
-jQuery.each( [ "height", "width" ], function( i, dimension ) {
+jQuery.each( [ "height", "width" ], function( _i, dimension ) {
 	jQuery.cssHooks[ dimension ] = {
 		get: function( elem, computed, extra ) {
 			if ( computed ) {
@@ -7537,7 +7779,7 @@
 			clearQueue = type;
 			type = undefined;
 		}
-		if ( clearQueue && type !== false ) {
+		if ( clearQueue ) {
 			this.queue( type || "fx", [] );
 		}
 
@@ -7620,7 +7862,7 @@
 	}
 } );
 
-jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
+jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) {
 	var cssFn = jQuery.fn[ name ];
 	jQuery.fn[ name ] = function( speed, easing, callback ) {
 		return speed == null || typeof speed === "boolean" ?
@@ -7841,7 +8083,7 @@
 	}
 };
 
-jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) {
 	var getter = attrHandle[ name ] || jQuery.find.attr;
 
 	attrHandle[ name ] = function( elem, name, isXML ) {
@@ -8465,7 +8707,9 @@
 				special.bindType || type;
 
 			// jQuery handler
-			handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
+			handle = (
+					dataPriv.get( cur, "events" ) || Object.create( null )
+				)[ event.type ] &&
 				dataPriv.get( cur, "handle" );
 			if ( handle ) {
 				handle.apply( cur, data );
@@ -8576,7 +8820,10 @@
 
 		jQuery.event.special[ fix ] = {
 			setup: function() {
-				var doc = this.ownerDocument || this,
+
+				// Handle: regular nodes (via `this.ownerDocument`), window
+				// (via `this.document`) & document (via `this`).
+				var doc = this.ownerDocument || this.document || this,
 					attaches = dataPriv.access( doc, fix );
 
 				if ( !attaches ) {
@@ -8585,7 +8832,7 @@
 				dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
 			},
 			teardown: function() {
-				var doc = this.ownerDocument || this,
+				var doc = this.ownerDocument || this.document || this,
 					attaches = dataPriv.access( doc, fix ) - 1;
 
 				if ( !attaches ) {
@@ -8601,7 +8848,7 @@
 }
 var location = window.location;
 
-var nonce = Date.now();
+var nonce = { guid: Date.now() };
 
 var rquery = ( /\?/ );
 
@@ -8733,7 +8980,7 @@
 				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
 				( this.checked || !rcheckableType.test( type ) );
 		} )
-		.map( function( i, elem ) {
+		.map( function( _i, elem ) {
 			var val = jQuery( this ).val();
 
 			if ( val == null ) {
@@ -9346,7 +9593,8 @@
 			// Add or update anti-cache param if needed
 			if ( s.cache === false ) {
 				cacheURL = cacheURL.replace( rantiCache, "$1" );
-				uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
+				uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) +
+					uncached;
 			}
 
 			// Put hash and anti-cache on the URL that will be requested (gh-1732)
@@ -9479,6 +9727,11 @@
 				response = ajaxHandleResponses( s, jqXHR, responses );
 			}
 
+			// Use a noop converter for missing script
+			if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) {
+				s.converters[ "text script" ] = function() {};
+			}
+
 			// Convert no matter what (that way responseXXX fields are always set)
 			response = ajaxConvert( s, response, jqXHR, isSuccess );
 
@@ -9569,7 +9822,7 @@
 	}
 } );
 
-jQuery.each( [ "get", "post" ], function( i, method ) {
+jQuery.each( [ "get", "post" ], function( _i, method ) {
 	jQuery[ method ] = function( url, data, callback, type ) {
 
 		// Shift arguments if data argument was omitted
@@ -9590,8 +9843,17 @@
 	};
 } );
 
+jQuery.ajaxPrefilter( function( s ) {
+	var i;
+	for ( i in s.headers ) {
+		if ( i.toLowerCase() === "content-type" ) {
+			s.contentType = s.headers[ i ] || "";
+		}
+	}
+} );
 
-jQuery._evalUrl = function( url, options ) {
+
+jQuery._evalUrl = function( url, options, doc ) {
 	return jQuery.ajax( {
 		url: url,
 
@@ -9609,7 +9871,7 @@
 			"text script": function() {}
 		},
 		dataFilter: function( response ) {
-			jQuery.globalEval( response, options );
+			jQuery.globalEval( response, options, doc );
 		}
 	} );
 };
@@ -9931,7 +10193,7 @@
 jQuery.ajaxSetup( {
 	jsonp: "callback",
 	jsonpCallback: function() {
-		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) );
 		this[ callback ] = true;
 		return callback;
 	}
@@ -10148,23 +10410,6 @@
 
 
 
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( [
-	"ajaxStart",
-	"ajaxStop",
-	"ajaxComplete",
-	"ajaxError",
-	"ajaxSuccess",
-	"ajaxSend"
-], function( i, type ) {
-	jQuery.fn[ type ] = function( fn ) {
-		return this.on( type, fn );
-	};
-} );
-
-
-
-
 jQuery.expr.pseudos.animated = function( elem ) {
 	return jQuery.grep( jQuery.timers, function( fn ) {
 		return elem === fn.elem;
@@ -10221,6 +10466,12 @@
 			options.using.call( elem, props );
 
 		} else {
+			if ( typeof props.top === "number" ) {
+				props.top += "px";
+			}
+			if ( typeof props.left === "number" ) {
+				props.left += "px";
+			}
 			curElem.css( props );
 		}
 	}
@@ -10371,7 +10622,7 @@
 // Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
 // getComputedStyle returns percent when specified for top/left/bottom/right;
 // rather than make the css module depend on the offset module, just check for it here
-jQuery.each( [ "top", "left" ], function( i, prop ) {
+jQuery.each( [ "top", "left" ], function( _i, prop ) {
 	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
 		function( elem, computed ) {
 			if ( computed ) {
@@ -10434,25 +10685,19 @@
 } );
 
 
-jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
-	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
-	"change select submit keydown keypress keyup contextmenu" ).split( " " ),
-	function( i, name ) {
-
-	// Handle event binding
-	jQuery.fn[ name ] = function( data, fn ) {
-		return arguments.length > 0 ?
-			this.on( name, null, data, fn ) :
-			this.trigger( name );
+jQuery.each( [
+	"ajaxStart",
+	"ajaxStop",
+	"ajaxComplete",
+	"ajaxError",
+	"ajaxSuccess",
+	"ajaxSend"
+], function( _i, type ) {
+	jQuery.fn[ type ] = function( fn ) {
+		return this.on( type, fn );
 	};
 } );
 
-jQuery.fn.extend( {
-	hover: function( fnOver, fnOut ) {
-		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
-	}
-} );
-
 
 
 
@@ -10474,9 +10719,33 @@
 		return arguments.length === 1 ?
 			this.off( selector, "**" ) :
 			this.off( types, selector || "**", fn );
+	},
+
+	hover: function( fnOver, fnOut ) {
+		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
 	}
 } );
 
+jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
+	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+	"change select submit keydown keypress keyup contextmenu" ).split( " " ),
+	function( _i, name ) {
+
+		// Handle event binding
+		jQuery.fn[ name ] = function( data, fn ) {
+			return arguments.length > 0 ?
+				this.on( name, null, data, fn ) :
+				this.trigger( name );
+		};
+	} );
+
+
+
+
+// Support: Android <=4.0 only
+// Make sure we trim BOM and NBSP
+var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
+
 // Bind a function to a context, optionally partially applying any
 // arguments.
 // jQuery.proxy is deprecated to promote standards (specifically Function#bind)
@@ -10539,6 +10808,11 @@
 		!isNaN( obj - parseFloat( obj ) );
 };
 
+jQuery.trim = function( text ) {
+	return text == null ?
+		"" :
+		( text + "" ).replace( rtrim, "" );
+};
 
 
 
@@ -10587,7 +10861,7 @@
 // Expose jQuery and $ identifiers, even in AMD
 // (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
 // and CommonJS for browser emulators (#13566)
-if ( !noGlobal ) {
+if ( typeof noGlobal === "undefined" ) {
 	window.jQuery = window.$ = jQuery;
 }
 
diff --git a/webconsole/src/main/debug-resources/res/lib/jquery-migrate-3.1.0.js b/webconsole/src/main/debug-resources/res/lib/jquery-migrate-3.3.0.js
old mode 100755
new mode 100644
similarity index 70%
rename from webconsole/src/main/debug-resources/res/lib/jquery-migrate-3.1.0.js
rename to webconsole/src/main/debug-resources/res/lib/jquery-migrate-3.3.0.js
index 31cf2f5..d0585ce
--- a/webconsole/src/main/debug-resources/res/lib/jquery-migrate-3.1.0.js
+++ b/webconsole/src/main/debug-resources/res/lib/jquery-migrate-3.3.0.js
@@ -1,12 +1,14 @@
 /*!
- * jQuery Migrate - v3.1.0 - 2019-06-08
+ * jQuery Migrate - v3.3.0 - 2020-05-05T01:57Z
  * Copyright OpenJS Foundation and other contributors
  */
-;( function( factory ) {
+( function( factory ) {
+	"use strict";
+
 	if ( typeof define === "function" && define.amd ) {
 
 		// AMD. Register as an anonymous module.
-		define( [ "jquery" ], function ( jQuery ) {
+		define( [ "jquery" ], function( jQuery ) {
 			return factory( jQuery, window );
 		} );
 	} else if ( typeof module === "object" && module.exports ) {
@@ -22,18 +24,16 @@
 } )( function( jQuery, window ) {
 "use strict";
 
-
-jQuery.migrateVersion = "3.1.0";
-
-/* exported jQueryVersionSince, compareVersions */
+jQuery.migrateVersion = "3.3.0";
 
 // Returns 0 if v1 == v2, -1 if v1 < v2, 1 if v1 > v2
 function compareVersions( v1, v2 ) {
-	var rVersionParts = /^(\d+)\.(\d+)\.(\d+)/,
+	var i,
+		rVersionParts = /^(\d+)\.(\d+)\.(\d+)/,
 		v1p = rVersionParts.exec( v1 ) || [ ],
 		v2p = rVersionParts.exec( v2 ) || [ ];
 
-	for ( var i = 1; i <= 3; i++ ) {
+	for ( i = 1; i <= 3; i++ ) {
 		if ( +v1p[ i ] > +v2p[ i ] ) {
 			return 1;
 		}
@@ -48,8 +48,6 @@
 	return compareVersions( jQuery.fn.jquery, version ) >= 0;
 }
 
-/* exported migrateWarn, migrateWarnFunc, migrateWarnProp */
-
 ( function() {
 
 	// Support: IE9 only
@@ -76,6 +74,9 @@
 
 var warnedAbout = {};
 
+// By default each warning is only reported once.
+jQuery.migrateDeduplicateWarnings = true;
+
 // List of warnings already given; public read only
 jQuery.migrateWarnings = [];
 
@@ -92,7 +93,7 @@
 
 function migrateWarn( msg ) {
 	var console = window.console;
-	if ( !warnedAbout[ msg ] ) {
+	if ( !jQuery.migrateDeduplicateWarnings || !warnedAbout[ msg ] ) {
 		warnedAbout[ msg ] = true;
 		jQuery.migrateWarnings.push( msg );
 		if ( console && console.warn && !jQuery.migrateMute ) {
@@ -132,12 +133,17 @@
 	migrateWarn( "jQuery is not compatible with Quirks Mode" );
 }
 
-
-var oldInit = jQuery.fn.init,
-	oldIsNumeric = jQuery.isNumeric,
+var findProp,
+	class2type = {},
+	oldInit = jQuery.fn.init,
 	oldFind = jQuery.find,
+
 	rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,
-	rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
+	rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g,
+
+	// Support: Android <=4.0 only
+	// Make sure we trim BOM and NBSP
+	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
 
 jQuery.fn.init = function( arg1 ) {
 	var args = Array.prototype.slice.call( arguments );
@@ -187,7 +193,6 @@
 };
 
 // Copy properties attached to original jQuery.find method (e.g. .attr, .isXML)
-var findProp;
 for ( findProp in oldFind ) {
 	if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) {
 		jQuery.find[ findProp ] = oldFind[ findProp ];
@@ -195,42 +200,15 @@
 }
 
 // The number of elements contained in the matched element set
-jQuery.fn.size = function() {
-	migrateWarn( "jQuery.fn.size() is deprecated and removed; use the .length property" );
+migrateWarnFunc( jQuery.fn, "size", function() {
 	return this.length;
-};
+},
+"jQuery.fn.size() is deprecated and removed; use the .length property" );
 
-jQuery.parseJSON = function() {
-	migrateWarn( "jQuery.parseJSON is deprecated; use JSON.parse" );
+migrateWarnFunc( jQuery, "parseJSON", function() {
 	return JSON.parse.apply( null, arguments );
-};
-
-jQuery.isNumeric = function( val ) {
-
-	// The jQuery 2.2.3 implementation of isNumeric
-	function isNumeric2( obj ) {
-		var realStringObj = obj && obj.toString();
-		return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
-	}
-
-	var newValue = oldIsNumeric( val ),
-		oldValue = isNumeric2( val );
-
-	if ( newValue !== oldValue ) {
-		migrateWarn( "jQuery.isNumeric() should not be called on constructed objects" );
-	}
-
-	return oldValue;
-};
-
-if ( jQueryVersionSince( "3.3.0" ) ) {
-	migrateWarnFunc( jQuery, "isWindow",
-		function( obj ) {
-			return obj != null && obj === obj.window;
-		},
-		"jQuery.isWindow() is deprecated"
-	);
-}
+},
+"jQuery.parseJSON is deprecated; use JSON.parse" );
 
 migrateWarnFunc( jQuery, "holdReady", jQuery.holdReady,
 	"jQuery.holdReady is deprecated" );
@@ -244,12 +222,81 @@
 migrateWarnProp( jQuery.expr, ":", jQuery.expr.pseudos,
 	"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos" );
 
+// Prior to jQuery 3.1.1 there were internal refs so we don't warn there
+if ( jQueryVersionSince( "3.1.1" ) ) {
+	migrateWarnFunc( jQuery, "trim", function( text ) {
+		return text == null ?
+			"" :
+			( text + "" ).replace( rtrim, "" );
+	},
+	"jQuery.trim is deprecated; use String.prototype.trim" );
+}
+
 // Prior to jQuery 3.2 there were internal refs so we don't warn there
 if ( jQueryVersionSince( "3.2.0" ) ) {
-	migrateWarnFunc( jQuery, "nodeName", jQuery.nodeName,
+	migrateWarnFunc( jQuery, "nodeName", function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+	},
 	"jQuery.nodeName is deprecated" );
 }
 
+if ( jQueryVersionSince( "3.3.0" ) ) {
+
+	migrateWarnFunc( jQuery, "isNumeric", function( obj ) {
+
+			// As of jQuery 3.0, isNumeric is limited to
+			// strings and numbers (primitives or objects)
+			// that can be coerced to finite numbers (gh-2662)
+			var type = typeof obj;
+			return ( type === "number" || type === "string" ) &&
+
+				// parseFloat NaNs numeric-cast false positives ("")
+				// ...but misinterprets leading-number strings, e.g. hex literals ("0x...")
+				// subtraction forces infinities to NaN
+				!isNaN( obj - parseFloat( obj ) );
+		},
+		"jQuery.isNumeric() is deprecated"
+	);
+
+	// Populate the class2type map
+	jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".
+		split( " " ),
+	function( _, name ) {
+		class2type[ "[object " + name + "]" ] = name.toLowerCase();
+	} );
+
+	migrateWarnFunc( jQuery, "type", function( obj ) {
+		if ( obj == null ) {
+			return obj + "";
+		}
+
+		// Support: Android <=2.3 only (functionish RegExp)
+		return typeof obj === "object" || typeof obj === "function" ?
+			class2type[ Object.prototype.toString.call( obj ) ] || "object" :
+			typeof obj;
+	},
+	"jQuery.type is deprecated" );
+
+	migrateWarnFunc( jQuery, "isFunction",
+		function( obj ) {
+			return typeof obj === "function";
+		},
+		"jQuery.isFunction() is deprecated" );
+
+	migrateWarnFunc( jQuery, "isWindow",
+		function( obj ) {
+			return obj != null && obj === obj.window;
+		},
+		"jQuery.isWindow() is deprecated"
+	);
+
+	migrateWarnFunc( jQuery, "isArray", Array.isArray,
+		"jQuery.isArray is deprecated; use Array.isArray"
+	);
+}
+
+// Support jQuery slim which excludes the ajax module
+if ( jQuery.ajax ) {
 
 var oldAjax = jQuery.ajax;
 
@@ -269,6 +316,7 @@
 	return jQXHR;
 };
 
+}
 
 var oldRemoveAttr = jQuery.fn.removeAttr,
 	oldToggleClass = jQuery.fn.toggleClass,
@@ -318,8 +366,38 @@
 	} );
 };
 
+function camelCase( string ) {
+	return string.replace( /-([a-z])/g, function( _, letter ) {
+		return letter.toUpperCase();
+	} );
+}
 
-var internalSwapCall = false;
+var oldFnCss,
+	internalSwapCall = false,
+	ralphaStart = /^[a-z]/,
+
+	// The regex visualized:
+	//
+	//                         /----------\
+	//                        |            |    /-------\
+	//                        |  / Top  \  |   |         |
+	//         /--- Border ---+-| Right  |-+---+- Width -+---\
+	//        |                 | Bottom |                    |
+	//        |                  \ Left /                     |
+	//        |                                               |
+	//        |                              /----------\     |
+	//        |          /-------------\    |            |    |- END
+	//        |         |               |   |  / Top  \  |    |
+	//        |         |  / Margin  \  |   | | Right  | |    |
+	//        |---------+-|           |-+---+-| Bottom |-+----|
+	//        |            \ Padding /         \ Left /       |
+	// BEGIN -|                                               |
+	//        |                /---------\                    |
+	//        |               |           |                   |
+	//        |               |  / Min \  |    / Width  \     |
+	//         \--------------+-|       |-+---|          |---/
+	//                           \ Max /       \ Height /
+	rautoPx = /^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/;
 
 // If this version of jQuery has .swap(), don't false-alarm on internal uses
 if ( jQuery.swap ) {
@@ -363,17 +441,58 @@
 	return ret;
 };
 
+if ( jQueryVersionSince( "3.4.0" ) && typeof Proxy !== "undefined" ) {
+
+	jQuery.cssProps = new Proxy( jQuery.cssProps || {}, {
+		set: function() {
+			migrateWarn( "JQMIGRATE: jQuery.cssProps is deprecated" );
+			return Reflect.set.apply( this, arguments );
+		}
+	} );
+}
+
+// Create a dummy jQuery.cssNumber if missing. It won't be used by jQuery but
+// it will prevent code adding new keys to it unconditionally from crashing.
+if ( !jQuery.cssNumber ) {
+	jQuery.cssNumber = {};
+}
+
+function isAutoPx( prop ) {
+
+	// The first test is used to ensure that:
+	// 1. The prop starts with a lowercase letter (as we uppercase it for the second regex).
+	// 2. The prop is not empty.
+	return ralphaStart.test( prop ) &&
+		rautoPx.test( prop[ 0 ].toUpperCase() + prop.slice( 1 ) );
+}
+
+oldFnCss = jQuery.fn.css;
+
+jQuery.fn.css = function( name, value ) {
+	var origThis = this;
+	if ( typeof name !== "string" ) {
+		jQuery.each( name, function( n, v ) {
+			jQuery.fn.css.call( origThis, n, v );
+		} );
+	}
+	if ( typeof value === "number" && !isAutoPx( camelCase( name ) ) ) {
+		migrateWarn( "Use of number-typed values is deprecated in jQuery.fn.css" );
+	}
+
+	return oldFnCss.apply( this, arguments );
+};
+
 var oldData = jQuery.data;
 
 jQuery.data = function( elem, name, value ) {
-	var curData;
+	var curData, sameKeys, key;
 
 	// Name can be an object, and each entry in the object is meant to be set as data
 	if ( name && typeof name === "object" && arguments.length === 2 ) {
 		curData = jQuery.hasData( elem ) && oldData.call( this, elem );
-		var sameKeys = {};
-		for ( var key in name ) {
-			if ( key !== jQuery.camelCase( key ) ) {
+		sameKeys = {};
+		for ( key in name ) {
+			if ( key !== camelCase( key ) ) {
 				migrateWarn( "jQuery.data() always sets/gets camelCased names: " + key );
 				curData[ key ] = name[ key ];
 			} else {
@@ -387,7 +506,7 @@
 	}
 
 	// If the name is transformed, look for the un-transformed name in the data object
-	if ( name && typeof name === "string" && name !== jQuery.camelCase( name ) ) {
+	if ( name && typeof name === "string" && name !== camelCase( name ) ) {
 		curData = jQuery.hasData( elem ) && oldData.call( this, elem );
 		if ( curData && name in curData ) {
 			migrateWarn( "jQuery.data() always sets/gets camelCased names: " + name );
@@ -401,8 +520,12 @@
 	return oldData.apply( this, arguments );
 };
 
-var oldTweenRun = jQuery.Tween.prototype.run;
-var linearEasing = function( pct ) {
+// Support jQuery slim which excludes the effects module
+if ( jQuery.fx ) {
+
+var intervalValue, intervalMsg,
+	oldTweenRun = jQuery.Tween.prototype.run,
+	linearEasing = function( pct ) {
 		return pct;
 	};
 
@@ -418,8 +541,8 @@
 	oldTweenRun.apply( this, arguments );
 };
 
-var intervalValue = jQuery.fx.interval || 13,
-	intervalMsg = "jQuery.fx.interval is deprecated";
+intervalValue = jQuery.fx.interval || 13;
+intervalMsg = "jQuery.fx.interval is deprecated";
 
 // Support: IE9, Android <=4.4
 // Avoid false positives on browsers that lack rAF
@@ -441,6 +564,8 @@
 	} );
 }
 
+}
+
 var oldLoad = jQuery.fn.load,
 	oldEventAdd = jQuery.event.add,
 	originalFix = jQuery.event.fix;
@@ -571,28 +696,57 @@
 	}
 } );
 
+var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
+	origHtmlPrefilter = jQuery.htmlPrefilter,
+	makeMarkup = function( html ) {
+		var doc = window.document.implementation.createHTMLDocument( "" );
+		doc.body.innerHTML = html;
+		return doc.body && doc.body.innerHTML;
+	},
+	warnIfChanged = function( html ) {
+		var changed = html.replace( rxhtmlTag, "<$1></$2>" );
+		if ( changed !== html && makeMarkup( html ) !== makeMarkup( changed ) ) {
+			migrateWarn( "HTML tags must be properly nested and closed: " + html );
+		}
+	};
+
+jQuery.UNSAFE_restoreLegacyHtmlPrefilter = function() {
+	jQuery.htmlPrefilter = function( html ) {
+		warnIfChanged( html );
+		return html.replace( rxhtmlTag, "<$1></$2>" );
+	};
+};
+
+jQuery.htmlPrefilter = function( html ) {
+	warnIfChanged( html );
+	return origHtmlPrefilter( html );
+};
 
 var oldOffset = jQuery.fn.offset;
 
 jQuery.fn.offset = function() {
 	var docElem,
 		elem = this[ 0 ],
-		origin = { top: 0, left: 0 };
+		bogus = { top: 0, left: 0 };
 
 	if ( !elem || !elem.nodeType ) {
 		migrateWarn( "jQuery.fn.offset() requires a valid DOM element" );
-		return origin;
+		return undefined;
 	}
 
 	docElem = ( elem.ownerDocument || window.document ).documentElement;
 	if ( !jQuery.contains( docElem, elem ) ) {
 		migrateWarn( "jQuery.fn.offset() requires an element connected to a document" );
-		return origin;
+		return bogus;
 	}
 
 	return oldOffset.apply( this, arguments );
 };
 
+// Support jQuery slim which excludes the ajax module
+// The jQuery.param patch is about respecting `jQuery.ajaxSettings.traditional`
+// so it doesn't make sense for the slim build.
+if ( jQuery.ajax ) {
 
 var oldParam = jQuery.param;
 
@@ -608,6 +762,8 @@
 	return oldParam.call( this, data, traditional );
 };
 
+}
+
 var oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
 
 jQuery.fn.andSelf = function() {
@@ -615,6 +771,8 @@
 	return oldSelf.apply( this, arguments );
 };
 
+// Support jQuery slim which excludes the deferred module in jQuery 4.0+
+if ( jQuery.Deferred ) {
 
 var oldDeferred = jQuery.Deferred,
 	tuples = [
@@ -639,14 +797,14 @@
 
 		return jQuery.Deferred( function( newDefer ) {
 			jQuery.each( tuples, function( i, tuple ) {
-				var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+				var fn = typeof fns[ i ] === "function" && fns[ i ];
 
 				// Deferred.done(function() { bind to newDefer or newDefer.resolve })
 				// deferred.fail(function() { bind to newDefer or newDefer.reject })
 				// deferred.progress(function() { bind to newDefer or newDefer.notify })
 				deferred[ tuple[ 1 ] ]( function() {
 					var returned = fn && fn.apply( this, arguments );
-					if ( returned && jQuery.isFunction( returned.promise ) ) {
+					if ( returned && typeof returned.promise === "function" ) {
 						returned.promise()
 							.done( newDefer.resolve )
 							.fail( newDefer.reject )
@@ -674,5 +832,7 @@
 // Preserve handler of uncaught exceptions in promise chains
 jQuery.Deferred.exceptionHook = oldDeferred.exceptionHook;
 
+}
+
 return jQuery;
 } );
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/User.java b/webconsole/src/main/java/org/apache/felix/webconsole/User.java
new file mode 100644
index 0000000..0e56790
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/User.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.felix.webconsole;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Representation of a user.
+ * The user object can be used by plugins to {@link #authorize(String)} the user.
+ * @since 3.4.0
+ */
+@ProviderType
+public interface User {
+    
+    /**
+     * The name of the request attribute providing an object of this class
+     */
+    String USER_ATTRIBUTE = User.class.getName();
+
+    /**
+     * Return the user object.
+     * This method might return {@code null} if no web console security provider is configured and
+     * access to the console is allowed without authentication.
+     * This is the same value as the request attribute from {@link WebConsoleSecurityProvider2#USER_ATTRIBUTE}.
+     * @return The user object or {@code null}
+     */
+    Object getUserObject();
+
+
+    /**
+     * Checks whether the user has the given role permission.
+     *
+     * @param role The requested role
+     * @return {@code true} if the user is given permission for the given role.
+     */
+    boolean authorize( String role );
+}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider.java b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider.java
index fa62d5e..39b0e07 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider.java
@@ -44,7 +44,7 @@
 
 
     /**
-     * Checks whether bthe authenticated user has the given role permission.
+     * Checks whether the authenticated user has the given role permission.
      *
      * @param user The object referring to the authenticated user. This is the
      *      object returned from the {@link #authenticate(String, String)}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/bundleinfo/package-info.java b/webconsole/src/main/java/org/apache/felix/webconsole/bundleinfo/package-info.java
new file mode 100644
index 0000000..46d6e34
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/bundleinfo/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+@org.osgi.annotation.versioning.Version("1.0.0")
+package org.apache.felix.webconsole.bundleinfo;
+
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/i18n/package-info.java b/webconsole/src/main/java/org/apache/felix/webconsole/i18n/package-info.java
new file mode 100644
index 0000000..59cd5c3
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/i18n/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+@org.osgi.annotation.versioning.Version("1.0.0")
+package org.apache.felix.webconsole.i18n;
+
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java
index 0af9428..6eb0cad 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java
@@ -99,7 +99,7 @@
         return bundleContext;
     }
 
-    private MetaTypeServiceSupport getMetaTypeSupport()
+    MetaTypeServiceSupport getMetaTypeSupport()
     {
         Object metaTypeService = configManager.getService( ConfigManager.META_TYPE_NAME );
         if ( metaTypeService != null )
@@ -162,7 +162,7 @@
         return ConfigManager.PLACEHOLDER_PID;
     }
 
-    String applyConfiguration( HttpServletRequest request, String pid )
+    String applyConfiguration( final HttpServletRequest request, final String pid, final boolean isUpdate )
             throws IOException
     {
         if ( request.getParameter( ConfigManager.ACTION_DELETE ) != null ) //$NON-NLS-1$
@@ -177,7 +177,7 @@
             return null; // return request.getHeader( "Referer" );
         }
 
-        String factoryPid = request.getParameter( ConfigManager.FACTORY_PID );
+        final String factoryPid = request.getParameter( ConfigManager.FACTORY_PID );
         Configuration config = null;
 
         String propertyList = request.getParameter( ConfigManager.PROPERTY_LIST ); //$NON-NLS-1$
@@ -316,17 +316,21 @@
                 }
             }
 
-            // remove the properties that are not specified in the request
-            final Dictionary<String, Object> updateProps = new Hashtable<>(props.size());
-            for ( Enumeration<String> e = props.keys(); e.hasMoreElements(); )
-            {
-                final String key = e.nextElement();
-                if ( propsToKeep.contains(key) )
+            if ( !isUpdate ) {
+                // remove the properties that are not specified in the request
+                final Dictionary<String, Object> updateProps = new Hashtable<>(props.size());
+                for ( Enumeration<String> e = props.keys(); e.hasMoreElements(); )
                 {
-                    updateProps.put(key, props.get(key));
+                    final String key = e.nextElement();
+                    if ( propsToKeep.contains(key) )
+                    {
+                        updateProps.put(key, props.get(key));
+                    }
                 }
+                props = updateProps;
             }
 
+
             final String location = request.getParameter(ConfigManager.LOCATION);
             if ( location == null || location.trim().length() == 0 || ConfigManager.UNBOUND_LOCATION.equals(location) )
             {
@@ -350,7 +354,7 @@
                     config.setBundleLocation(location);
                 }
             }
-            config.update( updateProps );
+            config.update( props );
         }
 
         // redirect to the new configuration (if existing)
@@ -552,8 +556,9 @@
     }
 
 
-    final void listConfigurations( JSONWriter jw, String pidFilter, String locale, Locale loc )
+    final boolean listConfigurations( JSONWriter jw, String pidFilter, String locale, Locale loc )
     {
+        boolean hasConfigurations = false;
         try
         {
             // start with ManagedService instances
@@ -609,6 +614,7 @@
             jw.array();
             for ( Iterator<String> ii = optionsPlain.keySet().iterator(); ii.hasNext(); )
             {
+                hasConfigurations = true;
                 String id = ii.next();
                 Object name = optionsPlain.get( id );
 
@@ -648,6 +654,7 @@
         {
             configManager.log("listConfigurations: Unexpected problem encountered", e);
         }
+        return hasConfigurations;
     }
 
     /**
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigManager.java
index c13cdf4..8a8284a 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigManager.java
@@ -61,6 +61,7 @@
     static final String ACTION_CREATE = "create"; //$NON-NLS-1$
     static final String ACTION_DELETE = "delete"; //$NON-NLS-1$
     static final String ACTION_APPLY = "apply"; //$NON-NLS-1$
+    static final String ACTION_UPDATE = "update"; //$NON-NLS-1$
     static final String ACTION_UNBIND = "unbind"; //$NON-NLS-1$
     static final String PROPERTY_LIST = "propertylist"; //$NON-NLS-1$
     static final String LOCATION = "$location"; //$NON-NLS-1$
@@ -160,7 +161,7 @@
         }
         else if ( request.getParameter( ACTION_APPLY ) != null )
         {
-            String redirect = cas.applyConfiguration( request, pid );
+            String redirect = cas.applyConfiguration( request, pid, ACTION_UPDATE.equals(request.getParameter(ACTION_APPLY)) );
             if ( redirect != null )
             {
                 if (pidFilter != null) {
@@ -399,12 +400,21 @@
         @SuppressWarnings("unchecked")
         final Map<String, Object> labelMap = (Map<String, Object>) request.getAttribute(WebConsoleConstants.ATTR_LABEL_MAP);
         jw.key("jsonsupport").value( labelMap.containsKey("osgi-installer-config-printer") ); //$NON-NLS-1$
+        final boolean hasMetatype = ca.getMetaTypeSupport() != null;
         jw.key("status").value( ca != null ? Boolean.TRUE : Boolean.FALSE); //$NON-NLS-1$
+        jw.key("metatype").value( hasMetatype ? Boolean.TRUE : Boolean.FALSE); //$NON-NLS-1$
+        boolean hasConfigs = true;
         if ( ca != null )
         {
-            ca.listConfigurations( jw, pidFilter, locale, loc );
+            hasConfigs = ca.listConfigurations( jw, pidFilter, locale, loc );
             ca.listFactoryConfigurations( jw, pidFilter, locale );
         }
+        if ( !hasConfigs && !hasMetatype && ca != null ) {
+            jw.key("noconfigs").value(true); //$NON-NLS-1$
+        } else {
+            jw.key("noconfigs").value(false); //$NON-NLS-1$
+        }
+
         jw.endObject();
 
         // if a configuration is addressed, display it immediately
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 28a46c6..9a3569e 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -53,6 +53,7 @@
 import org.apache.commons.io.FilenameUtils;
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.apache.felix.webconsole.BrandingPlugin;
+import org.apache.felix.webconsole.User;
 import org.apache.felix.webconsole.WebConsoleConstants;
 import org.apache.felix.webconsole.WebConsoleSecurityProvider;
 import org.apache.felix.webconsole.WebConsoleSecurityProvider2;
@@ -219,13 +220,13 @@
 
     private ServiceTracker brandingTracker;
 
-    private ServiceTracker securityProviderTracker;
+    private ServiceTracker<WebConsoleSecurityProvider, WebConsoleSecurityProvider> securityProviderTracker;
 
     private ServiceRegistration configurationListener;
 
     // list of OsgiManagerPlugin instances activated during init. All these
     // instances will have to be deactivated during destroy
-    private List osgiManagerPlugins = new ArrayList();
+    private List<OsgiManagerPlugin> osgiManagerPlugins = new ArrayList<>();
 
     private String webManagerRoot;
 
@@ -236,15 +237,15 @@
     private boolean httpResourcesRegistered;
 
     // default configuration from framework properties
-    private HashMap defaultConfiguration;
+    private Map<String, Object> defaultConfiguration;
 
     // configuration from Configuration Admin
-    private HashMap configuration;
+    private volatile Map<String, Object> configuration;
 
     // See https://issues.apache.org/jira/browse/FELIX-2267
     private Locale configuredLocale;
 
-    private Set enabledPlugins;
+    private Set<String> enabledPlugins;
 
     final ConcurrentSkipListSet<String> registeredSecurityProviders = new ConcurrentSkipListSet<String>();
 
@@ -277,13 +278,14 @@
 
             try
             {
-                Class pluginClass = classLoader.loadClass(pluginClassName);
-                Object plugin = pluginClass.newInstance();
+                final Class<?> pluginClass = classLoader.loadClass(pluginClassName);
+                final Object plugin = pluginClass.getDeclaredConstructor().newInstance();
 
                 if (plugin instanceof OsgiManagerPlugin)
                 {
-                    ((OsgiManagerPlugin) plugin).activate(bundleContext);
-                    osgiManagerPlugins.add(plugin);
+                    final OsgiManagerPlugin p = (OsgiManagerPlugin)plugin;
+                    p.activate(bundleContext);
+                    osgiManagerPlugins.add(p);
                 }
                 if (plugin instanceof BrandingPlugin)
                 {
@@ -332,13 +334,12 @@
         this.requiredSecurityProviders = splitCommaSeparatedString(bundleContext.getProperty(FRAMEWORK_PROP_SECURITY_PROVIDERS));
 
         // add support for pluggable security
-        securityProviderTracker = new ServiceTracker(bundleContext,
-            WebConsoleSecurityProvider.class.getName(),
-            new UpdateDependenciesStateCustomizer());
+        securityProviderTracker = new ServiceTracker<>(bundleContext, WebConsoleSecurityProvider.class,
+                                          new UpdateDependenciesStateCustomizer());
         securityProviderTracker.open();
 
         // load the default configuration from the framework
-        this.defaultConfiguration = new HashMap();
+        this.defaultConfiguration = new HashMap<>();
         this.defaultConfiguration.put( PROP_MANAGER_ROOT,
             ConfigurationUtil.getProperty( bundleContext, FRAMEWORK_PROP_MANAGER_ROOT, DEFAULT_MANAGER_ROOT ) );
         this.defaultConfiguration.put( PROP_REALM,
@@ -348,7 +349,7 @@
         this.defaultConfiguration.put( PROP_PASSWORD,
             ConfigurationUtil.getProperty( bundleContext, FRAMEWORK_PROP_PASSWORD, DEFAULT_PASSWORD ) );
         this.defaultConfiguration.put( PROP_LOG_LEVEL,
-            new Integer( ConfigurationUtil.getProperty( bundleContext, FRAMEWORK_PROP_LOG_LEVEL, DEFAULT_LOG_LEVEL ) ) );
+            ConfigurationUtil.getProperty( bundleContext, FRAMEWORK_PROP_LOG_LEVEL, DEFAULT_LOG_LEVEL ) );
         this.defaultConfiguration.put( PROP_LOCALE,
             ConfigurationUtil.getProperty( bundleContext, FRAMEWORK_PROP_LOCALE, null ) );
 
@@ -386,7 +387,7 @@
                 {
                     // do nothing
                 }
-            }, new Hashtable()
+            }, new Hashtable<String, Object>()
             {
                 {
                     put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" ); //$NON-NLS-1$
@@ -431,10 +432,10 @@
         }
 
         // deactivate any remaining plugins
-        for (Iterator pi = osgiManagerPlugins.iterator(); pi.hasNext();)
+        for (Iterator<OsgiManagerPlugin> pi = osgiManagerPlugins.iterator(); pi.hasNext();)
         {
-            Object plugin = pi.next();
-            ((OsgiManagerPlugin) plugin).deactivate();
+            OsgiManagerPlugin plugin = pi.next();
+            plugin.deactivate();
         }
 
         // simply remove all operations, we should not be used anymore
@@ -487,7 +488,7 @@
         // don't really expect to be called within a non-HTTP environment
         try
         {
-            AccessController.doPrivileged(new PrivilegedExceptionAction()
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
             {
                 public Object run() throws Exception
                 {
@@ -648,7 +649,7 @@
             // check for basic authentication
             String auth = request.getHeader(HEADER_AUTHORIZATION); //$NON-NLS-1$
             if (null != auth && auth.toLowerCase().startsWith("basic ")) { //$NON-NLS-1$
-                Map config = getConfiguration();
+                Map<String, Object> config = getConfiguration();
                 String realm = ConfigurationUtil.getProperty(config, PROP_REALM, DEFAULT_REALM);
                 response.setHeader(HEADER_WWW_AUTHENTICATE, "Basic realm=\"" +  realm + "\""); //$NON-NLS-1$ //$NON-NLS-2$
                 response.addCookie(new Cookie("logout", "true")); //$NON-NLS-1$ //$NON-NLS-2$
@@ -660,6 +661,7 @@
         request.removeAttribute(HttpContext.REMOTE_USER);
         request.removeAttribute(HttpContext.AUTHORIZATION);
         request.removeAttribute(WebConsoleSecurityProvider2.USER_ATTRIBUTE);
+        request.removeAttribute(User.USER_ATTRIBUTE);
     }
 
     private final AbstractWebConsolePlugin getConsolePlugin(final String label)
@@ -840,11 +842,8 @@
         return new FilteringResponseWrapper(response, resourceBundle, request);
     }
 
-    private static class HttpServiceTracker extends ServiceTracker
+    private static class HttpServiceTracker extends ServiceTracker<HttpService, HttpService>
     {
-
-        private static final String HTTP_SERVICE = "org.osgi.service.http.HttpService"; //$NON-NLS-1$
-
         private final OsgiManager osgiManager;
 
         private final String httpServiceSelector;
@@ -858,7 +857,7 @@
                 try
                 {
                     final String filterString = "(&(" + Constants.OBJECTCLASS + "=" //$NON-NLS-1$ //$NON-NLS-2$
-                        + HTTP_SERVICE + ")(" + httpServiceSelector + "))"; //$NON-NLS-1$ //$NON-NLS-2$
+                        + HttpService.class.getName() + ")(" + httpServiceSelector + "))"; //$NON-NLS-1$ //$NON-NLS-2$
                     Filter filter = osgiManager.getBundleContext().createFilter(
                         filterString);
                     return new HttpServiceTracker(osgiManager, httpServiceSelector,
@@ -876,7 +875,7 @@
 
         private HttpServiceTracker(final OsgiManager osgiManager)
         {
-            super(osgiManager.getBundleContext(), HTTP_SERVICE, null);
+            super(osgiManager.getBundleContext(), HttpService.class, null);
             this.osgiManager = osgiManager;
             this.httpServiceSelector = null;
         }
@@ -897,50 +896,38 @@
             return httpServiceSelector == null;
         }
 
-        public Object addingService(ServiceReference reference)
+        public HttpService addingService(ServiceReference<HttpService> reference)
         {
-            Object service = super.addingService(reference);
-            if (service instanceof HttpService)
-            {
-                osgiManager.bindHttpService((HttpService) service);
-            }
+            HttpService service = super.addingService(reference);
+            osgiManager.bindHttpService(service);
             return service;
         }
 
-        public void removedService(ServiceReference reference, Object service)
+        public void removedService(ServiceReference<HttpService> reference, HttpService service)
         {
-            if (service instanceof HttpService)
-            {
-                osgiManager.unbindHttpService((HttpService) service);
-            }
+            osgiManager.unbindHttpService(service);
 
             super.removedService(reference, service);
         }
     }
 
-    private static class BrandingServiceTracker extends ServiceTracker
+    private static class BrandingServiceTracker extends ServiceTracker<BrandingPlugin, BrandingPlugin>
     {
         BrandingServiceTracker(OsgiManager osgiManager)
         {
-            super(osgiManager.getBundleContext(), BrandingPlugin.class.getName(), null);
+            super(osgiManager.getBundleContext(), BrandingPlugin.class, null);
         }
 
-        public Object addingService(ServiceReference reference)
+        public BrandingPlugin addingService(ServiceReference<BrandingPlugin> reference)
         {
-            Object plugin = super.addingService(reference);
-            if (plugin instanceof BrandingPlugin)
-            {
-                AbstractWebConsolePlugin.setBrandingPlugin((BrandingPlugin) plugin);
-            }
+            BrandingPlugin plugin = super.addingService(reference);
+            AbstractWebConsolePlugin.setBrandingPlugin( plugin);
             return plugin;
         }
 
-        public void removedService(ServiceReference reference, Object service)
+        public void removedService(ServiceReference<BrandingPlugin> reference, BrandingPlugin service)
         {
-            if (service instanceof BrandingPlugin)
-            {
-                AbstractWebConsolePlugin.setBrandingPlugin(null);
-            }
+            AbstractWebConsolePlugin.setBrandingPlugin(null);
             super.removedService(reference, service);
         }
 
@@ -961,7 +948,7 @@
     }
 
     synchronized void registerHttpService() {
-        Map config = getConfiguration();
+        Map<String, Object> config = getConfiguration();
 
         // get authentication details
         String realm = ConfigurationUtil.getProperty(config, PROP_REALM, DEFAULT_REALM);
@@ -974,7 +961,7 @@
             HttpContext httpContext = new OsgiManagerHttpContext(bundleContext, httpService,
                 securityProviderTracker, userId, password, realm);
 
-            Dictionary servletConfig = toStringConfig(config);
+            Dictionary<String, String> servletConfig = toStringConfig(config);
 
             if (!httpServletRegistered) {
                 // register this servlet and take note of this
@@ -1045,27 +1032,27 @@
     }
 
 
-    private Map getConfiguration()
+    private Map<String, Object> getConfiguration()
     {
         return configuration;
     }
 
 
-    Map getDefaultConfiguration()
+    Map<String, Object> getDefaultConfiguration()
     {
         return defaultConfiguration;
     }
 
 
-    synchronized void updateConfiguration( Dictionary osgiConfig )
+    synchronized void updateConfiguration( Dictionary<String, Object> osgiConfig )
     {
-        HashMap config = new HashMap( this.defaultConfiguration );
+        Map<String, Object> config = new HashMap<String, Object>( this.defaultConfiguration );
 
         if ( osgiConfig != null )
         {
-            for ( Enumeration keys = osgiConfig.keys(); keys.hasMoreElements(); )
+            for ( Enumeration<String> keys = osgiConfig.keys(); keys.hasMoreElements(); )
             {
-                final Object key = keys.nextElement();
+                final String key = keys.nextElement();
                 config.put( key, osgiConfig.get( key ) );
             }
         }
@@ -1105,7 +1092,7 @@
 
         // get enabled plugins
         String[] plugins = ConfigurationUtil.getStringArrayProperty(config, PROP_ENABLED_PLUGINS);
-        enabledPlugins = null == plugins ? null : new HashSet(Arrays.asList(plugins));
+        enabledPlugins = null == plugins ? null : new HashSet<String>(Arrays.asList(plugins));
         // check for moved config manager class (see FELIX-4074)
         if ( enabledPlugins != null )
         {
@@ -1180,12 +1167,12 @@
     }
 
 
-    private Dictionary toStringConfig( Map config )
+    private Dictionary<String, String> toStringConfig( Map<String, Object> config )
     {
-        Dictionary stringConfig = new Hashtable();
-        for ( Iterator ei = config.entrySet().iterator(); ei.hasNext(); )
+        Dictionary<String, String> stringConfig = new Hashtable<>();
+        for ( Iterator<Map.Entry<String, Object>> ei = config.entrySet().iterator(); ei.hasNext(); )
         {
-            Entry entry = ( Entry ) ei.next();
+            Entry<String, Object> entry = ei.next();
             stringConfig.put( entry.getKey(), String.valueOf( entry.getValue() ) );
         }
         return stringConfig;
@@ -1233,9 +1220,9 @@
         return langMap = map;
     }
 
-    class UpdateDependenciesStateCustomizer implements ServiceTrackerCustomizer {
+    class UpdateDependenciesStateCustomizer implements ServiceTrackerCustomizer<WebConsoleSecurityProvider, WebConsoleSecurityProvider> {
         @Override
-        public Object addingService(ServiceReference reference) {
+        public WebConsoleSecurityProvider addingService(ServiceReference<WebConsoleSecurityProvider> reference) {
             Object nameObj = reference.getProperty(SECURITY_PROVIDER_PROPERTY_NAME);
             if (nameObj instanceof String) {
                 String name = (String) nameObj;
@@ -1246,13 +1233,13 @@
         }
 
         @Override
-        public void modifiedService(ServiceReference reference, Object service) {
+        public void modifiedService(ServiceReference<WebConsoleSecurityProvider> reference, WebConsoleSecurityProvider service) {
             removedService(reference, service);
             addingService(reference);
         }
 
         @Override
-        public void removedService(ServiceReference reference, Object service) {
+        public void removedService(ServiceReference<WebConsoleSecurityProvider> reference, WebConsoleSecurityProvider service) {
             Object nameObj = reference.getProperty(SECURITY_PROVIDER_PROPERTY_NAME);
             if (nameObj instanceof String) {
                 String name = (String) nameObj;
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
index 03cf735..c7d472f 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
@@ -23,6 +23,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.felix.webconsole.User;
 import org.apache.felix.webconsole.WebConsoleSecurityProvider;
 import org.apache.felix.webconsole.WebConsoleSecurityProvider2;
 import org.osgi.framework.BundleContext;
@@ -44,7 +45,7 @@
 
     private final HttpContext base;
 
-    private final ServiceTracker tracker;
+    private final ServiceTracker<WebConsoleSecurityProvider, WebConsoleSecurityProvider> tracker;
 
     private final String username;
 
@@ -54,7 +55,7 @@
 
 
     OsgiManagerHttpContext(final BundleContext bundleContext,
-        final HttpService httpService, final ServiceTracker tracker, final String username,
+        final HttpService httpService, final ServiceTracker<WebConsoleSecurityProvider, WebConsoleSecurityProvider> tracker, final String username,
         final String password, final String realm )
     {
         this.bundleContext = bundleContext;
@@ -95,19 +96,52 @@
      *            <code>Authorization</code> header.
      * @param response The HTTP response used to send the authentication request
      *            if authentication is required but not satisfied.
-     * @return <code>true</code> if authentication is required and not
-     *         satisfied by the request.
+     * @return {@code} true if authentication is required and not satisfied by the request.
      */
-    public boolean handleSecurity( HttpServletRequest request, HttpServletResponse response )
-    {
-        Object provider = tracker.getService();
+    public boolean handleSecurity( final HttpServletRequest request, final HttpServletResponse response ) {
+        final WebConsoleSecurityProvider provider = tracker.getService();
 
         // check whether the security provider can fully handle the request
-        if ( provider instanceof WebConsoleSecurityProvider2 )
-        {
-            return ( ( WebConsoleSecurityProvider2 ) provider ).authenticate( request, response );
+        final boolean result;
+        if ( provider instanceof WebConsoleSecurityProvider2 ) {
+            result = ( ( WebConsoleSecurityProvider2 ) provider ).authenticate( request, response );
+        } else {
+            result = handleSecurity(provider, request, response);
         }
 
+        if ( result ) {
+            request.setAttribute(User.USER_ATTRIBUTE, new User(){
+
+				@Override
+				public boolean authorize(String role) {
+                    final Object user = this.getUserObject();
+                    if ( user == null ) {
+                        // no user object in request, deny
+                        return false;
+                    }
+					if ( provider == null ) {
+                        // no provider, allow (compatibility)
+                        return true;
+                    }
+					return provider.authorize(this.getUserObject(), role);
+				}
+
+				@Override
+				public Object getUserObject() {
+					return request.getAttribute(WebConsoleSecurityProvider2.USER_ATTRIBUTE);
+				}
+                
+            });
+        }
+        return result;
+    }
+
+    /**
+     * Handle security with an optional web console security provider
+     */
+    private boolean handleSecurity( final WebConsoleSecurityProvider provider, 
+        final HttpServletRequest request,
+        final HttpServletResponse response) {
         // Return immediately if the header is missing
         String authHeader = request.getHeader( HEADER_AUTHORIZATION );
         if ( authHeader != null && authHeader.length() > 0 )
@@ -170,27 +204,6 @@
         return false;
     }
 
-
-    public boolean authorize( final HttpServletRequest request, String role )
-    {
-        Object user = request.getAttribute( WebConsoleSecurityProvider2.USER_ATTRIBUTE );
-        if ( user != null )
-        {
-            WebConsoleSecurityProvider provider = ( WebConsoleSecurityProvider ) tracker.getService();
-            if ( provider != null )
-            {
-                return provider.authorize( user, role );
-            }
-
-            // no provider, grant access (backwards compatibility)
-            return true;
-        }
-
-        // missing user in the request, deny access
-        return false;
-    }
-
-
     private static byte[][] base64Decode( String srcString )
     {
         byte[] transformed = Base64.decodeBase64( srcString );
@@ -225,11 +238,11 @@
     }
 
 
-    private boolean authenticate( Object provider, String username, byte[] password )
+    private boolean authenticate( WebConsoleSecurityProvider provider, String username, byte[] password )
     {
         if ( provider != null )
         {
-            return ( ( WebConsoleSecurityProvider ) provider ).authenticate( username, toString( password ) ) != null;
+            return provider.authenticate( username, toString( password ) ) != null;
         }
         if ( this.username.equals( username ) && this.password.matches( password ) )
         {
@@ -240,5 +253,4 @@
         }
         return false;
     }
-
 }
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/package-info.java b/webconsole/src/main/java/org/apache/felix/webconsole/package-info.java
new file mode 100644
index 0000000..beefc07
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+@org.osgi.annotation.versioning.Version("3.4.0")
+package org.apache.felix.webconsole;
+
diff --git a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
index 5dd397b..6fbc505 100644
--- a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -174,6 +174,9 @@
 configMgr.pluginTitle=Configuration
 config.status.ok=Configuration Admin Service is running.
 config.status.missing=Configuration Admin Service is not installed/running.
+config.metatype.ok=Metatype Service is available.
+config.metatype.missing=Metatype service is missing.
+config.noconfigs=No configurations available.
 config.properties=Properties
 config.properties.enter=Enter Name-Value pairs of configuration properties
 config.info.title=Configuration Information
diff --git a/webconsole/src/main/resources/res/lib/jquery-3.4.1.js b/webconsole/src/main/resources/res/lib/jquery-3.4.1.js
deleted file mode 100755
index a1c07fd..0000000
--- a/webconsole/src/main/resources/res/lib/jquery-3.4.1.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
-!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(p,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),"function"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k="sizzle"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",$=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",F=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="<a id='"+k+"'></a><select id='"+k+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(F," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[k]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,"$1"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(B,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split("").sort(D).join("")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[":"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,"parentNode")},parentsUntil:function(e,t,n){return T(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return T(e,"nextSibling")},prevAll:function(e){return T(e,"previousSibling")},nextUntil:function(e,t,n){return T(e,"nextSibling",n)},prevUntil:function(e,t,n){return T(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return"undefined"!=typeof e.contentDocument?e.contentDocument:(A(e,"template")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\x20\t\r\n\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[["notify","progress",k.Callbacks("memory"),k.Callbacks("memory"),2],["resolve","done",k.Callbacks("once memory"),k.Callbacks("once memory"),0,"resolved"],["reject","fail",k.Callbacks("once memory"),k.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),k.ready()}k.fn.ready=function(e){return F.then(e)["catch"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,"ms-").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(Z,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks("once memory").add(function(){Q.remove(e,[t+"queue",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Q.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ne=new RegExp("^(?:([+-])=|)("+te+")([a-z%]*)$","i"),re=["Top","Right","Bottom","Left"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&oe(e)&&"none"===k.css(e,"display")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,"")},u=s(),l=n&&n[3]||(k.cssNumber[t]?"":"px"),c=e.nodeType&&(k.cssNumber[t]||"px"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Q.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ce[s]=u)))):"none"!==n&&(l[c]="none",Q.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],"globalEval",!t||Q.get(t[n],"globalEval"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement("div")),(xe=E.createElement("input")).setAttribute("type","radio"),xe.setAttribute("checked","checked"),xe.setAttribute("name","t"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Q.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:"focusin",blur:"focusout"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/<script|<style|<link/i,Le=/checked\s*(?:[^=]|=\s*.checked.)/i,He=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,"script"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Q.access(u,"globalEval")&&k.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")}):b(u.textContent.replace(He,""),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,"<$1></$2>")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp("^("+te+")(?!px)[a-z%]+$","i"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join("|"),"i");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",u.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n="1%"!==e.top,a=12===t(e.marginLeft),u.style.right="60%",o=36===t(e.right),r=36===t(e.width),u.style.position="absolute",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement("div"),u=E.createElement("div");u.style&&(u.style.backgroundClip="content-box",u.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=["Webkit","Moz","ms"],Xe=E.createElement("div").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:"absolute",visibility:"hidden",display:"block"},Ke={letterSpacing:"0",fontWeight:"400"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function et(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=k.css(e,n+re[a],!0,i)),r?("content"===n&&(u-=k.css(e,"padding"+re[a],!0,i)),"margin"!==n&&(u-=k.css(e,"border"+re[a]+"Width",!0,i))):(u+=k.css(e,"padding"+re[a],!0,i),"padding"!==n?u+=k.css(e,"border"+re[a]+"Width",!0,i):s+=k.css(e,"border"+re[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&"border-box"===k.css(e,"boxSizing",!1,r),o=i,a=_e(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||"auto"===a||!parseFloat(a)&&"inline"===k.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===k.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?"border":"content"),o,r,a)+"px"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),"normal"===i&&t in Ke&&(i=Ke[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each(["height","width"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===k.css(e,"boxSizing",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,"border",!1,i)-.5)),s&&(r=ne.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,"marginLeft"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),k.each({margin:"",padding:"",border:"Width"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?"":"px")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=re[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,"fxshow");for(r in n.queue||(null==(a=k._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,"display")),"none"===(c=k.css(e,"display"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,"display"),fe([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===k.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Q.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,"fxshow"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&"object"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Q.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each(["toggle","show","hide"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft("show"),slideUp:ft("hide"),slideToggle:ft("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement("input"),at=E.createElement("select").appendChild(E.createElement("option")),ot.type="checkbox",y.checkOn=""!==ot.value,y.optSelected=at.selected,(ot=E.createElement("input")).value="t",ot.type="radio",y.radioValue="t"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(" ")}function xt(e){return e.getAttribute&&e.getAttribute("class")||""}function bt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,"tabindex");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr("class","");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=xt(this))&&Q.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Q.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+mt(xt(n))+" ").indexOf(t))return!0;return!1}});var wt=/\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?"":e+""})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(wt,""):null==e?"":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,"value");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each(["radio","checkbox"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[k.expando]?e:new k.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,"events")||{})[e.type]&&Q.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\?/;k.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||k.error("Invalid XML: "+e),t};var Nt=/\[\]$/,At=/\r?\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)qt(n+"["+t+"]",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join("&")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,"elements");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(":disabled")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,"\r\n")}}):{name:t.name,value:n.replace(At,"\r\n")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Ft=E.createElement("a");function Bt(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+"").replace(Mt,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(R)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+"//"+Ft.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Lt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(St.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,"$1"),o=(St.test(f)?"&":"?")+"_="+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader("If-Modified-Since",k.lastModified[f]),k.etag[f]&&T.setRequestHeader("If-None-Match",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+$t+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(k.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(k.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--k.active||k.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,"json")},getScript:function(e,t){return k.get(e,void 0,t,"script")}}),k.each(["get","post"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&"withCredentials"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),k.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&k.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?k("<div>").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),k.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},"function"==typeof define&&define.amd&&define("jquery",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});
diff --git a/webconsole/src/main/resources/res/lib/jquery-3.5.1.js b/webconsole/src/main/resources/res/lib/jquery-3.5.1.js
new file mode 100644
index 0000000..b061403
--- /dev/null
+++ b/webconsole/src/main/resources/res/lib/jquery-3.5.1.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(D).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var j,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^key/,we=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ce(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function ke(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)ke(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Ae(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,Ce)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click",Ce),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ce:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ce,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ce,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ce,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&be.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&we.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Ae(this,e,Se),!1},trigger:function(){return Ae(this,e),!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return ke(this,e,t,n,r)},one:function(e,t,n,r){return ke(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){S.event.remove(this,e,n,t)})}});var Ne=/<script|<style|<link/i,De=/checked\s*(?:[^=]|=\s*.checked.)/i,je=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function Pe(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&De.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Pe(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),Le)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,He),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(je,""),u,l))}return n}function Re(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Oe(o[r],a[r]);else Oe(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Pe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Pe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ne.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Pe(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Me=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},We=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Fe=new RegExp(ne.join("|"),"i");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||Ie(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Me.test(a)&&Fe.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function $e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px",t.style.height="1px",n.style.height="9px",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=3<parseInt(r.height),re.removeChild(e)),a}}))}();var _e=["Webkit","Moz","ms"],ze=E.createElement("div").style,Ue={};function Xe(e){var t=S.cssProps[e]||Ue[e];return t||(e in ze?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_e.length;while(n--)if((e=_e[n]+t)in ze)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Ge=/^--/,Ye={position:"absolute",visibility:"hidden",display:"block"},Qe={letterSpacing:"0",fontWeight:"400"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=Be(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?"border":"content"),o,r,a)+"px"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Ge.test(t)||(t=Xe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Qe&&(i=Qe[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,u,n):We(e,Ye,function(){return Ze(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Je(0,t,s)}}}),S.cssHooks.marginLeft=$e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Je)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=et).prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}}).init.prototype=et.prototype,(et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=et.prototype.init,S.fx.step={};var tt,nt,rt,it,ot=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function st(){nt&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(st):C.setTimeout(st,S.fx.interval),S.fx.tick())}function ut(){return C.setTimeout(function(){tt=void 0}),tt=Date.now()}function lt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ct(e,t,n){for(var r,i=(ft.tweeners[t]||[]).concat(ft.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ft(o,e,t){var n,a,r=0,i=ft.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=tt||ut(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:tt||ut(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=ft.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ct,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(ft,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],ft.tweeners[n]=ft.tweeners[n]||[],ft.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ot.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ct(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ft.prefilters.unshift(e):ft.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=ft(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&at.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),S.each({slideDown:lt("show"),slideUp:lt("hide"),slideToggle:lt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),tt=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){nt||(nt=!0,st())},S.fx.stop=function(){nt=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},rt=E.createElement("input"),it=E.createElement("select").appendChild(E.createElement("option")),rt.type="checkbox",y.checkOn=""!==rt.value,y.optSelected=it.selected,(rt=E.createElement("input")).value="t",rt.type="radio",y.radioValue="t"===rt.value;var pt,dt=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=dt[t]||S.find.attr;dt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=dt[o],dt[o]=r,r=null!=a(e,t,n)?o:null,dt[o]=i),r}});var ht=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function mt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):ht.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,yt(this)))});if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr("class","");if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=mt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=yt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+vt(yt(n))+" ").indexOf(t))return!0;return!1}});var xt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(xt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:vt(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var bt=/^(?:focusinfocus|focusoutblur)$/,wt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!bt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,bt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,wt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,wt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var Tt=C.location,Ct={guid:Date.now()},Et=/\?/;S.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||S.error("Invalid XML: "+e),t};var St=/\[\]$/,kt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Nt=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||St.test(n)?i(n,t):Dt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)Dt(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&Nt.test(this.nodeName)&&!At.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(kt,"\r\n")}}):{name:t.name,value:n.replace(kt,"\r\n")}}).get()}});var jt=/%20/g,qt=/#.*$/,Lt=/([?&])_=[^&]*/,Ht=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ot=/^(?:GET|HEAD)$/,Pt=/^\/\//,Rt={},Mt={},It="*/".concat("*"),Wt=E.createElement("a");function Ft(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Bt(t,i,o,a){var s={},u=t===Mt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function $t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Wt.href=Tt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":It,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,S.ajaxSettings),t):$t(S.ajaxSettings,e)},ajaxPrefilter:Ft(Rt),ajaxTransport:Ft(Mt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Ht.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Tt.href)+"").replace(Pt,Tt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Wt.protocol+"//"+Wt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Bt(Rt,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ot.test(v.type),f=v.url.replace(qt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(jt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Et.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Lt,"$1"),o=(Et.test(f)?"&":"?")+"_="+Ct.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+It+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Bt(Mt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var _t={0:200,1223:204},zt=S.ajaxSettings.xhr();y.cors=!!zt&&"withCredentials"in zt,y.ajax=zt=!!zt,S.ajaxTransport(function(i){var o,a;if(y.cors||zt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(_t[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Gt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Gt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
diff --git a/webconsole/src/main/resources/res/lib/jquery-migrate-3.1.0.js b/webconsole/src/main/resources/res/lib/jquery-migrate-3.1.0.js
deleted file mode 100755
index 023af8f..0000000
--- a/webconsole/src/main/resources/res/lib/jquery-migrate-3.1.0.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! jQuery Migrate v3.1.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
-"undefined"==typeof jQuery.migrateMute&&(jQuery.migrateMute=!0),function(t){"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e,window)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery"),window):t(jQuery,window)}(function(s,n){"use strict";function e(e){return 0<=function(e,t){for(var r=/^(\d+)\.(\d+)\.(\d+)/,n=r.exec(e)||[],o=r.exec(t)||[],i=1;i<=3;i++){if(+n[i]>+o[i])return 1;if(+n[i]<+o[i])return-1}return 0}(s.fn.jquery,e)}s.migrateVersion="3.1.0",n.console&&n.console.log&&(s&&e("3.0.0")||n.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),s.migrateWarnings&&n.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),n.console.log("JQMIGRATE: Migrate is installed"+(s.migrateMute?"":" with logging active")+", version "+s.migrateVersion));var r={};function u(e){var t=n.console;r[e]||(r[e]=!0,s.migrateWarnings.push(e),t&&t.warn&&!s.migrateMute&&(t.warn("JQMIGRATE: "+e),s.migrateTrace&&t.trace&&t.trace()))}function t(e,t,r,n){Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:function(){return u(n),r},set:function(e){u(n),r=e}})}function o(e,t,r,n){e[t]=function(){return u(n),r.apply(this,arguments)}}s.migrateWarnings=[],void 0===s.migrateTrace&&(s.migrateTrace=!0),s.migrateReset=function(){r={},s.migrateWarnings.length=0},"BackCompat"===n.document.compatMode&&u("jQuery is not compatible with Quirks Mode");var i,a=s.fn.init,c=s.isNumeric,d=s.find,l=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,p=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;for(i in s.fn.init=function(e){var t=Array.prototype.slice.call(arguments);return"string"==typeof e&&"#"===e&&(u("jQuery( '#' ) is not a valid selector"),t[0]=[]),a.apply(this,t)},s.fn.init.prototype=s.fn,s.find=function(t){var r=Array.prototype.slice.call(arguments);if("string"==typeof t&&l.test(t))try{n.document.querySelector(t)}catch(e){t=t.replace(p,function(e,t,r,n){return"["+t+r+'"'+n+'"]'});try{n.document.querySelector(t),u("Attribute selector with '#' must be quoted: "+r[0]),r[0]=t}catch(e){u("Attribute selector with '#' was not fixed: "+r[0])}}return d.apply(this,r)},d)Object.prototype.hasOwnProperty.call(d,i)&&(s.find[i]=d[i]);s.fn.size=function(){return u("jQuery.fn.size() is deprecated and removed; use the .length property"),this.length},s.parseJSON=function(){return u("jQuery.parseJSON is deprecated; use JSON.parse"),JSON.parse.apply(null,arguments)},s.isNumeric=function(e){var t,r,n=c(e),o=(r=(t=e)&&t.toString(),!s.isArray(t)&&0<=r-parseFloat(r)+1);return n!==o&&u("jQuery.isNumeric() should not be called on constructed objects"),o},e("3.3.0")&&o(s,"isWindow",function(e){return null!=e&&e===e.window},"jQuery.isWindow() is deprecated"),o(s,"holdReady",s.holdReady,"jQuery.holdReady is deprecated"),o(s,"unique",s.uniqueSort,"jQuery.unique is deprecated; use jQuery.uniqueSort"),t(s.expr,"filters",s.expr.pseudos,"jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),t(s.expr,":",s.expr.pseudos,"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"),e("3.2.0")&&o(s,"nodeName",s.nodeName,"jQuery.nodeName is deprecated");var f=s.ajax;s.ajax=function(){var e=f.apply(this,arguments);return e.promise&&(o(e,"success",e.done,"jQXHR.success is deprecated and removed"),o(e,"error",e.fail,"jQXHR.error is deprecated and removed"),o(e,"complete",e.always,"jQXHR.complete is deprecated and removed")),e};var y=s.fn.removeAttr,m=s.fn.toggleClass,h=/\S+/g;s.fn.removeAttr=function(e){var r=this;return s.each(e.match(h),function(e,t){s.expr.match.bool.test(t)&&(u("jQuery.fn.removeAttr no longer sets boolean properties: "+t),r.prop(t,!1))}),y.apply(this,arguments)};var g=!(s.fn.toggleClass=function(t){return void 0!==t&&"boolean"!=typeof t?m.apply(this,arguments):(u("jQuery.fn.toggleClass( boolean ) is deprecated"),this.each(function(){var e=this.getAttribute&&this.getAttribute("class")||"";e&&s.data(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===t?"":s.data(this,"__className__")||"")}))});s.swap&&s.each(["height","width","reliableMarginRight"],function(e,t){var r=s.cssHooks[t]&&s.cssHooks[t].get;r&&(s.cssHooks[t].get=function(){var e;return g=!0,e=r.apply(this,arguments),g=!1,e})}),s.swap=function(e,t,r,n){var o,i,a={};for(i in g||u("jQuery.swap() is undocumented and deprecated"),t)a[i]=e.style[i],e.style[i]=t[i];for(i in o=r.apply(e,n||[]),t)e.style[i]=a[i];return o};var v=s.data;s.data=function(e,t,r){var n;if(t&&"object"==typeof t&&2===arguments.length){n=s.hasData(e)&&v.call(this,e);var o={};for(var i in t)i!==s.camelCase(i)?(u("jQuery.data() always sets/gets camelCased names: "+i),n[i]=t[i]):o[i]=t[i];return v.call(this,e,o),t}return t&&"string"==typeof t&&t!==s.camelCase(t)&&(n=s.hasData(e)&&v.call(this,e))&&t in n?(u("jQuery.data() always sets/gets camelCased names: "+t),2<arguments.length&&(n[t]=r),n[t]):v.apply(this,arguments)};function j(e){return e}var Q=s.Tween.prototype.run;s.Tween.prototype.run=function(){1<s.easing[this.easing].length&&(u("'jQuery.easing."+this.easing.toString()+"' should use only one argument"),s.easing[this.easing]=j),Q.apply(this,arguments)};var w=s.fx.interval||13,b="jQuery.fx.interval is deprecated";n.requestAnimationFrame&&Object.defineProperty(s.fx,"interval",{configurable:!0,enumerable:!0,get:function(){return n.document.hidden||u(b),w},set:function(e){u(b),w=e}});var x=s.fn.load,k=s.event.add,A=s.event.fix;s.event.props=[],s.event.fixHooks={},t(s.event.props,"concat",s.event.props.concat,"jQuery.event.props.concat() is deprecated and removed"),s.event.fix=function(e){var t,r=e.type,n=this.fixHooks[r],o=s.event.props;if(o.length){u("jQuery.event.props are deprecated and removed: "+o.join());while(o.length)s.event.addProp(o.pop())}if(n&&!n._migrated_&&(n._migrated_=!0,u("jQuery.event.fixHooks are deprecated and removed: "+r),(o=n.props)&&o.length))while(o.length)s.event.addProp(o.pop());return t=A.call(this,e),n&&n.filter?n.filter(t,e):t},s.event.add=function(e,t){return e===n&&"load"===t&&"complete"===n.document.readyState&&u("jQuery(window).on('load'...) called after load event occurred"),k.apply(this,arguments)},s.each(["load","unload","error"],function(e,t){s.fn[t]=function(){var e=Array.prototype.slice.call(arguments,0);return"load"===t&&"string"==typeof e[0]?x.apply(this,e):(u("jQuery.fn."+t+"() is deprecated"),e.splice(0,0,t),arguments.length?this.on.apply(this,e):(this.triggerHandler.apply(this,e),this))}}),s.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,r){s.fn[r]=function(e,t){return u("jQuery.fn."+r+"() event shorthand is deprecated"),0<arguments.length?this.on(r,null,e,t):this.trigger(r)}}),s(function(){s(n.document).triggerHandler("ready")}),s.event.special.ready={setup:function(){this===n.document&&u("'ready' event is deprecated")}},s.fn.extend({bind:function(e,t,r){return u("jQuery.fn.bind() is deprecated"),this.on(e,null,t,r)},unbind:function(e,t){return u("jQuery.fn.unbind() is deprecated"),this.off(e,null,t)},delegate:function(e,t,r,n){return u("jQuery.fn.delegate() is deprecated"),this.on(t,e,r,n)},undelegate:function(e,t,r){return u("jQuery.fn.undelegate() is deprecated"),1===arguments.length?this.off(e,"**"):this.off(t,e||"**",r)},hover:function(e,t){return u("jQuery.fn.hover() is deprecated"),this.on("mouseenter",e).on("mouseleave",t||e)}});var S=s.fn.offset;s.fn.offset=function(){var e,t=this[0],r={top:0,left:0};return t&&t.nodeType?(e=(t.ownerDocument||n.document).documentElement,s.contains(e,t)?S.apply(this,arguments):(u("jQuery.fn.offset() requires an element connected to a document"),r)):(u("jQuery.fn.offset() requires a valid DOM element"),r)};var q=s.param;s.param=function(e,t){var r=s.ajaxSettings&&s.ajaxSettings.traditional;return void 0===t&&r&&(u("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),t=r),q.call(this,e,t)};var C=s.fn.andSelf||s.fn.addBack;s.fn.andSelf=function(){return u("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),C.apply(this,arguments)};var M=s.Deferred,R=[["resolve","done",s.Callbacks("once memory"),s.Callbacks("once memory"),"resolved"],["reject","fail",s.Callbacks("once memory"),s.Callbacks("once memory"),"rejected"],["notify","progress",s.Callbacks("memory"),s.Callbacks("memory")]];return s.Deferred=function(e){var i=M(),a=i.promise();return i.pipe=a.pipe=function(){var o=arguments;return u("deferred.pipe() is deprecated"),s.Deferred(function(n){s.each(R,function(e,t){var r=s.isFunction(o[e])&&o[e];i[t[1]](function(){var e=r&&r.apply(this,arguments);e&&s.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[t[0]+"With"](this===a?n.promise():this,r?[e]:arguments)})}),o=null}).promise()},e&&e.call(i,i),i},s.Deferred.exceptionHook=M.exceptionHook,s});
diff --git a/webconsole/src/main/resources/res/lib/jquery-migrate-3.3.0.js b/webconsole/src/main/resources/res/lib/jquery-migrate-3.3.0.js
new file mode 100644
index 0000000..411afbd
--- /dev/null
+++ b/webconsole/src/main/resources/res/lib/jquery-migrate-3.3.0.js
@@ -0,0 +1,2 @@
+/*! jQuery Migrate v3.3.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+"undefined"==typeof jQuery.migrateMute&&(jQuery.migrateMute=!0),function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e,window)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery"),window):t(jQuery,window)}(function(s,n){"use strict";function e(e){return 0<=function(e,t){var r,n=/^(\d+)\.(\d+)\.(\d+)/,i=n.exec(e)||[],o=n.exec(t)||[];for(r=1;r<=3;r++){if(+i[r]>+o[r])return 1;if(+i[r]<+o[r])return-1}return 0}(s.fn.jquery,e)}s.migrateVersion="3.3.0",n.console&&n.console.log&&(s&&e("3.0.0")||n.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),s.migrateWarnings&&n.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),n.console.log("JQMIGRATE: Migrate is installed"+(s.migrateMute?"":" with logging active")+", version "+s.migrateVersion));var r={};function u(e){var t=n.console;s.migrateDeduplicateWarnings&&r[e]||(r[e]=!0,s.migrateWarnings.push(e),t&&t.warn&&!s.migrateMute&&(t.warn("JQMIGRATE: "+e),s.migrateTrace&&t.trace&&t.trace()))}function t(e,t,r,n){Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:function(){return u(n),r},set:function(e){u(n),r=e}})}function i(e,t,r,n){e[t]=function(){return u(n),r.apply(this,arguments)}}s.migrateDeduplicateWarnings=!0,s.migrateWarnings=[],void 0===s.migrateTrace&&(s.migrateTrace=!0),s.migrateReset=function(){r={},s.migrateWarnings.length=0},"BackCompat"===n.document.compatMode&&u("jQuery is not compatible with Quirks Mode");var o,a={},c=s.fn.init,d=s.find,l=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,p=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g,f=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;for(o in s.fn.init=function(e){var t=Array.prototype.slice.call(arguments);return"string"==typeof e&&"#"===e&&(u("jQuery( '#' ) is not a valid selector"),t[0]=[]),c.apply(this,t)},s.fn.init.prototype=s.fn,s.find=function(t){var r=Array.prototype.slice.call(arguments);if("string"==typeof t&&l.test(t))try{n.document.querySelector(t)}catch(e){t=t.replace(p,function(e,t,r,n){return"["+t+r+'"'+n+'"]'});try{n.document.querySelector(t),u("Attribute selector with '#' must be quoted: "+r[0]),r[0]=t}catch(e){u("Attribute selector with '#' was not fixed: "+r[0])}}return d.apply(this,r)},d)Object.prototype.hasOwnProperty.call(d,o)&&(s.find[o]=d[o]);if(i(s.fn,"size",function(){return this.length},"jQuery.fn.size() is deprecated and removed; use the .length property"),i(s,"parseJSON",function(){return JSON.parse.apply(null,arguments)},"jQuery.parseJSON is deprecated; use JSON.parse"),i(s,"holdReady",s.holdReady,"jQuery.holdReady is deprecated"),i(s,"unique",s.uniqueSort,"jQuery.unique is deprecated; use jQuery.uniqueSort"),t(s.expr,"filters",s.expr.pseudos,"jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),t(s.expr,":",s.expr.pseudos,"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"),e("3.1.1")&&i(s,"trim",function(e){return null==e?"":(e+"").replace(f,"")},"jQuery.trim is deprecated; use String.prototype.trim"),e("3.2.0")&&i(s,"nodeName",function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},"jQuery.nodeName is deprecated"),e("3.3.0")&&(i(s,"isNumeric",function(e){var t=typeof e;return("number"==t||"string"==t)&&!isNaN(e-parseFloat(e))},"jQuery.isNumeric() is deprecated"),s.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){a["[object "+t+"]"]=t.toLowerCase()}),i(s,"type",function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?a[Object.prototype.toString.call(e)]||"object":typeof e},"jQuery.type is deprecated"),i(s,"isFunction",function(e){return"function"==typeof e},"jQuery.isFunction() is deprecated"),i(s,"isWindow",function(e){return null!=e&&e===e.window},"jQuery.isWindow() is deprecated"),i(s,"isArray",Array.isArray,"jQuery.isArray is deprecated; use Array.isArray")),s.ajax){var y=s.ajax;s.ajax=function(){var e=y.apply(this,arguments);return e.promise&&(i(e,"success",e.done,"jQXHR.success is deprecated and removed"),i(e,"error",e.fail,"jQXHR.error is deprecated and removed"),i(e,"complete",e.always,"jQXHR.complete is deprecated and removed")),e}}var m=s.fn.removeAttr,g=s.fn.toggleClass,h=/\S+/g;function v(e){return e.replace(/-([a-z])/g,function(e,t){return t.toUpperCase()})}s.fn.removeAttr=function(e){var r=this;return s.each(e.match(h),function(e,t){s.expr.match.bool.test(t)&&(u("jQuery.fn.removeAttr no longer sets boolean properties: "+t),r.prop(t,!1))}),m.apply(this,arguments)};var j,Q=!(s.fn.toggleClass=function(t){return void 0!==t&&"boolean"!=typeof t?g.apply(this,arguments):(u("jQuery.fn.toggleClass( boolean ) is deprecated"),this.each(function(){var e=this.getAttribute&&this.getAttribute("class")||"";e&&s.data(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===t?"":s.data(this,"__className__")||"")}))}),b=/^[a-z]/,w=/^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/;s.swap&&s.each(["height","width","reliableMarginRight"],function(e,t){var r=s.cssHooks[t]&&s.cssHooks[t].get;r&&(s.cssHooks[t].get=function(){var e;return Q=!0,e=r.apply(this,arguments),Q=!1,e})}),s.swap=function(e,t,r,n){var i,o,a={};for(o in Q||u("jQuery.swap() is undocumented and deprecated"),t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=r.apply(e,n||[]),t)e.style[o]=a[o];return i},e("3.4.0")&&"undefined"!=typeof Proxy&&(s.cssProps=new Proxy(s.cssProps||{},{set:function(){return u("JQMIGRATE: jQuery.cssProps is deprecated"),Reflect.set.apply(this,arguments)}})),s.cssNumber||(s.cssNumber={}),j=s.fn.css,s.fn.css=function(e,t){var r=this;return"string"!=typeof e&&s.each(e,function(e,t){s.fn.css.call(r,e,t)}),"number"!=typeof t||function(e){return b.test(e)&&w.test(e[0].toUpperCase()+e.slice(1))}(v(e))||u("Use of number-typed values is deprecated in jQuery.fn.css"),j.apply(this,arguments)};var x=s.data;if(s.data=function(e,t,r){var n,i,o;if(t&&"object"==typeof t&&2===arguments.length){for(o in n=s.hasData(e)&&x.call(this,e),i={},t)o!==v(o)?(u("jQuery.data() always sets/gets camelCased names: "+o),n[o]=t[o]):i[o]=t[o];return x.call(this,e,i),t}return t&&"string"==typeof t&&t!==v(t)&&(n=s.hasData(e)&&x.call(this,e))&&t in n?(u("jQuery.data() always sets/gets camelCased names: "+t),2<arguments.length&&(n[t]=r),n[t]):x.apply(this,arguments)},s.fx){var A,k,M=s.Tween.prototype.run,S=function(e){return e};s.Tween.prototype.run=function(){1<s.easing[this.easing].length&&(u("'jQuery.easing."+this.easing.toString()+"' should use only one argument"),s.easing[this.easing]=S),M.apply(this,arguments)},A=s.fx.interval||13,k="jQuery.fx.interval is deprecated",n.requestAnimationFrame&&Object.defineProperty(s.fx,"interval",{configurable:!0,enumerable:!0,get:function(){return n.document.hidden||u(k),A},set:function(e){u(k),A=e}})}var H=s.fn.load,R=s.event.add,N=s.event.fix;s.event.props=[],s.event.fixHooks={},t(s.event.props,"concat",s.event.props.concat,"jQuery.event.props.concat() is deprecated and removed"),s.event.fix=function(e){var t,r=e.type,n=this.fixHooks[r],i=s.event.props;if(i.length){u("jQuery.event.props are deprecated and removed: "+i.join());while(i.length)s.event.addProp(i.pop())}if(n&&!n._migrated_&&(n._migrated_=!0,u("jQuery.event.fixHooks are deprecated and removed: "+r),(i=n.props)&&i.length))while(i.length)s.event.addProp(i.pop());return t=N.call(this,e),n&&n.filter?n.filter(t,e):t},s.event.add=function(e,t){return e===n&&"load"===t&&"complete"===n.document.readyState&&u("jQuery(window).on('load'...) called after load event occurred"),R.apply(this,arguments)},s.each(["load","unload","error"],function(e,t){s.fn[t]=function(){var e=Array.prototype.slice.call(arguments,0);return"load"===t&&"string"==typeof e[0]?H.apply(this,e):(u("jQuery.fn."+t+"() is deprecated"),e.splice(0,0,t),arguments.length?this.on.apply(this,e):(this.triggerHandler.apply(this,e),this))}}),s.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,r){s.fn[r]=function(e,t){return u("jQuery.fn."+r+"() event shorthand is deprecated"),0<arguments.length?this.on(r,null,e,t):this.trigger(r)}}),s(function(){s(n.document).triggerHandler("ready")}),s.event.special.ready={setup:function(){this===n.document&&u("'ready' event is deprecated")}},s.fn.extend({bind:function(e,t,r){return u("jQuery.fn.bind() is deprecated"),this.on(e,null,t,r)},unbind:function(e,t){return u("jQuery.fn.unbind() is deprecated"),this.off(e,null,t)},delegate:function(e,t,r,n){return u("jQuery.fn.delegate() is deprecated"),this.on(t,e,r,n)},undelegate:function(e,t,r){return u("jQuery.fn.undelegate() is deprecated"),1===arguments.length?this.off(e,"**"):this.off(t,e||"**",r)},hover:function(e,t){return u("jQuery.fn.hover() is deprecated"),this.on("mouseenter",e).on("mouseleave",t||e)}});function C(e){var t=n.document.implementation.createHTMLDocument("");return t.body.innerHTML=e,t.body&&t.body.innerHTML}function T(e){var t=e.replace(P,"<$1></$2>");t!==e&&C(e)!==C(t)&&u("HTML tags must be properly nested and closed: "+e)}var P=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,q=s.htmlPrefilter;s.UNSAFE_restoreLegacyHtmlPrefilter=function(){s.htmlPrefilter=function(e){return T(e),e.replace(P,"<$1></$2>")}},s.htmlPrefilter=function(e){return T(e),q(e)};var D=s.fn.offset;if(s.fn.offset=function(){var e,t=this[0];if(t&&t.nodeType)return e=(t.ownerDocument||n.document).documentElement,s.contains(e,t)?D.apply(this,arguments):(u("jQuery.fn.offset() requires an element connected to a document"),{top:0,left:0});u("jQuery.fn.offset() requires a valid DOM element")},s.ajax){var E=s.param;s.param=function(e,t){var r=s.ajaxSettings&&s.ajaxSettings.traditional;return void 0===t&&r&&(u("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),t=r),E.call(this,e,t)}}var _=s.fn.andSelf||s.fn.addBack;if(s.fn.andSelf=function(){return u("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),_.apply(this,arguments)},s.Deferred){var F=s.Deferred,O=[["resolve","done",s.Callbacks("once memory"),s.Callbacks("once memory"),"resolved"],["reject","fail",s.Callbacks("once memory"),s.Callbacks("once memory"),"rejected"],["notify","progress",s.Callbacks("memory"),s.Callbacks("memory")]];s.Deferred=function(e){var o=F(),a=o.promise();return o.pipe=a.pipe=function(){var i=arguments;return u("deferred.pipe() is deprecated"),s.Deferred(function(n){s.each(O,function(e,t){var r="function"==typeof i[e]&&i[e];o[t[1]](function(){var e=r&&r.apply(this,arguments);e&&"function"==typeof e.promise?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[t[0]+"With"](this===a?n.promise():this,r?[e]:arguments)})}),i=null}).promise()},e&&e.call(o,o),o},s.Deferred.exceptionHook=F.exceptionHook}return s});
diff --git a/webconsole/src/main/resources/res/ui/config.js b/webconsole/src/main/resources/res/ui/config.js
index ebe2b93..4634d62 100644
--- a/webconsole/src/main/resources/res/ui/config.js
+++ b/webconsole/src/main/resources/res/ui/config.js
@@ -698,12 +698,19 @@
 	jsonSupport = configData.jsonsupport;
 
 	// display the configuration data
-	$(".statline").html(configData.status ? i18n.stat_ok : i18n.stat_missing);
+	var line = configData.status ? i18n.stat_ok : i18n.stat_missing;
+	line = line + " " + (configData.metatype ? i18n.metatype_ok : i18n.metatype_missing);
+	if ( configData.noconfigs ) {
+	    line = line + " " + i18n.noconfigs;
+	}
+	$(".statline").html(line);
 	if (configData.status) {
+	    var hasData = false;
 		configBody.empty();
 		var factories = {};
 
 		for(var i in configData.pids) {
+		    hasData = true;
 			var c = configData.pids[i];
 			if (c.fpid) {
 				if (!factories[c.fpid]) factories[c.fpid] = new Array();
@@ -713,6 +720,7 @@
 			}
 		}
 		for(var i in configData.fpids) {
+            hasData = true;
 			addFactoryConfig(configData.fpids[i]);
 
 			var fpid = configData.fpids[i].id;
@@ -733,17 +741,19 @@
 		}
 		initStaticWidgets(configTable);
 
-		// init tablesorte
-		configTable.tablesorter({
-			headers: {
-				0: { sorter: false },
-				3: { sorter: false }
-			},
-			sortList: [[1,1]],
-			textExtraction: treetableExtraction
-		}).bind('sortStart', function() { // clear cache, otherwise extraction will not work
-			var table = $(this).trigger('update'); 
-		}).find('th:eq(1)').click();
+		// init tablesorter
+		if ( hasData ) {
+		    configTable.tablesorter({
+			    headers: {
+				    0: { sorter: false },
+				    3: { sorter: false }
+			    },
+			    sortList: [[1,1]],
+			    textExtraction: treetableExtraction
+		    }).bind('sortStart', function() { // clear cache, otherwise extraction will not work
+			    var table = $(this).trigger('update'); 
+		    }).find('th:eq(1)').click();
+	 }
 	} else {
 		configContent.addClass('ui-helper-hidden');
 	}
diff --git a/webconsole/src/main/resources/templates/config.html b/webconsole/src/main/resources/templates/config.html
index d354f9a..fe87717 100644
--- a/webconsole/src/main/resources/templates/config.html
+++ b/webconsole/src/main/resources/templates/config.html
@@ -9,6 +9,9 @@
 var i18n = { // i18n
 	stat_ok      : '${config.status.ok}', // "Configuration Admin Service is running.";
 	stat_missing : '${config.status.missing}', //"Configuration Admin Service is not installed/running."
+    metatype_ok  : '${config.metatype.ok}',
+    metatype_missing  : '${config.metatype.missing}',
+    noconfigs    : '${config.noconfigs}',
 	save         : '${save}',
 	reset        : '${reset}',
 	del          : '${delete}',
diff --git a/webconsole/src/main/resources/templates/main_header.html b/webconsole/src/main/resources/templates/main_header.html
index f3e7183..eda6f80 100644
--- a/webconsole/src/main/resources/templates/main_header.html
+++ b/webconsole/src/main/resources/templates/main_header.html
@@ -18,8 +18,8 @@
 	// ]]>
 	</script>
 
-	<script src="${appRoot}/res/lib/jquery-3.4.1.js"></script>
-	<script src="${appRoot}/res/lib/jquery-migrate-3.1.0.js"></script>
+	<script src="${appRoot}/res/lib/jquery-3.5.1.js"></script>
+	<script src="${appRoot}/res/lib/jquery-migrate-3.3.0.js"></script>
 	<script src="${appRoot}/res/lib/jquery-ui-1.12.1.js"></script>
 	<script src="${appRoot}/res/lib/jquery-ui-i18n-1.12.1.js" type="text/javascript"></script>
 	<script src="${appRoot}/res/lib/jquery.cookies-2.2.0.js" type="text/javascript"></script>
diff --git a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
index 2664100..0b49dbd 100644
--- a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
+++ b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
@@ -36,7 +36,7 @@
         OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(bc, svc, null, "foo", "bar", "blah");
 
         Method authenticateMethod = OsgiManagerHttpContext.class.getDeclaredMethod(
-                "authenticate", new Class [] {Object.class, String.class, byte[].class});
+                "authenticate", new Class [] {WebConsoleSecurityProvider.class, String.class, byte[].class});
         authenticateMethod.setAccessible(true);
 
         assertEquals(true, authenticateMethod.invoke(ctx, null, "foo", "bar".getBytes()));
@@ -57,7 +57,7 @@
         OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(bc, svc, null, "foo", "bar", "blah");
 
         Method authenticateMethod = OsgiManagerHttpContext.class.getDeclaredMethod(
-                "authenticate", new Class [] {Object.class, String.class, byte[].class});
+                "authenticate", new Class [] {WebConsoleSecurityProvider.class, String.class, byte[].class});
         authenticateMethod.setAccessible(true);
 
         assertEquals("A required security provider is configured, logging in using "
diff --git a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
index 49f6af7..7c52482 100644
--- a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
+++ b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
@@ -36,6 +36,7 @@
 import java.util.List;
 import java.util.Set;
 
+import org.apache.felix.webconsole.WebConsoleSecurityProvider;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
@@ -134,13 +135,13 @@
         final List<String> invocations = new ArrayList<String>();
         ServiceTrackerCustomizer stc = mgr.new UpdateDependenciesStateCustomizer() {
             @Override
-            public Object addingService(ServiceReference reference) {
+            public WebConsoleSecurityProvider addingService(ServiceReference<WebConsoleSecurityProvider> reference) {
                 invocations.add("added:" + reference);
                 return null;
             }
 
             @Override
-            public void removedService(ServiceReference reference, Object service) {
+            public void removedService(ServiceReference<WebConsoleSecurityProvider> reference, WebConsoleSecurityProvider service) {
                 invocations.add("removed:" + reference);
             }
         };