resolve merge conflicts
diff --git a/.dockerignore b/.dockerignore
index ca65eed..302c3f5 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,4 +1,4 @@
 views/
 applications/
-containers/
 xos/tests/api/node_modules
+xos/configurations/cord-pod/images
diff --git a/.gitignore b/.gitignore
index 3c86d00..bf493e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@
 !xos/core/static/xos.css
 .DS_Store
 xos/configurations/setup/
+migrations/
diff --git a/containers/onos/Dockerfile b/containers/onos/Dockerfile
new file mode 100644
index 0000000..d00b8e2
--- /dev/null
+++ b/containers/onos/Dockerfile
@@ -0,0 +1,57 @@
+FROM debian:jessie
+MAINTAINER Zack Williams <zdw@cs.arizona.edu>
+
+# Add Java 8 repository
+ENV DEBIAN_FRONTEND noninteractive
+RUN echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
+    echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \
+    echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \
+    apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
+
+# Set the environment variables
+ENV HOME /root
+ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
+ENV ONOS_ROOT /src/onos
+ENV KARAF_VERSION 3.0.5
+ENV KARAF_ROOT /root/onos/apache-karaf-3.0.5
+ENV KARAF_LOG /root/onos/apache-karaf-3.0.5/data/log/karaf.log
+ENV BUILD_NUMBER docker
+ENV PATH $PATH:$KARAF_ROOT/bin
+
+#Download and Build ONOS
+WORKDIR /src
+RUN     apt-get update && apt-get install -y python maven git curl oracle-java8-installer oracle-java8-set-default && \
+        git clone https://github.com/opennetworkinglab/onos.git && cd onos && \
+        git checkout f503a62372ffa55150936628689d1435109ffccb && \
+        mkdir -p /root/Downloads && \
+        mvn clean install && \
+        tools/build/onos-package && \
+        rm -rf /root/.m2 && cd .. && \
+        rm -rf onos && \
+        apt-get remove --purge -y `apt-mark showauto` && \
+        apt-get install oracle-java8-set-default -y && \
+        apt-get clean && apt-get purge -y && apt-get autoremove -y && \
+        rm -rf /var/lib/apt/lists/* && \
+        rm -rf /var/cache/oracle-jdk8-installer && \
+        rm -rf /root/Downloads
+
+# Change to /root directory
+WORKDIR /root
+
+#Install ONOS
+RUN mkdir onos && \
+   mv /tmp/onos-*.docker.tar.gz . && \
+   tar -xf onos-*.docker.tar.gz -C onos --strip-components=1 && \
+   rm -rf onos-*.docker.tar.gz
+
+# Ports
+# 6653 - OpenFlow
+# 8181 - GUI
+# 8101 - ONOS CLI
+# 9876 - ONOS CLUSTER COMMUNICATION
+EXPOSE 6653 8181 8101 9876
+
+# Get ready to run command
+WORKDIR /root/onos
+ENTRYPOINT ["./bin/onos-service"]
+
diff --git a/containers/onos/Makefile b/containers/onos/Makefile
new file mode 100644
index 0000000..4db1a9b
--- /dev/null
+++ b/containers/onos/Makefile
@@ -0,0 +1,15 @@
+IMAGE_NAME:=xosproject/onos-fork
+CONTAINER_NAME:=onos-fork
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/containers/synchronizer/Dockerfile b/containers/synchronizer/Dockerfile
index 011e8dd..2f1e092 100644
--- a/containers/synchronizer/Dockerfile
+++ b/containers/synchronizer/Dockerfile
@@ -1,48 +1,6 @@
 FROM       xosproject/xos
 
-RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
-    openssh-client \
-    python-crypto \
-    python-jinja2 \
-    python-paramiko \
-    python-yaml \
-    python-httplib2 \
-    rsync \
-    supervisor
-
-RUN pip install -U \
-    jinja2
-
-# Install custom Ansible
-RUN \
-    git clone -b release1.8.2 git://github.com/ansible/ansible.git /opt/ansible && \
-    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/lib/ansible/modules/extras && \
-    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/v2/ansible/modules/extras && \
-    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/lib/ansible/modules/core && \
-    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/v2/ansible/modules/core && \
-    # git clone uses cached copy, doesn't pick up latest
-    git -C /opt/ansible pull && \
-    git -C /opt/ansible/lib/ansible/modules/core pull && \
-    git -C /opt/ansible/v2/ansible/modules/core pull
-
-
-# For Observer
-RUN mkdir -p /usr/local/share /bin /etc/ansible
-
-COPY conf/ansible-hosts /etc/ansible/hosts
-
-ADD http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-x86_64.tar.bz2 /usr/local/share/
-
-RUN git clone git://git.planet-lab.org/fofum.git /tmp/fofum && \
-    cd /tmp/fofum; python setup.py install && \
-    rm -rf /tmp/fofum && \
-    tar jxvf /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2 -C /usr/local/share/ && \
-    rm -f /usr/local/share/phantomjs-1.7.0-linux-x86_64.tar.bz2 && \
-    ln -s /usr/local/share/phantomjs-1.7.0-linux-x86_64 /usr/local/share/phantomjs && \
-    ln -s /usr/local/share/phantomjs/bin/phantomjs /bin/phantomjs
-
-
 # Supervisor
 COPY conf/synchronizer.conf /etc/supervisor/conf.d/
 
-CMD update-ca-certificates && /usr/bin/supervisord -c /etc/supervisor/conf.d/synchronizer.conf
+CMD /usr/bin/supervisord -c /etc/supervisor/conf.d/synchronizer.conf
diff --git a/containers/xos/Dockerfile b/containers/xos/Dockerfile
index afc7c9d..cbaad65 100644
--- a/containers/xos/Dockerfile
+++ b/containers/xos/Dockerfile
@@ -1,96 +1,26 @@
-FROM       ubuntu:14.04.3
+FROM xosproject/xos-base
 
-# XXX Workaround for docker bug:
-# https://github.com/docker/docker/issues/6345
-# Kernel 3.15 breaks docker, uss the line below as a workaround
-# until there is a fix
-RUN ln -s -f /bin/true /usr/bin/chfn
-# XXX End workaround
+# Include certificates from Openstack
+ADD local_certs.crt /usr/local/share/ca-certificates/local_certs.crt
+RUN update-ca-certificates
 
-# Install.
-RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
-    curl \
-    gcc \
-    geoip-database \
-    git \
-    graphviz \
-    graphviz-dev \
-    libgeoip1 \
-    libxslt1.1 \
-    libxslt1-dev \
-    libyaml-dev \
-    m4 \
-    pkg-config \
-    python-dev \
-    python-httplib2 \
-    python-pip \
-    python-psycopg2 \
-    python-pycurl \
-    python-setuptools \
-    tar \
-    wget \
-##### observer dependencies
-    python-keystoneclient \
-    python-novaclient \
-    python-neutronclient \
-    python-glanceclient \
-    python-ceilometerclient
+# Install and boostrap XOS and Tosca
+ENV XOS_GIT_REPO git://github.com/open-cloud/xos.git
+ENV XOS_GIT_BRANCH master
 
-RUN pip install \
-    django==1.7 \
-    django-bitfield \
-    django-crispy-forms \
-    django-encrypted-fields \
-    django-extensions \
-    django-filter==0.11.0 \
-    django-geoposition \
-    django-ipware \
-    django_rest_swagger \
-    django-suit==0.3a1 \
-    django-timezones \
-    djangorestframework==3.3.3 \
-    dnslib \
-    jinja2 \
-    lxml \
-    markdown \
-    netaddr \
-    pyOpenSSL \
-    psycopg2 \
-    python-ceilometerclient \
-    python-dateutil \
-    python-keyczar \
-    python-logstash \
-    pygraphviz \
-    pytz \
-    pyyaml \
-    requests
-
-RUN easy_install --upgrade httplib2
-
-RUN easy_install \
-    python_gflags \
-    google_api_python_client \
-    httplib2.ca_certs_locater
-
-ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
-
-# Install XOS
-RUN git clone git://github.com/open-cloud/xos.git /tmp/xos && \
+RUN git clone $XOS_GIT_REPO -b $XOS_GIT_BRANCH /tmp/xos && \
     mv /tmp/xos/xos /opt/ && \
     chmod +x /opt/xos/tools/xos-manage && \
     /opt/xos/tools/xos-manage genkeys
 
-# install Tosca engine
-RUN chmod +x /opt/xos/tosca/run.py
-RUN bash /opt/xos/tosca/install_tosca.sh
-
 EXPOSE 8000
 
-# Set environment variables.
+# Set environment variables
 ENV HOME /root
 
-# Define working directory.
+# Define working directory
 WORKDIR /opt/xos
 
-# Define default command.
-CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+# Define default command
+CMD python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+
diff --git a/containers/xos/Dockerfile.base b/containers/xos/Dockerfile.base
new file mode 100644
index 0000000..e430dc8
--- /dev/null
+++ b/containers/xos/Dockerfile.base
@@ -0,0 +1,142 @@
+# Dockerfile.base
+# This image isn't used, but installs the prereqs for the other XOS images
+
+FROM       ubuntu:14.04.3
+
+# XXX Workaround for docker bug:
+# https://github.com/docker/docker/issues/6345
+# Kernel 3.15 breaks docker, uss the line below as a workaround
+# until there is a fix
+RUN ln -s -f /bin/true /usr/bin/chfn
+# XXX End workaround
+
+# Install apt packages
+RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
+    apt-transport-https \
+    curl \
+    gcc \
+    geoip-database \
+    git \
+    graphviz \
+    graphviz-dev \
+    libgeoip1 \
+    libxslt1-dev \
+    libxslt1.1 \
+    libyaml-dev \
+    m4 \
+    openssh-client \
+    pkg-config \
+    python-ceilometerclient \
+    python-crypto \
+    python-dev \
+    python-glanceclient \
+    python-httplib2 \
+    python-jinja2 \
+    python-keystoneclient \
+    python-neutronclient \
+    python-novaclient \
+    python-paramiko \
+    python-pip \
+    python-psycopg2 \
+    python-pycurl \
+    python-setuptools \
+    python-yaml \
+    rsync \
+    supervisor \
+    tar \
+    wget \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install python pacakges with pip
+RUN pip install \
+    django==1.7 \
+    django-bitfield \
+    django-crispy-forms \
+    django-encrypted-fields \
+    django-extensions \
+    django-filter==0.11.0 \
+    django-geoposition \
+    django-ipware \
+    django_rest_swagger \
+    django-suit==0.3a1 \
+    django-timezones \
+    djangorestframework==3.3.3 \
+    dnslib \
+    jinja2 \
+    lxml \
+    markdown \
+    netaddr \
+    pyOpenSSL \
+    psycopg2 \
+    python-ceilometerclient \
+    python-dateutil \
+    python-keyczar \
+    python-logstash \
+    pygraphviz \
+    pytz \
+    pyyaml \
+    requests
+
+# Upgrade jinja2
+RUN pip install -U \
+    jinja2
+
+# Installs with Easy install (should be incorporated into pip?)
+RUN easy_install --upgrade httplib2
+
+RUN easy_install \
+    python_gflags \
+    google_api_python_client \
+    httplib2.ca_certs_locater
+
+# jQuery download w/checksum
+ENV JQUERY_VERSION jquery-1.9.1.min.js
+ENV JQUERY_DL_URL http://code.jquery.com/jquery-1.9.1.min.js
+ENV JQUERY_SHA256 c12f6098e641aaca96c60215800f18f5671039aecf812217fab3c0d152f6adb4
+
+RUN wget $JQUERY_DL_URL && \
+  echo "$JQUERY_SHA256  $JQUERY_VERSION" | sha256sum -c - && \
+  mv $JQUERY_VERSION /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+
+# Install heat-translator for TOSCA support
+ENV HT_REPO_URL https://github.com/openstack/heat-translator.git
+ENV HT_REF a951b93c16e54046ed2d233d814860181c772e30
+
+RUN git clone $HT_REPO_URL /tmp/heat-translator && \
+    cd /tmp/heat-translator && \
+    git checkout $HT_REF && \
+    mkdir -p /opt/tosca && \
+    mv /tmp/heat-translator/translator /opt/tosca/translator && \
+    echo > /opt/tosca/translator/__init__.py && \
+    rm -rf /tmp/heat-translator
+
+# Install custom Ansible
+RUN \
+    git clone -b release1.8.2 git://github.com/ansible/ansible.git /opt/ansible && \
+    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/lib/ansible/modules/extras && \
+    git clone -b release1.8.2 git://github.com/ansible/ansible-modules-extras.git /opt/ansible/v2/ansible/modules/extras && \
+    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/lib/ansible/modules/core && \
+    git clone git://github.com/sb98052/ansible-modules-core.git /opt/ansible/v2/ansible/modules/core && \
+    # git clone uses cached copy, doesn't pick up latest
+    git -C /opt/ansible pull && \
+    git -C /opt/ansible/lib/ansible/modules/core pull && \
+    git -C /opt/ansible/v2/ansible/modules/core pull && \
+    mkdir -p /usr/local/share /bin /etc/ansible
+
+COPY ansible-hosts /etc/ansible/hosts
+
+# For Synchronizer
+ENV PHANTOMJS_DL_URL http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-x86_64.tar.bz2
+ENV PHANTOMJS_SHA256 a7658f5f2d9464f86891afdb979eb60b754d5f404801db624368ac11e16724d4
+
+RUN curl -fLsS $PHANTOMJS_DL_URL -o phantomjs.tar.bz2 && \
+  echo "$PHANTOMJS_SHA256  phantomjs.tar.bz2" | sha256sum -c - && \
+  tar -C /usr/local/share -xjf phantomjs.tar.bz2 && \
+  ln -s /usr/local/share/phantomjs-* /usr/local/share/phantomjs && \
+  ln -s /usr/local/share/phantomjs/bin/phantomjs /bin/phantomjs && \
+  rm phantomjs.tar.bz2
+
+RUN git clone git://git.planet-lab.org/fofum.git /tmp/fofum && \
+    cd /tmp/fofum; python setup.py install && \
+    rm -rf /tmp/fofum
+
diff --git a/containers/xos/Dockerfile.devel b/containers/xos/Dockerfile.devel
index 5dc62a6..6d1c510 100644
--- a/containers/xos/Dockerfile.devel
+++ b/containers/xos/Dockerfile.devel
@@ -1,95 +1,23 @@
-FROM       ubuntu:14.04.3
+FROM xosproject/xos-base
 
-# XXX Workaround for docker bug:
-# https://github.com/docker/docker/issues/6345
-# Kernel 3.15 breaks docker, uss the line below as a workaround
-# until there is a fix
-RUN ln -s -f /bin/true /usr/bin/chfn
-# XXX End workaround
-
-# Install.
-RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
-    curl \
-    gcc \
-    geoip-database \
-    git \
-    graphviz \
-    graphviz-dev \
-    libgeoip1 \
-    libxslt1.1 \
-    libxslt1-dev \
-    libyaml-dev \
-    m4 \
-    pkg-config \
-    python-dev \
-    python-httplib2 \
-    python-pip \
-    python-psycopg2 \
-    python-pycurl \
-    python-setuptools \
-    tar \
-    wget \
-##### observer dependencies
-    python-keystoneclient \
-    python-novaclient \
-    python-neutronclient \
-    python-glanceclient \
-    python-ceilometerclient
-
-RUN pip install \
-    django==1.7 \
-    django-bitfield \
-    django-crispy-forms \
-    django-encrypted-fields \
-    django-extensions \
-    django-filter==0.11.0 \
-    django-geoposition \
-    django-ipware \
-    django_rest_swagger \
-    django-suit==0.3a1 \
-    django-timezones \
-    djangorestframework==3.3.3 \
-    dnslib \
-    jinja2 \
-    lxml \
-    markdown \
-    netaddr \
-    pyOpenSSL \
-    psycopg2 \
-    python-ceilometerclient \
-    python-dateutil \
-    python-keyczar \
-    python-logstash \
-    pygraphviz \
-    pytz \
-    pyyaml \
-    requests
-
-RUN easy_install --upgrade httplib2
-
-RUN easy_install \
-    python_gflags \
-    google_api_python_client \
-    httplib2.ca_certs_locater
-
-ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
+# Include certificates from Openstack
+ADD containers/xos/local_certs.crt /usr/local/share/ca-certificates/local_certs.crt
+RUN update-ca-certificates
 
 # Install XOS
 ADD xos /opt/xos
-RUN chmod +x /opt/xos/tools/xos-manage
-RUN /opt/xos/tools/xos-manage genkeys
 
-# install Tosca engine
-RUN chmod +x /opt/xos/tosca/run.py
-RUN bash /opt/xos/tosca/install_tosca.sh
+RUN chmod +x /opt/xos/tools/xos-manage && sync && \
+    /opt/xos/tools/xos-manage genkeys
 
 EXPOSE 8000
 
-# Set environment variables.
+# Set environment variables
 ENV HOME /root
 
-# Define working directory.
+# Define working directory
 WORKDIR /opt/xos
 
-# Define default command.
-CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+# Define default command
+CMD python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+
diff --git a/containers/xos/Dockerfile.templ b/containers/xos/Dockerfile.templ
deleted file mode 100644
index cfcf9ac..0000000
--- a/containers/xos/Dockerfile.templ
+++ /dev/null
@@ -1,89 +0,0 @@
-FROM       ubuntu:14.04.3
-
-# XXX Workaround for docker bug:
-# https://github.com/docker/docker/issues/6345
-# Kernel 3.15 breaks docker, uss the line below as a workaround
-# until there is a fix
-RUN ln -s -f /bin/true /usr/bin/chfn
-# XXX End workaround
-
-# Install.
-RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
-    curl \
-    gcc \
-    geoip-database \
-    git \
-    graphviz \
-    graphviz-dev \
-    libgeoip1 \
-    libxslt1.1 \
-    libxslt1-dev \
-    libyaml-dev \
-    m4 \
-    pkg-config \
-    python-dev \
-    python-httplib2 \
-    python-pip \
-    python-psycopg2 \
-    python-pycurl \
-    python-setuptools \
-    tar \
-    wget \
-##### observer dependencies
-    python-keystoneclient \
-    python-novaclient \
-    python-neutronclient \
-    python-glanceclient \
-    python-ceilometerclient
-
-RUN pip install -U \
-    django==1.7 \
-    django-bitfield \
-    django-crispy-forms \
-    django-encrypted-fields \
-    django_evolution \
-    django-extensions \
-    django-filter==0.11.0 \
-    django-geoposition \
-    django-ipware \
-    django_rest_swagger \
-    django-suit==0.3a1 \
-    django-timezones \
-    djangorestframework==3.3.3 \
-    dnslib \
-    google_api_python_client \
-    httplib2 \
-    httplib2.ca_certs_locater \
-    lxml \
-    markdown \
-    netaddr \
-    python-dateutil \
-    python_gflags \
-    python-keyczar \
-    python-logstash \
-    pygraphviz \
-    pytz \
-    pyyaml \
-    requests
-
-ADD http://code.jquery.com/jquery-1.9.1.min.js /usr/local/lib/python2.7/dist-packages/suit/static/suit/js/
-
-# Install XOS
-RUN git clone XOS_GIT_REPO -b XOS_GIT_BRANCH /tmp/xos && \
-    mv /tmp/xos/xos /opt/ && \
-    chmod +x /opt/xos/tools/xos-manage && \
-    /opt/xos/tools/xos-manage genkeys
-
-# install Tosca engine
-RUN bash /opt/xos/tosca/install_tosca.sh
-
-EXPOSE 8000
-
-# Set environment variables.
-ENV HOME /root
-
-# Define working directory.
-WORKDIR /root
-
-# Define default command.
-CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
diff --git a/containers/xos/Dockerfile.test b/containers/xos/Dockerfile.test
index 8b01b98..ac3c14c 100644
--- a/containers/xos/Dockerfile.test
+++ b/containers/xos/Dockerfile.test
@@ -1,9 +1,17 @@
 FROM       xosproject/xos
 
 # install nodejs
-RUN curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
-RUN sudo apt-get install -y nodejs
+COPY containers/xos/nodesource.gpg.key /tmp/nodesource.gpg.key
+
+RUN apt-key add /tmp/nodesource.gpg.key && \
+    echo "deb https://deb.nodesource.com/node_4.x trusty main" \
+    > /etc/apt/sources.list.d/nodesource.list
+
+RUN apt-get update && apt-get install -y --force-yes nodejs && \
+    rm -rf /var/lib/apt/lists/*
+
 RUN node -v
 
 # install node modules
-# RUN cd /opt/xos/tests/api; npm install
\ No newline at end of file
+# RUN cd /opt/xos/tests/api; npm install
+
diff --git a/containers/xos/Makefile b/containers/xos/Makefile
index cf91988..1f856b7 100644
--- a/containers/xos/Makefile
+++ b/containers/xos/Makefile
@@ -1,30 +1,63 @@
-CONTAINER_NAME:=xos-server
-IMAGE_NAME:=xosproject/xos
-TOSCA_CONFIG_PATH:=/opt/xos/configurations/opencloud/opencloud.yaml
-XOS_GIT_REPO?=git://github.com/open-cloud/xos.git
-XOS_GIT_BRANCH?=master
-NO_DOCKER_CACHE?=false
+# Docker container Makefile for XOS
+#
+# Targets:
+#
+#  `base`   - XOS prerequistie files, no XOS code, builds xosproject/xos-base
+#  `build`  - base + XOS code, git pulled in Dockerfile from main repo,
+#             builds xosproject/xos
+#  `custom` - base + XOS code, git pulled in Dockerfile from selectable repo,
+#             builds xosproject/xos
+#  `devel`  - base + XOS code from local directory, builds xosproject/xos
+#  `test`   - xosproject/xos + nodejs testing frameworks, builds
+#             xosproject/xos-test
+#
 
-.PHONY: build
-build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+NO_DOCKER_CACHE    ?= false
 
-.PHONY: custom
-custom: ; cat Dockerfile.templ | sed -e "s|XOS_GIT_REPO|${XOS_GIT_REPO}|g" -e "s|XOS_GIT_BRANCH|${XOS_GIT_BRANCH}|g" | docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} -
+CONTAINER_NAME     ?= xos-server
+IMAGE_NAME         ?= xosproject/xos
 
-.PHONY: devel
-devel: ; cd ../..; ls; sudo docker build -f containers/xos/Dockerfile.devel --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+XOS_GIT_REPO       ?= git://github.com/open-cloud/xos.git
+XOS_GIT_BRANCH     ?= master
 
-.PHONY: test
-test: ; cd ../..; ls; sudo docker build -f containers/xos/Dockerfile.test --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+TOSCA_CONFIG_PATH  ?= /opt/xos/configurations/opencloud/opencloud.yaml
 
-.PHONY: run
-run: ; sudo docker run -d --name ${CONTAINER_NAME} -p 80:8000 -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro ${IMAGE_NAME}
+base:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile.base -t xosproject/xos-base .
 
-.PHONY: runtosca
-runtosca: ; sudo docker exec -it ${CONTAINER_NAME} /usr/bin/python /opt/xos/tosca/run.py padmin@vicci.org ${TOSCA_CONFIG_PATH}
+build:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile -t ${IMAGE_NAME} .
 
-.PHONY: stop
-stop: ; sudo docker stop ${CONTAINER_NAME}
+custom:
+	docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	--build-arg XOS_GIT_REPO=${XOS_GIT_REPO} \
+	--build-arg XOS_GIT_BRANCH=${XOS_GIT_BRANCH} \
+	-f Dockerfile -t ${IMAGE_NAME} .
 
-.PHONY: rm
-rm: ; sudo docker rm ${CONTAINER_NAME}
+devel:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile.devel -t ${IMAGE_NAME} ../..
+
+test:
+	sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm \
+	-f Dockerfile.test -t xosproject/xos-test ../..
+
+run:
+	sudo docker run -d --name ${CONTAINER_NAME} -p 80:8000 \
+	${IMAGE_NAME}
+
+runtosca:
+	sudo docker exec -it ${CONTAINER_NAME} \
+  /usr/bin/python /opt/xos/tosca/run.py padmin@vicci.org ${TOSCA_CONFIG_PATH}
+
+stop:
+	sudo docker stop ${CONTAINER_NAME}
+
+rm:
+	sudo docker rm ${CONTAINER_NAME}
+
+rmi:
+	sudo docker rmi `docker images | grep "^<none>" | awk '{print $$3}'`
+
diff --git a/containers/xos/ansible-hosts b/containers/xos/ansible-hosts
new file mode 100644
index 0000000..0dd74f1
--- /dev/null
+++ b/containers/xos/ansible-hosts
@@ -0,0 +1,2 @@
+[localhost]
+127.0.0.1
diff --git a/containers/xos/initdb b/containers/xos/initdb
index 1f5b770..b90a570 100755
--- a/containers/xos/initdb
+++ b/containers/xos/initdb
@@ -12,5 +12,5 @@
 # init db schema
 docker run -it --name=$CONTAINER_NAME $IMAGE_NAME /opt/xos/tools/xos-manage makemigrations
 # run overrides the CMD specifed in the Dockerfile, so we re-set the CMD in the final commit"
-docker commit --change="CMD update-ca-certificates && python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure" $CONTAINER_NAME $IMAGE_NAME
+docker commit --change="CMD python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure" $CONTAINER_NAME $IMAGE_NAME
 docker rm $CONTAINER_NAME
diff --git a/containers/xos/local_certs.crt b/containers/xos/local_certs.crt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/containers/xos/local_certs.crt
diff --git a/containers/xos/nodesource.gpg.key b/containers/xos/nodesource.gpg.key
new file mode 100644
index 0000000..1dc1d10
--- /dev/null
+++ b/containers/xos/nodesource.gpg.key
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+Comment: GPGTools - https://gpgtools.org
+
+mQINBFObJLYBEADkFW8HMjsoYRJQ4nCYC/6Eh0yLWHWfCh+/9ZSIj4w/pOe2V6V+
+W6DHY3kK3a+2bxrax9EqKe7uxkSKf95gfns+I9+R+RJfRpb1qvljURr54y35IZgs
+fMG22Np+TmM2RLgdFCZa18h0+RbH9i0b+ZrB9XPZmLb/h9ou7SowGqQ3wwOtT3Vy
+qmif0A2GCcjFTqWW6TXaY8eZJ9BCEqW3k/0Cjw7K/mSy/utxYiUIvZNKgaG/P8U7
+89QyvxeRxAf93YFAVzMXhoKxu12IuH4VnSwAfb8gQyxKRyiGOUwk0YoBPpqRnMmD
+Dl7SdmY3oQHEJzBelTMjTM8AjbB9mWoPBX5G8t4u47/FZ6PgdfmRg9hsKXhkLJc7
+C1btblOHNgDx19fzASWX+xOjZiKpP6MkEEzq1bilUFul6RDtxkTWsTa5TGixgCB/
+G2fK8I9JL/yQhDc6OGY9mjPOxMb5PgUlT8ox3v8wt25erWj9z30QoEBwfSg4tzLc
+Jq6N/iepQemNfo6Is+TG+JzI6vhXjlsBm/Xmz0ZiFPPObAH/vGCY5I6886vXQ7ft
+qWHYHT8jz/R4tigMGC+tvZ/kcmYBsLCCI5uSEP6JJRQQhHrCvOX0UaytItfsQfLm
+EYRd2F72o1yGh3yvWWfDIBXRmaBuIGXGpajC0JyBGSOWb9UxMNZY/2LJEwARAQAB
+tB9Ob2RlU291cmNlIDxncGdAbm9kZXNvdXJjZS5jb20+iQI4BBMBAgAiBQJTmyS2
+AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAWVaCraFdigHTmD/9OKhUy
+jJ+h8gMRg6ri5EQxOExccSRU0i7UHktecSs0DVC4lZG9AOzBe+Q36cym5Z1di6JQ
+kHl69q3zBdV3KTW+H1pdmnZlebYGz8paG9iQ/wS9gpnSeEyx0Enyi167Bzm0O4A1
+GK0prkLnz/yROHHEfHjsTgMvFwAnf9uaxwWgE1d1RitIWgJpAnp1DZ5O0uVlsPPm
+XAhuBJ32mU8S5BezPTuJJICwBlLYECGb1Y65Cil4OALU7T7sbUqfLCuaRKxuPtcU
+VnJ6/qiyPygvKZWhV6Od0Yxlyed1kftMJyYoL8kPHfeHJ+vIyt0s7cropfiwXoka
+1iJB5nKyt/eqMnPQ9aRpqkm9ABS/r7AauMA/9RALudQRHBdWIzfIg0Mlqb52yyTI
+IgQJHNGNX1T3z1XgZhI+Vi8SLFFSh8x9FeUZC6YJu0VXXj5iz+eZmk/nYjUt4Mtc
+pVsVYIB7oIDIbImODm8ggsgrIzqxOzQVP1zsCGek5U6QFc9GYrQ+Wv3/fG8hfkDn
+xXLww0OGaEQxfodm8cLFZ5b8JaG3+Yxfe7JkNclwvRimvlAjqIiW5OK0vvfHco+Y
+gANhQrlMnTx//IdZssaxvYytSHpPZTYw+qPEjbBJOLpoLrz8ZafN1uekpAqQjffI
+AOqW9SdIzq/kSHgl0bzWbPJPw86XzzftewjKNbkCDQRTmyS2ARAAxSSdQi+WpPQZ
+fOflkx9sYJa0cWzLl2w++FQnZ1Pn5F09D/kPMNh4qOsyvXWlekaV/SseDZtVziHJ
+Km6V8TBG3flmFlC3DWQfNNFwn5+pWSB8WHG4bTA5RyYEEYfpbekMtdoWW/Ro8Kmh
+41nuxZDSuBJhDeFIp0ccnN2Lp1o6XfIeDYPegyEPSSZqrudfqLrSZhStDlJgXjea
+JjW6UP6txPtYaaila9/Hn6vF87AQ5bR2dEWB/xRJzgNwRiax7KSU0xca6xAuf+TD
+xCjZ5pp2JwdCjquXLTmUnbIZ9LGV54UZ/MeiG8yVu6pxbiGnXo4Ekbk6xgi1ewLi
+vGmz4QRfVklV0dba3Zj0fRozfZ22qUHxCfDM7ad0eBXMFmHiN8hg3IUHTO+UdlX/
+aH3gADFAvSVDv0v8t6dGc6XE9Dr7mGEFnQMHO4zhM1HaS2Nh0TiL2tFLttLbfG5o
+QlxCfXX9/nasj3K9qnlEg9G3+4T7lpdPmZRRe1O8cHCI5imVg6cLIiBLPO16e0fK
+yHIgYswLdrJFfaHNYM/SWJxHpX795zn+iCwyvZSlLfH9mlegOeVmj9cyhN/VOmS3
+QRhlYXoA2z7WZTNoC6iAIlyIpMTcZr+ntaGVtFOLS6fwdBqDXjmSQu66mDKwU5Ek
+fNlbyrpzZMyFCDWEYo4AIR/18aGZBYUAEQEAAYkCHwQYAQIACQUCU5sktgIbDAAK
+CRAWVaCraFdigIPQEACcYh8rR19wMZZ/hgYv5so6Y1HcJNARuzmffQKozS/rxqec
+0xM3wceL1AIMuGhlXFeGd0wRv/RVzeZjnTGwhN1DnCDy1I66hUTgehONsfVanuP1
+PZKoL38EAxsMzdYgkYH6T9a4wJH/IPt+uuFTFFy3o8TKMvKaJk98+Jsp2X/QuNxh
+qpcIGaVbtQ1bn7m+k5Qe/fz+bFuUeXPivafLLlGc6KbdgMvSW9EVMO7yBy/2JE15
+ZJgl7lXKLQ31VQPAHT3an5IV2C/ie12eEqZWlnCiHV/wT+zhOkSpWdrheWfBT+ac
+hR4jDH80AS3F8jo3byQATJb3RoCYUCVc3u1ouhNZa5yLgYZ/iZkpk5gKjxHPudFb
+DdWjbGflN9k17VCf4Z9yAb9QMqHzHwIGXrb7ryFcuROMCLLVUp07PrTrRxnO9A/4
+xxECi0l/BzNxeU1gK88hEaNjIfviPR/h6Gq6KOcNKZ8rVFdwFpjbvwHMQBWhrqfu
+G3KaePvbnObKHXpfIKoAM7X2qfO+IFnLGTPyhFTcrl6vZBTMZTfZiC1XDQLuGUnd
+sckuXINIU3DFWzZGr0QrqkuE/jyr7FXeUJj9B7cLo+s/TXo+RaVfi3kOc9BoxIvy
+/qiNGs/TKy2/Ujqp/affmIMoMXSozKmga81JSwkADO1JMgUy6dApXz9kP4EE3g==
+=CLGF
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/views/ngXosLib/bower.json b/views/ngXosLib/bower.json
index 08a02e3..d2c7744 100644
--- a/views/ngXosLib/bower.json
+++ b/views/ngXosLib/bower.json
@@ -21,7 +21,8 @@
     "angular-animate": "1.4.7",
     "lodash": "~4.11.1",
     "angular-chart.js": "~0.10.2",
-    "d3": "~3.5.17"
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
   },
   "devDependencies": {
     "angular-mocks": "1.4.7",
diff --git a/views/ngXosLib/generator-xos/app/templates/bower.json b/views/ngXosLib/generator-xos/app/templates/bower.json
index 9dafc2b..0abca60 100644
--- a/views/ngXosLib/generator-xos/app/templates/bower.json
+++ b/views/ngXosLib/generator-xos/app/templates/bower.json
@@ -27,6 +27,7 @@
     "lodash": "~4.11.1",
     "bootstrap-css": "3.3.6",
     "angular-chart.js": "~0.10.2",
-    "d3": "~3.5.17"
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
   }
 }
diff --git a/views/ngXosLib/gulp/ngXosHelpers.js b/views/ngXosLib/gulp/ngXosHelpers.js
index f29a646..638e665 100644
--- a/views/ngXosLib/gulp/ngXosHelpers.js
+++ b/views/ngXosLib/gulp/ngXosHelpers.js
@@ -85,6 +85,7 @@
       module: {
         glob: [
           options.xosHelperSource + '*.js',
+          options.xosHelperSource + 'services/helpers/**/*.js',
           options.xosHelperSource + 'services/*.js',
           options.xosHelperSource + 'ui_components/**/*.js'
         ],
@@ -115,9 +116,7 @@
   gulp.task('docs', ['makeDocs', 'serveDocs'], function(){
     
     var files = [
-      options.xosHelperSource + '*.js',
-      options.xosHelperSource + 'services/*.js',
-      options.xosHelperSource + 'ui_components/**/*.js'
+      options.xosHelperSource + '**/*.js'
     ];
 
     gulp.watch(files, ['makeDocs']);
diff --git a/views/ngXosLib/gulpfile.js b/views/ngXosLib/gulpfile.js
index e514d7a..e030ad9 100644
--- a/views/ngXosLib/gulpfile.js
+++ b/views/ngXosLib/gulpfile.js
@@ -2,6 +2,7 @@
 
 var gulp = require('gulp');
 var wrench = require('wrench');
+var path = require('path');
 
 var options = {
   ngXosVendor: '../../xos/core/xoslib/static/js/vendor/', //save here the minfied vendor file, this is automatically loaded in the django page
@@ -11,9 +12,9 @@
   docs: './docs'
 };
 
-wrench.readdirSyncRecursive('./gulp')
+wrench.readdirSyncRecursive(path.join(__dirname, './gulp'))
 .map(function(file) {
-  require('./gulp/' + file)(options);
+  require(path.join(__dirname, './gulp/' + file))(options);
 });
 
 gulp.task('default', function () {
diff --git a/views/ngXosLib/package.json b/views/ngXosLib/package.json
index da9d27b..ba25551 100644
--- a/views/ngXosLib/package.json
+++ b/views/ngXosLib/package.json
@@ -12,7 +12,8 @@
     "doc": "gulp docs; cd ./docs",
     "doc:ci": "gulp makeDocs;",
     "build": "gulp vendor && gulp helpers",
-    "dev": "gulp dev"
+    "dev": "gulp dev",
+    "lint": "eslint xosHelpers/"
   },
   "author": "Matteo Scandolo",
   "license": "ISC",
diff --git a/views/ngXosLib/xosHelpers/spec/notification.test.js b/views/ngXosLib/xosHelpers/spec/notification.test.js
new file mode 100644
index 0000000..cbc1e56
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/notification.test.js
@@ -0,0 +1,63 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xosNotification service', () => {
+
+      let service, scope;
+
+      const options = {icon: 'icon', body: 'message'};
+
+      let notificationMock = {
+        requestPermission: () => {
+          return {
+            then: cb => cb('granted')
+          }
+        },
+        permission: 'granted'
+      }
+
+
+      // load the application module
+      beforeEach(module('xos.helpers', ($provide) => {
+        $provide.value('Notification', notificationMock);
+      }));
+
+      // inject the cartService
+      beforeEach(inject(function (_xosNotification_, $rootScope) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _xosNotification_;
+        scope = $rootScope;
+        spyOn(service, 'sendNotification');
+        spyOn(service, 'checkPermission').and.callThrough();
+        spyOn(notificationMock, 'requestPermission').and.callThrough();
+      }));
+
+      it('should exist', () => {
+        expect(service).toBeDefined();
+      });
+
+      describe('when permission are granted', () => {
+        it('should send the notification', () => {
+          service.notify('Test', options);
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+      describe('when permission are not granted', () => {
+        beforeEach(() => {
+          notificationMock.permission = false;
+        });
+
+        it('should request permission', () => {
+          service.notify('Test', options);
+          expect(service.checkPermission).toHaveBeenCalled();
+          scope.$apply(); // this resolve the promise
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
new file mode 100644
index 0000000..a126db5
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
@@ -0,0 +1,335 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+
+    describe('The XosFormHelper service', () => {
+      let service;
+
+      let fields = [
+        'id',
+        'name',
+        'mail',
+        'active',
+        'created'
+      ];
+
+      let modelField = {
+        id: {},
+        name: {},
+        mail: {},
+        active: {},
+        created: {}
+      };
+
+      let model = {
+        id: 1,
+        name: 'test',
+        mail: 'test@onlab.us',
+        active: true,
+        created: '2016-04-18T23:44:16.883181Z',
+        custom: 'MyCustomValue'
+      };
+
+      let customField = {
+        id: {
+          label: 'Id',
+          type: 'number',
+          validators: {
+            required: true
+          },
+          hint: ''
+        },
+        custom: {
+          label: 'Custom Label',
+          type: 'number',
+          validators: {},
+          hint: 'Test Hint'
+        }
+      };
+
+      let formObject = {
+        id: {
+          label: 'Id:',
+          type: 'number',
+          validators: {
+            required: true
+          },
+          hint: ''
+        },
+        name: {
+          label: 'Name:',
+          type: 'text',
+          validators: {},
+          hint: ''
+        },
+        mail: {
+          label: 'Mail:',
+          type: 'email',
+          validators: {},
+          hint: ''
+        },
+        active: {
+          label: 'Active:',
+          type: 'boolean',
+          validators: {},
+          hint: ''
+        },
+        created: {
+          label: 'Created:',
+          type: 'date',
+          validators: {},
+          hint: ''
+        },
+        custom: {
+          label: 'Custom Label:',
+          type: 'number',
+          validators: {},
+          hint: 'Test Hint'
+        }
+      };
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_XosFormHelpers_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _XosFormHelpers_;
+      }));
+
+      describe('the _isEmail method', () => {
+        it('should return true', () => {
+          expect(service._isEmail('test@onlab.us')).toEqual(true);
+        });
+        it('should return false', () => {
+          expect(service._isEmail('testonlab.us')).toEqual(false);
+          expect(service._isEmail('test@onlab')).toEqual(false);
+        });
+      });
+
+      describe('the _getFieldFormat method', () => {
+        it('should return text', () => {
+          expect(service._getFieldFormat('a random text')).toEqual('text');
+          expect(service._getFieldFormat(null)).toEqual('text');
+          expect(service._getFieldFormat('1')).toEqual('text');
+        });
+        it('should return mail', () => {
+          expect(service._getFieldFormat('test@onlab.us')).toEqual('email');
+        });
+        it('should return number', () => {
+          expect(service._getFieldFormat(1)).toEqual('number');
+        });
+        it('should return boolean', () => {
+          expect(service._getFieldFormat(false)).toEqual('boolean');
+          expect(service._getFieldFormat(true)).toEqual('boolean');
+        });
+
+        it('should return date', () => {
+          expect(service._getFieldFormat('2016-04-19T23:09:1092Z')).toEqual('text');
+          expect(service._getFieldFormat(new Date())).toEqual('date');
+          expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
+        });
+
+        it('should return array', () => {
+          expect(service._getFieldFormat([])).toEqual('array');
+          expect(service._getFieldFormat(['a', 'b'])).toEqual('array');
+        });
+
+        it('should return object', () => {
+          expect(service._getFieldFormat({})).toEqual('object');
+          expect(service._getFieldFormat({foo: 'bar'})).toEqual('object');
+        });
+      });
+
+      describe('the parseModelField mehtod', () => {
+        it('should convert the fields array in an empty form object', () => {
+          expect(service.parseModelField(fields)).toEqual(modelField);
+        });
+
+        xit('should handle nested config', () => {
+          
+        });
+      });
+
+      describe('when modelField are provided', () => {
+        it('should combine modelField and customField in a form object', () => {
+          const form = service.buildFormStructure(modelField, customField, model);
+          expect(form).toEqual(formObject);
+        });
+
+        it('should override modelField properties whith customField properties', () => {
+          const customFieldOverride = {
+            id: {
+              hint: 'something',
+              type: 'select',
+              options: [
+                {id: 1, label: 'one'},
+                {id: 2, label: 'two'}
+              ],
+              validators: {
+                required: true
+              }
+            }
+          };
+          const form = service.buildFormStructure({id: {}}, customFieldOverride, model);
+          
+          expect(form).toEqual({
+            id: {
+              label: 'Id:',
+              validators: {required: true},
+              hint: customFieldOverride.id.hint,
+              type: customFieldOverride.id.type,
+              options: customFieldOverride.id.options
+            }
+          });
+        });
+      });
+
+      describe('when model field is an empty array', () => {
+        let empty_modelField = {
+          // 5: {}
+        };
+        let empty_customFields = {
+          id: {
+            label: 'Id',
+            type: 'number'
+          },
+          name: {
+            label: 'Name',
+            type: 'text'
+          },
+          mail: {
+            label: 'Mail',
+            type: 'email'
+          },
+          active: {
+            label: 'Active',
+            type: 'boolean'
+          },
+          created: {
+            label: 'Created',
+            type: 'date'
+          },
+          custom: {
+            label: 'Custom Label',
+            type: 'number',
+            hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label',
+            type: 'select',
+            hint: 'Select Hint',
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label',
+            type: 'object',
+            hint: 'Object Hint',
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
+          }
+        };
+
+        let empty_formObject = {
+          id: {
+            label: 'Id:',
+            type: 'number',
+            validators: {},
+            hint: ''
+          },
+          name: {
+            label: 'Name:',
+            type: 'text',
+            validators: {},
+            hint: ''
+          },
+          mail: {
+            label: 'Mail:',
+            type: 'email',
+            validators: {},
+            hint: ''
+          },
+          active: {
+            label: 'Active:',
+            type: 'boolean',
+            validators: {},
+            hint: ''
+          },
+          created: {
+            label: 'Created:',
+            type: 'date',
+            validators: {},
+            hint: ''
+          },
+          custom: {
+            label: 'Custom Label:',
+            type: 'number',
+            validators: {},
+            hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label:',
+            type: 'select',
+            hint: 'Select Hint',
+            validators: {},
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label:',
+            type: 'object',
+            hint: 'Object Hint',
+            validators: {},
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
+          }
+        };
+
+        let empty_model = {5: 'Nan'}
+
+        it('should create a form object', () => {
+          let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model);
+          expect(res.id).toEqual(empty_formObject.id);
+          expect(res.name).toEqual(empty_formObject.name);
+          expect(res.mail).toEqual(empty_formObject.mail);
+          expect(res.active).toEqual(empty_formObject.active);
+          expect(res.created).toEqual(empty_formObject.created);
+          expect(res.custom).toEqual(empty_formObject.custom);
+          expect(res.select).toEqual(empty_formObject.select);
+          expect(res.object).toEqual(empty_formObject.object);
+          expect(res).toEqual(empty_formObject);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/user-prefs.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/user-prefs.test.js
new file mode 100644
index 0000000..4c76484
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/user-prefs.test.js
@@ -0,0 +1,113 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+  let service;
+  let cookies = {
+    xosUserPrefs: JSON.stringify({test: true})
+  };
+
+  const cookieMock = {
+    get: (name) => {
+      return cookies[name]
+    },
+    put: (name, value) => {
+      cookies[name] = value
+    }
+  };
+
+  describe('The xos.helper module', function(){
+
+    describe('The XosUserPrefs service', () => {
+
+      // load the application module
+      beforeEach(module('xos.helpers', ($provide) => {
+        $provide.value('$cookies', cookieMock);
+      }));
+
+      // inject the cartService
+      beforeEach(inject(function (_XosUserPrefs_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _XosUserPrefs_;
+        spyOn(cookieMock, 'put').and.callThrough();
+      }));
+
+      it('should exists and have methods', () => {
+        expect(service).toBeDefined();
+        expect(service.getAll).toBeDefined();
+        expect(service.setAll).toBeDefined();
+        expect(service.getSynchronizerNotificationStatus).toBeDefined();
+        expect(service.setSynchronizerNotificationStatus).toBeDefined();
+      });
+
+      describe('the getAll method', () => {
+        it('should return all the stored prefs', () => {
+          let prefs = service.getAll();
+          expect(prefs).toEqual(JSON.parse(cookies.xosUserPrefs));
+        });
+      });
+
+      describe('the setAll method', () => {
+        it('should override all preferences', () => {
+          service.setAll({test: true, updated: true});
+          expect(JSON.parse(cookies.xosUserPrefs)).toEqual({test: true, updated: true});
+        });
+      });
+
+      describe('the synchronizers status', () => {
+        let syncNotification;
+        beforeEach(() => {
+          syncNotification = {
+            synchronizers: {
+              notification: {
+                first: true,
+                second: false
+              }
+            }
+          }
+          cookies.xosUserPrefs = JSON.stringify(syncNotification);
+        });
+
+        describe('the getSynchronizerNotificationStatus method', () => {
+          it('should return notification status for all synchronizers', () => {
+            expect(service.getSynchronizerNotificationStatus()).toEqual(syncNotification.synchronizers.notification);
+          });
+
+          it('should return notification status for a single synchronizers', () => {
+            expect(service.getSynchronizerNotificationStatus('first')).toEqual(syncNotification.synchronizers.notification.first);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(syncNotification.synchronizers.notification.second);
+          });
+        });
+
+        describe('the setSynchronizerNotificationStatus', () => {
+          
+          it('should throw an error if called without synchronizer name', () => {
+            function wrapper (){
+              service.setSynchronizerNotificationStatus();
+            }
+            expect(wrapper).toThrowError('[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.');
+          });
+
+          it('should update a synchronizer notification status', () => {
+            service.setSynchronizerNotificationStatus('second', true);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(true);
+            expect(service.getSynchronizerNotificationStatus('first')).toEqual(true);
+
+            // should persist the change
+            expect(cookieMock.put).toHaveBeenCalledWith('xosUserPrefs', '{"synchronizers":{"notification":{"first":true,"second":true}}}');
+          });
+
+          it('should handle empty cookies', () => {
+            cookies.xosUserPrefs = '';
+            service.setSynchronizerNotificationStatus('second', true);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(true);
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/field.test.js b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
new file mode 100644
index 0000000..62a41a7
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
@@ -0,0 +1,272 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  let element, scope, isolatedScope, rootScope, compile;
+  const compileElement = (el) => {
+    element = el;
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+    if(!angular.isDefined(element)){
+      element = angular.element('<xos-field name="name" field="field" ng-model="ngModel"></xos-field>');
+    }
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
+  describe('The xos.helper module', function(){
+
+    describe('The xosField component', () => {
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      it('should throw an error if no name is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          scope.ngModel = 1;
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field name'));
+      }));
+
+      it('should throw an error if no field definition is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = 1;
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field definition'));
+      }));
+
+      it('should throw an error if no field type is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = 1;
+          scope.field = {label: 'Label:'}
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a type in the field definition'));
+      }));
+
+      it('should throw an error if no field model is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          compileElement(angular.element('<xos-field name="name" field="field"></xos-field>'));
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide an ng-model'));
+      }));
+
+      describe('when a text input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'text',
+            validators: {}
+          };
+          scope.ngModel = 'label';
+          compileElement();
+        });
+
+        it('should print a text field', () => {
+          expect($(element).find('[name="label"]')).toHaveAttr('type', 'text');
+        });
+      });
+
+
+
+
+      describe('when a option is selected in dropdown', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'select',
+            validators: {},
+            options: [
+              {
+                id: 0,
+                label: '---Site---'
+              },
+              {
+                id: 1,
+                label: '---Site1---'
+              }
+            ]
+          };
+          scope.ngModel = 'label';
+          compileElement();
+        });
+
+        it('No of select elements', () => {
+          expect($(element).find('select').children('option').length).toEqual(3);
+        });
+
+        it('should show a selected value', () => {
+          var elem =  angular.element($(element).find('select').children('option')[1]);
+          expect(elem.text()).toEqual('---Site---');
+        });
+      });
+
+      describe('when a number input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          scope.ngModel = 10;
+          compileElement();
+        });
+
+        it('should print a number field', () => {
+          expect($(element).find('[name="label"]')).toHaveAttr('type', 'number');
+        });
+      });
+
+      describe('when a boolean input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'boolean',
+            validators: {}
+          };
+          scope.ngModel = true;
+          compileElement();
+        });
+
+        let setFalse, setTrue;
+
+        beforeEach(() => {
+          setFalse= $(element).find('.boolean-field > button:first-child');
+          setTrue = $(element).find('.boolean-field > button:last-child');
+        });
+
+        it('should print two buttons', () => {
+          expect($(element).find('.boolean-field > button').length).toEqual(2)
+        });
+
+        it('should change value to false', () => {
+          expect(isolatedScope.ngModel).toEqual(true);
+          setFalse.click()
+          expect(isolatedScope.ngModel).toEqual(false);
+        });
+
+        it('should change value to true', () => {
+          isolatedScope.ngModel = false;
+          scope.$apply();
+          expect(isolatedScope.ngModel).toEqual(false);
+          setTrue.click()
+          expect(isolatedScope.ngModel).toEqual(true);
+        });
+      });
+
+      describe('when an object input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'object',
+            validators: {}
+          };
+          scope.ngModel = {
+            baz: true,
+            foo: 'bar',
+            foz: 1,
+          };
+          compileElement();
+        });
+
+        it('should print a panel to contain object property field', () => {
+          expect($(element).find('.panel.object-field')).toExist()
+        });
+
+        it('should print the right input type for each property', () => {
+          expect($(element).find('input').length).toBe(2);
+          expect($(element).find('.boolean-field > button').length).toEqual(2);
+        });
+
+        it('should format labels', () => {
+          expect($(element).find('input[name="foo"]').parent().find('label').text()).toBe('Foo:');
+        });
+
+        describe('and the model is empty', () => {
+          beforeEach(() => {
+            scope.ngModel = {
+            };
+            compileElement();
+          });
+
+          it('should not print the panel', () => {
+            expect($(element).find('.panel.object-field')).not.toExist()
+          });
+
+          describe('but field is configured', () => {
+            beforeEach(() => {
+              scope.field.properties = {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              };
+              compileElement();
+            });
+            it('should render panel and configured fields', () => {
+              expect($(element).find('.panel.object-field')).toExist();
+              expect($(element).find('input[name="foo"]').parent().find('label').text()).toBe('FooLabel:');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('type', 'string');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('required');
+
+              expect($(element).find('input[name="bar"]').parent().find('label').text()).toBe('Bar:');
+              expect($(element).find('input[name="bar"]')).toHaveAttr('type', 'number');
+
+            });
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/form.test.js b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
index 226a62a..eac10f5 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/form.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
@@ -7,242 +7,53 @@
 (function () {
   'use strict';
 
+  let element, scope, isolatedScope, rootScope, compile;
+
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element(`<xos-form config="config" ng-model="model"></xos-form>`);
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
   describe('The xos.helper module', function(){
 
-    describe('The XosFormHelper service', () => {
-      let service;
-
-      let fields = [
-        'id',
-        'name',
-        'mail',
-        'active',
-        'created',
-        'custom'
-      ];
-
-      let modelField = {
-        id: {},
-        name: {},
-        mail: {},
-        active: {},
-        created: {},
-        custom: {}
-      };
-
-      let model = {
-        id: 1,
-        name: 'test',
-        mail: 'test@onlab.us',
-        active: true,
-        created: '2016-04-18T23:44:16.883181Z',
-        custom: 'MyCustomValue'
-      };
-
-      let customField = {
-        custom: {
-          label: 'Custom Label',
-          type: 'number',
-          validators: {}
-        }
-      };
-
-      let formObject = {
-        id: {
-          label: 'Id:',
-          type: 'number',
-          validators: {}
-        },
-        name: {
-          label: 'Name:',
-          type: 'string',
-          validators: {}
-        },
-        mail: {
-          label: 'Mail:',
-          type: 'email',
-          validators: {}
-        },
-        active: {
-          label: 'Active:',
-          type: 'boolean',
-          validators: {}
-        },
-        created: {
-          label: 'Created:',
-          type: 'date',
-          validators: {}
-        },
-        custom: {
-          label: 'Custom Label:',
-          type: 'number',
-          validators: {}
-        }
-      };
-
-      // load the application module
-      beforeEach(module('xos.helpers'));
-
-      // inject the cartService
-      beforeEach(inject(function (_XosFormHelpers_) {
-        // The injector unwraps the underscores (_) from around the parameter names when matching
-        service = _XosFormHelpers_;
-      }));
-
-      describe('the _isEmail method', () => {
-        it('should return true', () => {
-          expect(service._isEmail('test@onlab.us')).toEqual(true);
-        });
-        it('should return false', () => {
-          expect(service._isEmail('testonlab.us')).toEqual(false);
-          expect(service._isEmail('test@onlab')).toEqual(false);
-        });
-      });
-
-      describe('the _getFieldFormat method', () => {
-        it('should return string', () => {
-          expect(service._getFieldFormat('string')).toEqual('string');
-          expect(service._getFieldFormat(null)).toEqual('string');
-        });
-        it('should return mail', () => {
-          expect(service._getFieldFormat('test@onlab.us')).toEqual('email');
-        });
-        it('should return number', () => {
-          expect(service._getFieldFormat(1)).toEqual('number');
-          // this is skipped because not realistic and js Date sucks
-          // expect(service._getFieldFormat('1')).toEqual('number');
-        });
-        it('should return boolean', () => {
-          expect(service._getFieldFormat(false)).toEqual('boolean');
-          expect(service._getFieldFormat(true)).toEqual('boolean');
-        });
-
-        it('should return date', () => {
-          expect(service._getFieldFormat('2016-04-19T23:09:1092Z')).toEqual('string');
-          expect(service._getFieldFormat(new Date())).toEqual('date');
-          expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
-        });
-      });
-
-      it('should convert the fields array in an empty form object', () => {
-        expect(service.parseModelField(fields)).toEqual(modelField);
-      });
-
-      describe('when modelField are provided', () => {
-        it('should combine modelField and customField in a form object', () => {
-          expect(service.buildFormStructure(modelField, customField, model)).toEqual(formObject);
-        });
-      });
-
-      describe('when model field is an empty array', () => {
-        let empty_modelField = {
-          // 5: {}
-        };
-        let empty_customFields = {
-          id: {
-            label: 'Id',
-            type: 'number'
-          },
-          name: {
-            label: 'Name',
-            type: 'string'
-          },
-          mail: {
-            label: 'Mail',
-            type: 'email'
-          },
-          active: {
-            label: 'Active',
-            type: 'boolean'
-          },
-          created: {
-            label: 'Created',
-            type: 'date'
-          },
-          custom: {
-            label: 'Custom Label',
-            type: 'number'
-          }
-        };
-
-        let empty_formObject = {
-          id: {
-            label: 'Id:',
-            type: 'number',
-            validators: {}
-          },
-          name: {
-            label: 'Name:',
-            type: 'string',
-            validators: {}
-          },
-          mail: {
-            label: 'Mail:',
-            type: 'email',
-            validators: {}
-          },
-          active: {
-            label: 'Active:',
-            type: 'boolean',
-            validators: {}
-          },
-          created: {
-            label: 'Created:',
-            type: 'date',
-            validators: {}
-          },
-          custom: {
-            label: 'Custom Label:',
-            type: 'number',
-            validators: {}
-          }
-        };
-
-        let empty_model = {5: 'Nan'}
-
-        it('should create a form object', () => {
-          let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model)
-          expect(res.id).toEqual(empty_formObject.id);
-          expect(res.name).toEqual(empty_formObject.name);
-          expect(res.mail).toEqual(empty_formObject.mail);
-          expect(res.active).toEqual(empty_formObject.active);
-          expect(res.created).toEqual(empty_formObject.created);
-          expect(res.custom).toEqual(empty_formObject.custom);
-          expect(res).toEqual(empty_formObject);
-        });
-      });
-    });
-
     describe('The xos-form component', () => {
 
-      let element, scope, isolatedScope;
 
       beforeEach(module('xos.helpers'));
 
-      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
-        function errorFunctionWrapper(){
-          $compile(angular.element('<xos-form></xos-form>'))($rootScope);
-          $rootScope.$digest();
-        }
-        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide a configuration via the "config" attribute'));
+      beforeEach(inject(($compile, $rootScope) => {
+        rootScope = $rootScope;
+        compile = $compile;
       }));
 
-      it('should throw an error if no actions is specified', inject(($compile, $rootScope) => {
+      it('should throw an error if no config is specified', () => {
         function errorFunctionWrapper(){
-          let scope = $rootScope.$new();
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide a configuration via the "config" attribute'));
+      });
+
+      it('should throw an error if no actions is specified', () => {
+        function errorFunctionWrapper(){
+          scope = rootScope.$new();
           scope.config = 'green';
-          $compile(angular.element('<xos-form config="config"></xos-form>'))(scope);
-          $rootScope.$digest();
+          compileElement();
         }
         expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide an action list in the configuration'));
-      }));
+      });
 
       describe('when correctly configured', () => {
         
         let cb = jasmine.createSpy('callback');
 
-        beforeEach(inject(($compile, $rootScope) => {
-
+        beforeEach(inject(($rootScope) => {
 
           scope = $rootScope.$new();
 
@@ -274,17 +85,15 @@
             enabled: true,
             role: 'user', //select
             a_permissions: [
-
             ],
-            o_permissions: {
-
+            object_field: {
+              string: 'bar',
+              number: 1,
+              email: 'teo@onlab.us'
             }
           };
 
-          element = angular.element(`<xos-form config="config" ng-model="model"></xos-form>`);
-          $compile(element)(scope);
-          scope.$digest();
-          isolatedScope = element.isolateScope().vm;
+          compileElement();
         }));
 
         it('should add excluded properties to the list', () => {
@@ -292,11 +101,11 @@
           expect(isolatedScope.excludedField).toEqual(expected);
         });
 
-        it('should render 8 input field', () => {
+        it('should render 10 input field', () => {
           // boolean are in the form model, but are not input
           expect(Object.keys(isolatedScope.formField).length).toEqual(9);
           var field = element[0].getElementsByTagName('input');
-          expect(field.length).toEqual(8);
+          expect(field.length).toEqual(10);
         });
 
         it('should render 1 boolean field', () => {
@@ -336,7 +145,7 @@
             expect(isolatedScope.ngModel.enabled).toEqual(false);
           });
 
-          it('should change value to false', () => {
+          it('should change value to true', () => {
             isolatedScope.ngModel.enabled = false;
             scope.$apply();
             expect(isolatedScope.ngModel.enabled).toEqual(false);
@@ -397,6 +206,53 @@
             expect(isolatedScope.testForm.age.$error.min).toBeTruthy();
           });
         });
+
+        describe('when a deep model is passed', () => {
+
+          beforeEach(inject(($rootScope) => {
+
+            scope = $rootScope.$new();
+
+            scope.config = {
+              exclude: ['excludedField'],
+              formName: 'testForm',
+              actions: [
+                {
+                  label: 'Save',
+                  icon: 'ok', // refers to bootstraps glyphicon
+                  cb: cb,
+                  class: 'success'
+                }
+              ],
+              fields: {
+                object_field: {
+                  field_one: {
+                    label: 'Custom Label'
+                  }
+                }
+              }
+            };
+
+            scope.model = {
+              object_field: {
+                field_one: 'bar',
+                number: 1,
+                email: 'teo@onlab.us'
+              }
+            };
+
+            compileElement();
+          }));
+
+          it('should print nested field', () => {
+            expect($(element).find('input').length).toBe(3);
+          });
+
+          xit('should configure nested fields', () => {
+            let custom_label = $(element).find('input[name=field_one]').parent().find('label');
+            expect(custom_label.text()).toBe('Custom Label');
+          });
+        });
       });
     });
   });
diff --git a/views/ngXosLib/xosHelpers/spec/ui/table.test.js b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
index e94eb36..1535c6e 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/table.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
@@ -31,22 +31,22 @@
         rootScope = $rootScope;
       }));
 
-      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+      it('should throw an error if no config is specified', () => {
         function errorFunctionWrapper(){
           compileElement();
         }
         expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a configuration via the "config" attribute'));
-      }));
+      });
 
-      it('should throw an error if no config columns are specified', inject(($compile, $rootScope) => {
+      it('should throw an error if no config columns are specified', () => {
         function errorFunctionWrapper(){
           // setup the parent scope
-          scope = $rootScope.$new();
+          scope = rootScope.$new();
           scope.config = 'green';
           compileElement();
         }
         expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a columns list in the configuration'));
-      }));
+      });
 
       describe('when basicly configured', function() {
 
diff --git a/views/ngXosLib/xosHelpers/spec/ui/validation.test.js b/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
index 782f03f..f8350ed 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
@@ -7,27 +7,45 @@
 (function () {
   'use strict';
 
+  let compile, element, scope;
+
+  const compileElement = (el) => {
+    element = el;
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+    if(!angular.isDefined(element)){
+      element = angular.element('<xos-validation field="field" form="form"></xos-validation>');
+    }
+    compile(element)(scope);
+    scope.$digest();
+  }
+
   describe('The xos.helper module', function(){
     describe('The xos-validation component', () => {
 
-      let element, scope, isolatedScope;
-
       beforeEach(module('xos.helpers'));
 
-      beforeEach(inject(($compile, $rootScope) => {
+      describe('when the form has no errors', () => {
+        beforeEach(inject(($compile, $rootScope) => {
+          compile = $compile;
+          scope = $rootScope.$new();
 
-        scope = $rootScope.$new();
+          scope.field = {
+            $error: {}
+          };
 
-        scope.errors = {};
+          scope.form = {
+            $submitted: true
+          }
 
-        element = angular.element(`<xos-validation errors="errors"></xos-validation>`);
-        $compile(element)(scope);
-        scope.$digest();
-        isolatedScope = element.isolateScope().vm;
-      }));
+          compileElement();
+        }));
 
-      it('should not show an alert', () => {
-        expect($(element).find('xos-alert > .alert')[0]).toHaveClass('ng-hide');
+        it('should not show an alert by default', () => {
+          expect($(element).find('xos-alert > .alert')[0]).toHaveClass('ng-hide');
+        });
       });
 
       let availableErrors = [
@@ -56,8 +74,8 @@
       // use a loop to generate similar test
       availableErrors.forEach((e, i) => {
         it(`should show an alert for ${e.type} errors`, () => {
-          scope.errors[e.type] = true;
-          scope.$digest();
+          scope.field.$error[e.type] = true;
+          compileElement();
           let alert = $(element).find('xos-alert > .alert')[i];
           expect(alert).not.toHaveClass('ng-hide');
           expect(alert).toHaveText(e.message);
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
new file mode 100644
index 0000000..bc6a503
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
@@ -0,0 +1,153 @@
+(function () {
+  
+  angular.module('xos.uiComponents')
+
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.XosFormHelpers
+  * @requires xos.uiComponents.LabelFormatter
+  * @requires xos.helpers._
+  **/
+
+  .service('XosFormHelpers', function(_, LabelFormatter){
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_isEmail
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return true if the string is an email address
+    * @param {string} text The string to be evaluated
+    * @returns {boolean} If the string match an email format
+    **/
+
+
+    this._isEmail = (text) => {
+      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
+      return re.test(text);
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_getFieldFormat
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {mixed} value The data to be evaluated
+    * @returns {string} The type of the input
+    **/
+
+    this._getFieldFormat = (value) => {
+
+      if(angular.isArray(value)){
+        return 'array';
+      }
+
+      // check if is date
+      if (_.isDate(value) || (!Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000)){
+        return 'date';
+      }
+
+      // check if is boolean
+      // isNaN(false) = false, false is a number (0), true is a number (1)
+      if(typeof value  === 'boolean'){
+        return 'boolean';
+      }
+
+      // check if a string is an email
+      if(this._isEmail(value)){
+        return 'email';
+      }
+
+      // if null return string
+      if(typeof value === 'string' || value === null){
+        return 'text';
+      }
+
+      return typeof value;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#buildFormStructure
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {object} modelField An object containing one property for each field of the model
+    * @param {object} customField An object containing one property for each field custom field
+    * @param {object} model The actual model on wich build the form structure (it is used to determine the type of the input)
+    * @returns {object} An object describing the form structure in the form of:
+    * ```
+    * {
+    *   'field-name': {
+    *     label: 'Label',
+    *     type: 'number', //typeof field
+    *     validators: {}, // see xosForm for more details
+    *     hint: 'A Custom hint for the field'
+    *   }
+    * }
+    * ```
+    **/
+
+    this.buildFormStructure = (modelField, customField, model) => {
+
+      modelField = angular.extend(modelField, customField);
+      customField = customField || {};
+
+      return _.reduce(Object.keys(modelField), (form, f) => {
+
+        form[f] = {
+          label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
+          type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
+          validators: (customField[f] && customField[f].validators) ? customField[f].validators : {},
+          hint: (customField[f] && customField[f].hint)? customField[f].hint : '',
+        };
+
+        if(customField[f] && customField[f].options){
+          form[f].options = customField[f].options;
+        }
+        if(customField[f] && customField[f].properties){
+          form[f].properties = customField[f].properties;
+        }
+        if(form[f].type === 'date'){
+          model[f] = new Date(model[f]);
+        }
+
+        if(form[f].type === 'number'){
+          model[f] = parseInt(model[f], 10);
+        }
+
+        return form;
+      }, {});
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#parseModelField
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Helpers for buildFormStructure, convert a list of model properties in an object used to build the form structure, eg:
+    * ```
+    * // input:
+    * ['id', 'name'm 'mail']
+    *
+    * // output
+    * {
+    *   id: {},
+    *   name: {},
+    *   mail: {}
+    * }
+    * ```
+    * @param {array} fields An array of fields representing the model properties
+    * @returns {object} An object containing one property for each field of the model
+    **/
+
+    this.parseModelField = (fields) => {
+      return _.reduce(fields, (form, f) => {
+        form[f] = {};
+        return form;
+      }, {});
+    }
+
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/label_formatter.service.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
similarity index 95%
rename from views/ngXosLib/xosHelpers/src/services/label_formatter.service.js
rename to views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
index 3b63ecd..bb1d279 100644
--- a/views/ngXosLib/xosHelpers/src/services/label_formatter.service.js
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/label_formatter.service.js
@@ -3,7 +3,7 @@
 
   /**
   * @ngdoc service
-  * @name xos.helpers.LabelFormatter
+  * @name xos.uiComponents.LabelFormatter
   * @description This factory define a set of helper function to format label started from an object property
   **/
 
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/user-prefs.service.js b/views/ngXosLib/xosHelpers/src/services/helpers/user-prefs.service.js
new file mode 100644
index 0000000..27edf7f
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/user-prefs.service.js
@@ -0,0 +1,95 @@
+(function () {
+  
+  angular.module('xos.helpers')
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.XosUserPrefs
+  * @description
+  * This service is used to store the user preferences in cookies, so that they survive to page changes.
+  * The structure of the user preference is:
+  * ```
+  * {
+  *   synchronizers: {
+  *     notification: {
+  *       'volt': boolean,
+  *       'openstack': boolean,
+  *       ...
+  *     }
+  *   }
+  * }
+  * ```
+  **/
+
+  .service('XosUserPrefs', function($cookies){
+
+    let userPrefs = $cookies.get('xosUserPrefs') ? JSON.parse($cookies.get('xosUserPrefs')) : {};
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#getAll
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Return all the user preferences stored in cookies
+    * @returns {object} The user preferences
+    **/
+    this.getAll = () => {
+      userPrefs = $cookies.get('xosUserPrefs') ? JSON.parse($cookies.get('xosUserPrefs')) : {};
+      return userPrefs;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#setAll
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Override all user preferences
+    * @param {object} prefs The user preferences
+    **/
+    this.setAll = (prefs) => {
+      $cookies.put('xosUserPrefs', JSON.stringify(prefs));
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#getSynchronizerNotificationStatus
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Return the synchronizer notification status, if name is not provided return the status for all synchronizers
+    * @param {string=} prefs The synchronizer name
+    * @returns {object | string} The synchronizer status
+    **/
+    this.getSynchronizerNotificationStatus = (name = false) => {
+      if(name){
+        return this.getAll().synchronizers.notification[name];
+      }
+      return this.getAll().synchronizers.notification;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.XosUserPrefs#setSynchronizerNotificationStatus
+    * @methodOf xos.helpers.XosUserPrefs
+    * @description
+    * Update the notification status for a single synchronizer
+    * @param {string} name The synchronizer name
+    * @param {boolean} value The notification status (true means that it has been sent)
+    **/
+    this.setSynchronizerNotificationStatus = (name = false, value) => {
+      if(!name){
+        throw new Error('[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.')
+      }
+
+      let cookies = this.getAll();
+
+      if(!cookies.synchronizers){
+        cookies.synchronizers = {
+          notification: {}
+        }
+      }
+
+      cookies.synchronizers.notification[name] = value;
+      this.setAll(cookies);
+    }
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/services/notification.service.js b/views/ngXosLib/xosHelpers/src/services/notification.service.js
new file mode 100644
index 0000000..e190451
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/services/notification.service.js
@@ -0,0 +1,61 @@
+(function() {
+  'use strict';
+
+  angular
+  .module('xos.helpers')
+  .factory('Notification', function(){
+    return window.Notification;
+  })
+  /**
+  * @ngdoc service
+  * @name xos.helpers.xosNotification
+  * @description This factory define a set of helper function to trigger desktop notification
+  **/
+  .service('xosNotification', function($q, $log, Notification) {
+
+    this.checkPermission = () => {
+      const deferred = $q.defer();
+      Notification.requestPermission()
+      .then(permission => {
+        if (permission === 'granted') {
+          deferred.resolve(permission);
+        }
+        else {
+          deferred.reject(permission);
+        }
+      });
+      return deferred.promise;
+    };
+
+    this.sendNotification = (title, options) => {
+      const notification = new Notification(title, options);
+      notification.onerror = function(err){
+        $log.error(err);
+      };
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.xosNotification#notify
+    * @methodOf xos.helpers.xosNotification
+    * @description
+    * This method will check for user permission and if granted will send a browser notification.
+    * @param {string} title The notification title
+    * @param {object} options The notification options: `{icon: 'url', body: 'Notification body'}`
+    **/
+
+    this.notify = (title, options) => {
+      if (!('Notification' in window)) {
+        $log.info('This browser does not support desktop notification');
+      }
+      else if (Notification.permission !== 'granted') {
+        this.checkPermission()
+        .then(() => this.sendNotification(title, options));
+      }
+      else if (Notification.permission === 'granted') {
+        this.sendNotification(title, options);
+      }
+    }
+
+  })
+})();
diff --git a/views/ngXosLib/xosHelpers/src/services/rest/Slices_plus.js b/views/ngXosLib/xosHelpers/src/services/rest/Slices_plus.js
index e744caa..8213b11 100644
--- a/views/ngXosLib/xosHelpers/src/services/rest/Slices_plus.js
+++ b/views/ngXosLib/xosHelpers/src/services/rest/Slices_plus.js
@@ -22,5 +22,19 @@
 
       return {$promise: deferred.promise};
     }
+
+    this.get = (id, params) => {
+      let deferred = $q.defer();
+
+      $http.get(`/api/utility/slicesplus/${id}`, {params: params})
+      .then(res => {
+        deferred.resolve(res.data);
+      })
+      .catch(res => {
+        deferred.reject(res.data);
+      });
+      return {$promise: deferred.promise};
+      
+    }
   })
 })();
diff --git a/views/ngXosLib/xosHelpers/src/styles/main.scss b/views/ngXosLib/xosHelpers/src/styles/main.scss
index 43c54f6..cc02e6f 100644
--- a/views/ngXosLib/xosHelpers/src/styles/main.scss
+++ b/views/ngXosLib/xosHelpers/src/styles/main.scss
@@ -4,6 +4,7 @@
 @import '../ui_components/dumbComponents/table/table.scss';
 @import '../ui_components/dumbComponents/alert/alert.scss';
 @import '../ui_components/dumbComponents/validation/validation.scss';
+@import '../ui_components/dumbComponents/field/field.scss';
 
 @import '../ui_components/smartComponents/smartTable/smartTable.scss';
 
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
new file mode 100644
index 0000000..686dd38
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
@@ -0,0 +1,239 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosField
+    * @restrict E
+    * @description The xos-field directive.
+    * This component decide, give a field wich kind of input it need to print.
+    * @param {string} name The field name
+    * @param {object} field The field configuration:
+    * ```
+    * {
+    *   label: 'Label',
+    *   type: 'number', //typeof field
+    *   validators: {} // see xosForm for more details
+    * }
+    * ```
+    * @param {mixed} ngModel The field value
+    *
+    * @example
+    
+    # Basic Example
+    
+      <example module="sampleField1">
+        <file name="script.js">
+          angular.module('sampleField1', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.name = 'input-name';
+            this.field = {label: 'My String Value:', type: 'string'};
+            this.model = 'my string';
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <xos-field ng-model="vm.model" name="vm.name" field="vm.field"></xos-field>
+          </div>
+        </file>
+      </example>
+      
+      # Possible Values
+
+      <example module="sampleField2">
+        <file name="script.js">
+          angular.module('sampleField2', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.field1 = {
+              name: 'number-field',
+              field: {label: 'My Number Value:', type: 'number'},
+              model: 2
+            };
+
+            this.field2 = {
+              name: 'date-field',
+              field: {label: 'My Date Value:', type: 'date'},
+              model: new Date()
+            };
+
+            this.field3 = {
+              name: 'boolean-field',
+              field: {label: 'My Boolean Value:', type: 'boolean'},
+              model: true
+            };
+
+            this.field4 = {
+              name: 'email-field',
+              field: {label: 'My Email Value:', type: 'email'},
+              model: 'sample@domain.us'
+            };
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <xos-field ng-model="vm.field1.model" name="vm.field1.name" field="vm.field1.field"></xos-field>
+            <xos-field ng-model="vm.field2.model" name="vm.field2.name" field="vm.field2.field"></xos-field>
+            <xos-field ng-model="vm.field3.model" name="vm.field3.name" field="vm.field3.field"></xos-field>
+            <xos-field ng-model="vm.field4.model" name="vm.field4.name" field="vm.field4.field"></xos-field>
+          </div>
+        </file>
+      </example>
+
+      # This element is recursive
+
+      <example module="sampleField3">
+        <file name="script.js">
+          angular.module('sampleField3', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.name1 = 'input-name';
+            this.field1 = {label: 'My Object Field:', type: 'object'};
+            this.model1 = {
+              name: 'Jhon',
+              age: '25',
+              email: 'jhon@thewall.ru',
+              active: true
+            };
+
+            this.name2 = 'another-name';
+            this.field2 = {
+              label: 'Empty Object Field',
+              type: 'object',
+              properties: {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              }
+            }
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <h4>Autogenerated object field</h4>
+            <xos-field ng-model="vm.model1" name="vm.name1" field="vm.field1"></xos-field>
+
+            <h4>Configured object field</h4>
+            <xos-field ng-model="vm.model2" name="vm.name2" field="vm.field2"></xos-field>
+          </div>
+        </file>
+      </example>
+    */
+  .directive('xosField', function(RecursionHelper){
+    return {
+      restrict: 'E',
+      scope: {
+        name: '=',
+        field: '=',
+        ngModel: '='
+      },
+      template: `
+        <label ng-if="vm.field.type !== 'object'">{{vm.field.label}}</label>
+            <input
+              ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object' && vm.field.type !== 'select'"
+              type="{{vm.field.type}}"
+              name="{{vm.name}}"
+              class="form-control"
+              ng-model="vm.ngModel"
+              ng-minlength="vm.field.validators.minlength || 0"
+              ng-maxlength="vm.field.validators.maxlength || 2000"
+              ng-required="vm.field.validators.required || false" />
+              <select class="form-control" ng-if ="vm.field.type === 'select'"
+                name = "{{vm.name}}"
+                ng-options="item.id as item.label for item in vm.field.options track by item.id"
+                ng-model="vm.ngModel"
+                ng-required="vm.field.validators.required || false">
+                </select>
+            <span class="boolean-field" ng-if="vm.field.type === 'boolean'">
+              <button
+                class="btn btn-success"
+                ng-show="vm.ngModel"
+                ng-click="vm.ngModel = false">
+                <i class="glyphicon glyphicon-ok"></i>
+              </button>
+              <button
+                class="btn btn-danger"
+                ng-show="!vm.ngModel"
+                ng-click="vm.ngModel = true">
+                <i class="glyphicon glyphicon-remove"></i>
+              </button>
+            </span>
+            <div
+              class="panel panel-default object-field"
+              ng-if="vm.field.type == 'object' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"
+              >
+              <div class="panel-heading">{{vm.field.label}}</div>
+              <div class="panel-body">
+                <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">
+                  <xos-field
+                    name="k"
+                    field="{label: vm.formatLabel(k), type: vm.getType(v)}"
+                    ng-model="v">
+                  </xos-field>
+                </div>
+                <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">
+                  <xos-field
+                    name="k"
+                    field="{
+                      label: v.label || vm.formatLabel(k),
+                      type: v.type,
+                      validators: v.validators
+                    }"
+                    ng-model="vm.ngModel[k]">
+                  </xos-field>
+                </div>
+              </div>
+            </div>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      // the compile cicle is needed to support recursion
+      compile: function (element) {
+        return RecursionHelper.compile(element);
+      },
+      controller: function($attrs, XosFormHelpers, LabelFormatter){
+
+        if(!this.name){
+          throw new Error('[xosField] Please provide a field name');
+        }
+        if(!this.field){
+          throw new Error('[xosField] Please provide a field definition');
+        }
+        if(!this.field.type){
+          throw new Error('[xosField] Please provide a type in the field definition');
+        }
+        if(!$attrs.ngModel){
+          throw new Error('[xosField] Please provide an ng-model');
+        }
+
+        this.getType = XosFormHelpers._getFieldFormat;
+        this.formatLabel = LabelFormatter.format;
+
+        this.isEmptyObject = o => o ? Object.keys(o).length === 0 : true;
+      }
+    }
+  });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.scss b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.scss
new file mode 100644
index 0000000..8dd7ca4
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.scss
@@ -0,0 +1,3 @@
+xos-field {
+  display: block;
+}
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
index 5294229..2a9f00c 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
@@ -9,6 +9,7 @@
 (function () {
   'use strict';
 
+
   angular.module('xos.uiComponents')
 
   /**
@@ -48,6 +49,9 @@
     * ```
     * @element ANY
     * @scope
+    * @requires xos.uiComponents.directive:xosField
+    * @requires xos.uiComponents.XosFormHelpers
+    * @requires xos.helpers._
     * @example
     
     Autogenerated form
@@ -159,32 +163,8 @@
       template: `
         <ng-form name="vm.{{vm.config.formName || 'form'}}">
           <div class="form-group" ng-repeat="(name, field) in vm.formField">
-            <label>{{field.label}}</label>
-            <input
-              ng-if="field.type !== 'boolean'"
-              type="{{field.type}}"
-              name="{{name}}"
-              class="form-control"
-              ng-model="vm.ngModel[name]"
-              ng-minlength="field.validators.minlength || 0"
-              ng-maxlength="field.validators.maxlength || 2000"
-              ng-required="field.validators.required || false" />
-            <span class="boolean-field" ng-if="field.type === 'boolean'">
-              <button
-                class="btn btn-success"
-                ng-show="vm.ngModel[name]"
-                ng-click="vm.ngModel[name] = false">
-                <i class="glyphicon glyphicon-ok"></i>
-              </button>
-              <button
-                class="btn btn-danger"
-                ng-show="!vm.ngModel[name]"
-                ng-click="vm.ngModel[name] = true">
-                <i class="glyphicon glyphicon-remove"></i>
-              </button>
-            </span>
-            <!-- <pre>{{vm[vm.config.formName][name].$error | json}}</pre> -->
-            <xos-validation errors="vm[vm.config.formName || 'form'][name].$error"></xos-validation>
+            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>
+            <xos-validation field="vm[vm.config.formName || 'form'][name]" form="vm[vm.config.formName || 'form']"></xos-validation>
           </div>
           <div class="form-group" ng-if="vm.config.actions">
             <button role="button" href=""
@@ -233,76 +213,5 @@
 
       }
     }
-  })
-  .service('XosFormHelpers', function(_, LabelFormatter){
-
-    this._isEmail = (text) => {
-      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
-      return re.test(text);
-    };
-
-    this._getFieldFormat = (value) => {
-
-      // check if is date
-      if (_.isDate(value) || (!Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000)){
-        return 'date';
-      }
-
-      // check if is boolean
-      // isNaN(false) = false, false is a number (0), true is a number (1)
-      if(typeof value  === 'boolean'){
-        return 'boolean';
-      }
-
-      // check if a string is a number
-      if(!isNaN(value) && value !== null){
-        return 'number';
-      }
-
-      // check if a string is an email
-      if(this._isEmail(value)){
-        return 'email';
-      }
-
-      // if null return string
-      if(value === null){
-        return 'string';
-      }
-
-      return typeof value;
-    };
-
-    this.buildFormStructure = (modelField, customField, model) => {
-
-      modelField = Object.keys(modelField).length > 0 ? modelField : customField; //if no model field are provided, check custom
-      customField = customField || {};
-
-      return _.reduce(Object.keys(modelField), (form, f) => {
-
-        form[f] = {
-          label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
-          type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
-          validators: (customField[f] && customField[f].validators) ? customField[f].validators : {}
-        };
-
-        if(form[f].type === 'date'){
-          model[f] = new Date(model[f]);
-        }
-
-        if(form[f].type === 'number'){
-          model[f] = parseInt(model[f], 10);
-        }
-
-        return form;
-      }, {});
-    };
-
-    this.parseModelField = (fields) => {
-      return _.reduce(fields, (form, f) => {
-        form[f] = {};
-        return form;
-      }, {});
-    }
-
-  })
+  });
 })();
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
index 84eb91a..91610e1 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
@@ -29,41 +29,44 @@
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.required = !vm.errors.required"
-              ng-class="{'btn-default': !vm.errors.required, 'btn-success': vm.errors.required}">
+              ng-click="vm.field.$error.required = !vm.field.$error.required"
+              ng-class="{'btn-default': !vm.field.$error.required, 'btn-success': vm.field.$error.required}">
               Required
             </a>
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.email = !vm.errors.email"
-              ng-class="{'btn-default': !vm.errors.email, 'btn-success': vm.errors.email}">
+              ng-click="vm.field.$error.email = !vm.field.$error.email"
+              ng-class="{'btn-default': !vm.field.$error.email, 'btn-success': vm.field.$error.email}">
               Email
             </a>
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.minlength = !vm.errors.minlength"
-              ng-class="{'btn-default': !vm.errors.minlength, 'btn-success': vm.errors.minlength}">
+              ng-click="vm.field.$error.minlength = !vm.field.$error.minlength"
+              ng-class="{'btn-default': !vm.field.$error.minlength, 'btn-success': vm.field.$error.minlength}">
               Min Length
             </a>
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.maxlength = !vm.errors.maxlength"
-              ng-class="{'btn-default': !vm.errors.maxlength, 'btn-success': vm.errors.maxlength}">
+              ng-click="vm.field.$error.maxlength = !vm.field.$error.maxlength"
+              ng-class="{'btn-default': !vm.field.$error.maxlength, 'btn-success': vm.field.$error.maxlength}">
               Max Length
             </a>
           </div>
         </div>
-        <xos-validation errors="vm.errors"></xos-validation>
+        <xos-validation field ="vm.field" form = "vm.form"></xos-validation>
       </div>
     </file>
     <file name="script.js">
       angular.module('sampleValidation', ['xos.uiComponents'])
       .controller('SampleCtrl', function(){
-        this.errors = {
-          email: false
+        this.field = {
+          $error: {}
+        };
+        this.form= {
+        $submitted:true
         }
       });
     </file>
@@ -74,24 +77,24 @@
     return {
       restrict: 'E',
       scope: {
-        errors: '='
+        field: '=',
+        form: '='
       },
       template: `
         <div ng-cloak>
-          <!-- <pre>{{vm.errors.email | json}}</pre> -->
-          <xos-alert config="vm.config" show="vm.errors.required !== undefined && vm.errors.required !== false">
+          <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">
             Field required
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.errors.email !== undefined && vm.errors.email !== false">
+          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">
             This is not a valid email
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.errors.minlength !== undefined && vm.errors.minlength !== false">
+          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">
             Too short
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.errors.maxlength !== undefined && vm.errors.maxlength !== false">
+          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">
             Too long
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.errors.custom !== undefined && vm.errors.custom !== false">
+          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">
             Field invalid
           </xos-alert>
         </div>
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
index c1f08fa..f8a3985 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
@@ -198,13 +198,11 @@
         const formatLabels = (data) => angular.isFunction(this.config.labelFormatter) ? this.config.labelFormatter(Object.keys(data)) : Object.keys(data);
 
         const prepareData = (data) => {
-          // $timeout(() => {
-            // group data
-            let grouped = groupData(data);
-            this.data = formatData(grouped);
-            // create labels
-            this.labels = formatLabels(grouped);
-          // }, 10);
+          // group data
+          let grouped = groupData(data);
+          this.data = formatData(grouped);
+          // create labels
+          this.labels = formatLabels(grouped);
         }
 
         if(this.config.resource){
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
index 059f461..27b1ef6 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
@@ -225,7 +225,7 @@
             let props = Object.keys(item);
 
             _.remove(props, p => {
-              return p == 'id' || p == 'validators'
+              return p === 'id' || p === 'validators'
             });
 
             // TODO move out cb,  non sense triggering a lot of times
@@ -249,6 +249,7 @@
             });
 
             // build form structure
+            // TODO move in a pure function for testing purposes
             props.forEach((p, i) => {
               this.formConfig.fields[p] = {
                 label: LabelFormatter.format(labels[i]).replace(':', ''),
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js b/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
index ad3dc49..d94e59d 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/ui-components.module.js
@@ -24,6 +24,7 @@
   **/
 
   angular.module('xos.uiComponents', [
-    'chart.js'
+    'chart.js',
+    'RecursionHelper'
   ])
 })();
diff --git a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
index b74ddf9..fe246a6 100644
--- a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
+++ b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
@@ -24,9 +24,16 @@
         'ngResource',
         'ngAnimate',
         'bugSnag',
-        'xos.uiComponents',
+        'xos.uiComponents'
       ])
       .config(config)
+
+      /**
+      * @ngdoc service
+      * @name xos.helpers._
+      * @description Wrap [lodash](https://lodash.com/docs) in an Angular Service
+      **/
+
       .factory('_', $window => $window._ );
 
   function config($httpProvider, $interpolateProvider, $resourceProvider) {
diff --git a/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json b/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
index e2409a7..9f5919a 100644
--- a/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
+++ b/views/ngXosViews/diagnostic/mocks/data/cordsubscriber.json
@@ -3,7 +3,6 @@
           "humanReadableName": "cordSubscriber-1", 
           "id": 1, 
           "service_specific_id": "123", 
-          "vlan_id": "432", 
           "s_tag": "222", 
           "c_tag": "432", 
           "vcpe_id": 4, 
diff --git a/views/ngXosViews/subscribers/bower.json b/views/ngXosViews/subscribers/bower.json
index f64b705..2fb2dab 100644
--- a/views/ngXosViews/subscribers/bower.json
+++ b/views/ngXosViews/subscribers/bower.json
@@ -14,8 +14,7 @@
     "test",
     "tests"
   ],
-  "dependencies": {
-  },
+  "dependencies": {},
   "devDependencies": {
     "jquery": "2.1.4",
     "angular-mocks": "1.4.7",
@@ -27,6 +26,7 @@
     "lodash": "~4.11.1",
     "bootstrap-css": "3.3.6",
     "angular-chart.js": "~0.10.2",
-    "d3": "~3.5.17"
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
   }
 }
diff --git a/views/ngXosViews/subscribers/karma.conf.js b/views/ngXosViews/subscribers/karma.conf.js
index 4123be9..0e9c4d8 100644
--- a/views/ngXosViews/subscribers/karma.conf.js
+++ b/views/ngXosViews/subscribers/karma.conf.js
@@ -26,6 +26,7 @@
 
     // list of files / patterns to load in the browser
     files: bowerComponents.concat([
+      'node_modules/babel-polyfill/dist/polyfill.js',
       '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
       '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
       'src/js/**/*.js',
@@ -78,7 +79,10 @@
 
     // start these browsers
     // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
-    browsers: ['PhantomJS'],
+    browsers: [
+      'PhantomJS',
+      'Chrome'
+    ],
 
 
     // Continuous Integration mode
diff --git a/views/ngXosViews/subscribers/package.json b/views/ngXosViews/subscribers/package.json
index 3d5def5..96a2326 100644
--- a/views/ngXosViews/subscribers/package.json
+++ b/views/ngXosViews/subscribers/package.json
@@ -21,6 +21,7 @@
   "dependencies": {},
   "devDependencies": {
     "autoprefixer": "^6.3.3",
+    "babel-polyfill": "^6.9.0",
     "browser-sync": "^2.9.11",
     "css-mqpacker": "^4.0.0",
     "csswring": "^4.2.1",
@@ -48,6 +49,7 @@
     "jasmine-core": "~2.3.4",
     "karma": "^0.13.14",
     "karma-babel-preprocessor": "~5.2.2",
+    "karma-chrome-launcher": "^1.0.1",
     "karma-coverage": "^0.5.3",
     "karma-jasmine": "~0.3.6",
     "karma-mocha-reporter": "~1.1.1",
diff --git a/views/ngXosViews/subscribers/spec/sample.test.js b/views/ngXosViews/subscribers/spec/sample.test.js
index 9b06600..1b7796c 100644
--- a/views/ngXosViews/subscribers/spec/sample.test.js
+++ b/views/ngXosViews/subscribers/spec/sample.test.js
@@ -1,7 +1,17 @@
 'use strict';
 
-describe('The User List', () => {
+describe('The Subscriber View', () => {
   
+  const subscribersList = [
+    {
+      humanReadableName: 'cordSubscriber-1',
+      features: {cdn: false, uplink_speed: 1000000000, downlink_speed: 1000000000, uverse: true, status: 'enabled'},
+      id: 1,
+      identity: {account_num: '123', name: 'Stanford'},
+      related: {}
+    }
+  ];
+
   var scope, element, isolatedScope, httpBackend;
 
   beforeEach(module('xos.subscribers'));
@@ -10,28 +20,34 @@
   beforeEach(inject(function($httpBackend, $compile, $rootScope){
     
     httpBackend = $httpBackend;
-    // Setting up mock request
-    $httpBackend.expectGET('/api/core/users/?no_hyperlinks=1').respond([
-      {
-        email: 'matteo.scandolo@gmail.com',
-        firstname: 'Matteo',
-        lastname: 'Scandolo' 
-      }
-    ]);
+    
+    httpBackend.whenGET('/api/tenant/cord/subscriber/?no_hyperlinks=1').respond(subscribersList);
   
     scope = $rootScope.$new();
-    element = angular.element('<users-list></users-list>');
+    element = angular.element('<subscribers-list></subscribers-list>');
     $compile(element)(scope);
     scope.$digest();
     isolatedScope = element.isolateScope().vm;
   }));
 
-  xit('should load 1 users', () => {
+  it('should load 1 subscriber', () => {
+    // this
     httpBackend.flush();
-    expect(isolatedScope.users.length).toBe(1);
-    expect(isolatedScope.users[0].email).toEqual('matteo.scandolo@gmail.com');
-    expect(isolatedScope.users[0].firstname).toEqual('Matteo');
-    expect(isolatedScope.users[0].lastname).toEqual('Scandolo');
+    scope.$digest();
+    let table = $(element).find('table');
+    let tr = table.find('tbody:last-child tr');
+    // let tds = $(tr[1]).find('td');
+    // console.log(tr);
+    expect(tr.length).toBe(1);
+    // expect($(tds[0]).html()).toBe('cordSubscriber-1')
+  });
+
+  it('should configure xos-smart-table', () => {
+    expect(isolatedScope.smartTableConfig).toEqual({resource: 'Subscribers'});
+  });
+
+  it('should render xos-smart-table', () => {
+    expect($(element).find('xos-smart-table').length).toBe(1);
   });
 
 });
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/src/index.html b/views/ngXosViews/subscribers/src/index.html
index 53ed8df..71cbddc 100644
--- a/views/ngXosViews/subscribers/src/index.html
+++ b/views/ngXosViews/subscribers/src/index.html
@@ -26,6 +26,7 @@
 <script src="vendor/Chart.js/Chart.js"></script>
 <script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
 <script src="vendor/d3/d3.js"></script>
+<script src="vendor/angular-recursion/angular-recursion.js"></script>
 <!-- endbower -->
 <!-- endjs -->
 <!-- inject:js -->
diff --git a/views/ngXosViews/subscribers/src/js/main.js b/views/ngXosViews/subscribers/src/js/main.js
index 6665b6d..203e9ff 100644
--- a/views/ngXosViews/subscribers/src/js/main.js
+++ b/views/ngXosViews/subscribers/src/js/main.js
@@ -23,44 +23,11 @@
     bindToController: true,
     controllerAs: 'vm',
     templateUrl: 'templates/subscribers-list.tpl.html',
-    controller: function(Subscribers){
-
-      this.tableConfig = {
-        filter: 'field',
-        order: true,
-        pagination: {
-          pageSize: 10
-        },
-        columns: [
-          {
-            label: 'Name',
-            prop: 'humanReadableName'
-          },
-          {
-            label: 'Identity',
-            prop: 'identity',
-            type: 'object'
-          },
-          {
-            label: 'Related Info',
-            prop: 'related',
-            type: 'object'
-          }
-        ]
-      };
+    controller: function(){
 
       this.smartTableConfig = {
         resource: 'Subscribers'
       };
-      
-      // retrieving user list
-      Subscribers.query().$promise
-      .then((users) => {
-        this.users = users;
-      })
-      .catch((e) => {
-        throw new Error(e);
-      });
     }
   };
 });
\ No newline at end of file
diff --git a/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html b/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
index bd14fd5..d6e755b 100644
--- a/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
+++ b/views/ngXosViews/subscribers/src/templates/subscribers-list.tpl.html
@@ -1,3 +1 @@
-<!-- <xos-table config="vm.tableConfig" data="vm.users"></xos-table> -->
-
 <xos-smart-table config="vm.smartTableConfig"></xos-smart-table>
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/.bowerrc b/views/ngXosViews/synchronizerNotifier/.bowerrc
new file mode 100644
index 0000000..e491038
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "src/vendor/"
+}
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/.eslintrc b/views/ngXosViews/synchronizerNotifier/.eslintrc
new file mode 100644
index 0000000..c852748
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/.eslintrc
@@ -0,0 +1,42 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "node": true,
+        "es6": true
+    },
+    "plugins": [
+        //"angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [1, {"properties": "always"}],
+        "no-underscore-dangle": 1,
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "max-nested-callbacks": [2, 4],
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+
+        //"angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        //"angular/ng_controller_name": [2, '/^[a-z].*Ctrl$/'],
+        //"angular/ng_service_name": [2, '/^[A-Z].*Service$/'],
+        //"angular/ng_directive_name": [2, '/^[a-z]+[[A-Z].*]*$/'],
+        //"angular/ng_di": [0, "function or array"]
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/.gitignore b/views/ngXosViews/synchronizerNotifier/.gitignore
new file mode 100644
index 0000000..567aee4
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/.gitignore
@@ -0,0 +1,6 @@
+dist/
+src/vendor
+.tmp
+node_modules
+npm-debug.log
+dist/
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/bower.json b/views/ngXosViews/synchronizerNotifier/bower.json
new file mode 100644
index 0000000..8b0eb12
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/bower.json
@@ -0,0 +1,32 @@
+{
+  "name": "xos-synchronizerNotifier",
+  "version": "0.0.0",
+  "authors": [
+    "Matteo Scandolo <matteo.scandolo@gmail.com>"
+  ],
+  "description": "The synchronizerNotifier view",
+  "license": "MIT",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "static/js/vendor/",
+    "test",
+    "tests"
+  ],
+  "dependencies": {},
+  "devDependencies": {
+    "jquery": "2.1.4",
+    "angular-mocks": "1.4.7",
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "angular-resource": "1.4.7",
+    "lodash": "~4.11.1",
+    "bootstrap-css": "3.3.6",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
+  }
+}
diff --git a/views/ngXosViews/synchronizerNotifier/gulp/build.js b/views/ngXosViews/synchronizerNotifier/gulp/build.js
new file mode 100644
index 0000000..47cb69c
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/gulp/build.js
@@ -0,0 +1,164 @@
+'use strict';
+
+// BUILD
+//
+// The only purpose of this gulpfile is to build a XOS view and copy the correct files into
+// .html => dashboards
+// .js (minified and concat) => static/js
+//
+// The template are parsed and added to js with angular $templateCache
+
+var gulp = require('gulp');
+var ngAnnotate = require('gulp-ng-annotate');
+var uglify = require('gulp-uglify');
+var templateCache = require('gulp-angular-templatecache');
+var runSequence = require('run-sequence');
+var concat = require('gulp-concat-util');
+var del = require('del');
+var wiredep = require('wiredep');
+var angularFilesort = require('gulp-angular-filesort');
+var _ = require('lodash');
+var eslint = require('gulp-eslint');
+var inject = require('gulp-inject');
+var rename = require('gulp-rename');
+var replace = require('gulp-replace');
+var postcss = require('gulp-postcss');
+var autoprefixer = require('autoprefixer');
+var mqpacker = require('css-mqpacker');
+var csswring = require('csswring');
+
+const TEMPLATE_FOOTER = `
+angular.module('xos.synchronizerNotifier')
+.run(['$location', function(a){
+  a.path('/');
+}])
+`
+
+module.exports = function(options){
+  
+  // delete previous builded file
+  gulp.task('clean', function(){
+    return del(
+      [
+        options.dashboards + 'xosSynchronizerNotifier.html',
+        options.static + 'css/xosSynchronizerNotifier.css'
+      ],
+      {force: true}
+    );
+  });
+
+  // minify css
+  gulp.task('css', function () {
+    var processors = [
+      autoprefixer({browsers: ['last 1 version']}),
+      mqpacker,
+      csswring
+    ];
+
+    gulp.src([
+      `${options.css}**/*.css`,
+      `!${options.css}dev.css`
+    ])
+    .pipe(postcss(processors))
+    .pipe(gulp.dest(options.tmp + '/css/'));
+  });
+
+  // copy css in correct folder
+  gulp.task('copyCss', ['wait'], function(){
+    return gulp.src([`${options.tmp}/css/*.css`])
+    .pipe(concat('xosSynchronizerNotifier.css'))
+    .pipe(gulp.dest(options.static + 'css/'))
+  });
+
+  // compile and minify scripts
+  gulp.task('scripts', function() {
+    return gulp.src([
+      options.tmp + '**/*.js'
+    ])
+    .pipe(ngAnnotate())
+    .pipe(angularFilesort())
+    .pipe(concat('xosSynchronizerNotifier.js'))
+    .pipe(concat.header('//Autogenerated, do not edit!!!\n'))
+    .pipe(concat.footer(TEMPLATE_FOOTER))
+    .pipe(uglify())
+    .pipe(gulp.dest(options.static + 'js/'));
+  });
+
+  // set templates in cache
+  gulp.task('templates', function(){
+    return gulp.src('./src/templates/*.html')
+      .pipe(templateCache({
+        module: 'xos.synchronizerNotifier',
+        root: 'templates/'
+      }))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // copy html index to Django Folder
+  gulp.task('copyHtml', function(){
+    return gulp.src(options.src + 'index.html')
+      // remove dev dependencies from html
+      .pipe(replace(/<!-- bower:css -->(\n^<link.*)*\n<!-- endbower -->/gmi, ''))
+      .pipe(replace(/<!-- bower:js -->(\n^<script.*)*\n<!-- endbower -->/gmi, ''))
+      // injecting minified files
+      .pipe(
+        inject(
+          gulp.src([
+            options.static + 'js/vendor/xosSynchronizerNotifierVendor.js',
+            options.static + 'js/xosSynchronizerNotifier.js',
+            options.static + 'css/xosSynchronizerNotifier.css'
+          ]),
+          {ignorePath: '/../../../xos/core/xoslib'}
+        )
+      )
+      .pipe(rename('xosSynchronizerNotifier.html'))
+      .pipe(gulp.dest(options.dashboards));
+  });
+
+  // minify vendor js files
+  gulp.task('wiredep', function(){
+    var bowerDeps = wiredep().js;
+    if(!bowerDeps){
+      return;
+    }
+
+    // remove angular (it's already loaded)
+    _.remove(bowerDeps, function(dep){
+      return dep.indexOf('angular/angular.js') !== -1;
+    });
+
+    return gulp.src(bowerDeps)
+      .pipe(concat('xosSynchronizerNotifierVendor.js'))
+      .pipe(uglify())
+      .pipe(gulp.dest(options.static + 'js/vendor/'));
+  });
+
+  gulp.task('lint', function () {
+    return gulp.src(['src/js/**/*.js'])
+      .pipe(eslint())
+      .pipe(eslint.format())
+      .pipe(eslint.failAfterError());
+  });
+
+  gulp.task('wait', function (cb) {
+    // setTimeout could be any async task
+    setTimeout(function () {
+      cb();
+    }, 1000);
+  });
+
+  gulp.task('build', function() {
+    runSequence(
+      'clean',
+      'sass',
+      'templates',
+      'babel',
+      'scripts',
+      'wiredep',
+      'css',
+      'copyCss',
+      'copyHtml',
+      'cleanTmp'
+    );
+  });
+};
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/gulp/server.js b/views/ngXosViews/synchronizerNotifier/gulp/server.js
new file mode 100644
index 0000000..1e40a34
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/gulp/server.js
@@ -0,0 +1,170 @@
+'use strict';
+
+var gulp = require('gulp');
+var browserSync = require('browser-sync').create();
+var inject = require('gulp-inject');
+var runSequence = require('run-sequence');
+var angularFilesort = require('gulp-angular-filesort');
+var babel = require('gulp-babel');
+var wiredep = require('wiredep').stream;
+var httpProxy = require('http-proxy');
+var del = require('del');
+var sass = require('gulp-sass');
+var fs = require('fs');
+var path = require('path');
+
+const environment = process.env.NODE_ENV;
+
+if(!fs.existsSync(path.join(__dirname, `../../../env/${environment || 'default'}.js`))){
+  if(!environment){
+    throw new Error('You should define a default.js config in /views/env folder.');
+  }
+  else{
+    throw new Error(`Since you are loading a custom environment, you should define a ${environment}.js config in /views/env folder.`);
+  }
+}
+
+var conf = require(path.join(__dirname, `../../../env/${environment || 'default'}.js`));
+
+var proxy = httpProxy.createProxyServer({
+  target: conf.host
+});
+
+
+proxy.on('error', function(error, req, res) {
+  res.writeHead(500, {
+    'Content-Type': 'text/plain'
+  });
+
+  console.error('[Proxy]', error);
+});
+
+module.exports = function(options){
+
+  gulp.task('browser', function() {
+    browserSync.init({
+      startPath: '#/',
+      snippetOptions: {
+        rule: {
+          match: /<!-- browserSync -->/i
+        }
+      },
+      server: {
+        baseDir: options.src,
+        routes: {
+          '/xos/core/xoslib/static/js/vendor': options.helpers,
+          '/xos/core/static': options.static + '../../static/'
+        },
+        middleware: function(req, res, next){
+          if(
+            req.url.indexOf('/api/') !== -1
+          ){
+            if(conf.xoscsrftoken && conf.xossessionid){
+              req.headers.cookie = `xoscsrftoken=${conf.xoscsrftoken}; xossessionid=${conf.xossessionid}`;
+              req.headers['x-csrftoken'] = conf.xoscsrftoken;
+            }
+            proxy.web(req, res);
+          }
+          else{
+            next();
+          }
+        }
+      }
+    });
+
+    gulp.watch(options.src + 'js/**/*.js', ['js-watch']);
+    gulp.watch(options.src + 'vendor/**/*.js', ['bower'], function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.src + '**/*.html', function(){
+      browserSync.reload();
+    });
+    gulp.watch(options.css + '**/*.css', function(){
+      browserSync.reload();
+    });
+    gulp.watch(`${options.sass}/**/*.scss`, ['sass'], function(){
+      browserSync.reload();
+    });
+
+    gulp.watch([
+      options.helpers + 'ngXosHelpers.js',
+      options.static + '../../static/xosNgLib.css'
+    ], function(){
+      browserSync.reload();
+    });
+  });
+
+  // compile sass
+  gulp.task('sass', function () {
+    return gulp.src(`${options.sass}/**/*.scss`)
+      .pipe(sass().on('error', sass.logError))
+      .pipe(gulp.dest(options.css));
+  });
+
+  // transpile js with sourceMaps
+  gulp.task('babel', function(){
+    return gulp.src(options.scripts + '**/*.js')
+      .pipe(babel({sourceMaps: true}))
+      .pipe(gulp.dest(options.tmp));
+  });
+
+  // inject scripts
+  gulp.task('injectScript', ['cleanTmp', 'babel'], function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.tmp + '**/*.js',
+            options.helpers + 'ngXosHelpers.js'
+          ])
+          .pipe(angularFilesort()),
+          {
+            ignorePath: [options.src, '/../../ngXosLib']
+          }
+        )
+      )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject CSS
+  gulp.task('injectCss', function(){
+    return gulp.src(options.src + 'index.html')
+      .pipe(
+        inject(
+          gulp.src([
+            options.src + 'css/*.css',
+            options.static + '../../static/xosNgLib.css'
+          ]),
+          {
+            ignorePath: [options.src]
+          }
+          )
+        )
+      .pipe(gulp.dest(options.src));
+  });
+
+  // inject bower dependencies with wiredep
+  gulp.task('bower', function () {
+    return gulp.src(options.src + 'index.html')
+    .pipe(wiredep({devDependencies: true}))
+    .pipe(gulp.dest(options.src));
+  });
+
+  gulp.task('js-watch', ['injectScript'], function(){
+    browserSync.reload();
+  });
+
+  gulp.task('cleanTmp', function(){
+    return del([options.tmp + '**/*']);
+  });
+
+  gulp.task('serve', function() {
+    runSequence(
+      'sass',
+      'bower',
+      'injectScript',
+      'injectCss',
+      ['browser']
+    );
+  });
+};
diff --git a/views/ngXosViews/synchronizerNotifier/gulpfile.js b/views/ngXosViews/synchronizerNotifier/gulpfile.js
new file mode 100644
index 0000000..08df554
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/gulpfile.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var gulp = require('gulp');
+var wrench = require('wrench');
+
+var options = {
+  src: 'src/',
+  css: 'src/css/',
+  sass: 'src/sass/',
+  scripts: 'src/js/',
+  tmp: 'src/.tmp',
+  dist: 'dist/',
+  api: '../../ngXosLib/api/',
+  helpers: '../../../xos/core/xoslib/static/js/vendor/',
+  static: '../../../xos/core/xoslib/static/', // this is the django static folder
+  dashboards: '../../../xos/core/xoslib/dashboards/' // this is the django html folder
+};
+
+wrench.readdirSyncRecursive('./gulp')
+.map(function(file) {
+  require('./gulp/' + file)(options);
+});
+
+gulp.task('default', function () {
+  gulp.start('build');
+});
diff --git a/views/ngXosViews/synchronizerNotifier/karma.conf.js b/views/ngXosViews/synchronizerNotifier/karma.conf.js
new file mode 100644
index 0000000..4123be9
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/karma.conf.js
@@ -0,0 +1,88 @@
+// Karma configuration
+// Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+/* eslint indent: [2,2], quotes: [2, "single"]*/
+
+/*eslint-disable*/
+var wiredep = require('wiredep');
+var path = require('path');
+
+var bowerComponents = wiredep( {devDependencies: true} )[ 'js' ].map(function( file ){
+  return path.relative(process.cwd(), file);
+});
+
+module.exports = function(config) {
+/*eslint-enable*/
+  config.set({
+
+    // base path that will be used to resolve all patterns (eg. files, exclude)
+    basePath: '',
+
+
+    // frameworks to use
+    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+    frameworks: ['jasmine'],
+
+
+    // list of files / patterns to load in the browser
+    files: bowerComponents.concat([
+      '../../../xos/core/xoslib/static/js/vendor/ngXosVendor.js',
+      '../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js',
+      'src/js/**/*.js',
+      'spec/**/*.mock.js',
+      'spec/**/*.test.js',
+      'src/**/*.html'
+    ]),
+
+
+    // list of files to exclude
+    exclude: [
+    ],
+
+
+    // preprocess matching files before serving them to the browser
+    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+    preprocessors: {
+      'src/js/**/*.js': ['babel'],
+      'spec/**/*.test.js': ['babel'],
+      'src/**/*.html': ['ng-html2js']
+    },
+
+    ngHtml2JsPreprocessor: {
+      stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      moduleName: 'templates' // define the template module name
+    },
+
+    // test results reporter to use
+    // possible values: 'dots', 'progress'
+    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+    reporters: ['mocha'],
+
+
+    // web server port
+    port: 9876,
+
+
+    // enable / disable colors in the output (reporters and logs)
+    colors: true,
+
+
+    // level of logging
+    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+    logLevel: config.LOG_INFO,
+
+
+    // enable / disable watching file and executing tests whenever any file changes
+    autoWatch: true,
+
+
+    // start these browsers
+    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    browsers: ['PhantomJS'],
+
+
+    // Continuous Integration mode
+    // if true, Karma captures browsers, runs the tests and exits
+    singleRun: false
+  });
+};
diff --git a/views/ngXosViews/synchronizerNotifier/package.json b/views/ngXosViews/synchronizerNotifier/package.json
new file mode 100644
index 0000000..ad76efe
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "xos-synchronizerNotifier",
+  "version": "1.0.0",
+  "description": "Angular Application for XOS, created with generator-xos",
+  "scripts": {
+    "prestart": "npm install && bower install",
+    "start": "gulp serve",
+    "prebuild": "npm install && bower install",
+    "build": "gulp",
+    "test": "karma start",
+    "test:ci": "karma start --single-run",
+    "lint": "eslint src/js/"
+  },
+  "keywords": [
+    "XOS",
+    "Angular",
+    "XOSlib"
+  ],
+  "author": "Matteo Scandolo",
+  "license": "MIT",
+  "dependencies": {},
+  "devDependencies": {
+    "autoprefixer": "^6.3.3",
+    "browser-sync": "^2.9.11",
+    "css-mqpacker": "^4.0.0",
+    "csswring": "^4.2.1",
+    "del": "^2.0.2",
+    "easy-mocker": "^1.2.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-angular-templatecache": "^1.8.0",
+    "gulp-babel": "^5.3.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-concat-util": "^0.5.5",
+    "gulp-eslint": "^1.0.0",
+    "gulp-inject": "^3.0.0",
+    "gulp-minify-html": "^1.0.4",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-postcss": "^6.0.1",
+    "gulp-rename": "^1.2.2",
+    "gulp-replace": "^0.5.4",
+    "gulp-sass": "^2.2.0",
+    "gulp-uglify": "^1.4.2",
+    "http-proxy": "^1.12.0",
+    "ink-docstrap": "^0.5.2",
+    "jasmine-core": "~2.3.4",
+    "karma": "^0.13.14",
+    "karma-babel-preprocessor": "~5.2.2",
+    "karma-coverage": "^0.5.3",
+    "karma-jasmine": "~0.3.6",
+    "karma-mocha-reporter": "~1.1.1",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "~0.2.1",
+    "lodash": "^3.10.1",
+    "phantomjs": "^1.9.19",
+    "proxy-middleware": "^0.15.0",
+    "run-sequence": "^1.1.4",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/views/ngXosViews/synchronizerNotifier/spec/notification.test.js b/views/ngXosViews/synchronizerNotifier/spec/notification.test.js
new file mode 100644
index 0000000..265b7b9
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/spec/notification.test.js
@@ -0,0 +1,76 @@
+'use strict';
+
+describe('The Synchronizer Notification Panel', () => {
+  
+  var scope, element, isolatedScope, XosUserPrefs;
+  const xosNotification = {
+    notify: jasmine.createSpy('notify')
+  };
+
+  const failureEvent = {
+    name: 'test',
+    status: false
+  };
+
+  const successEvent = {
+    name: 'test',
+    status: true
+  };
+
+  beforeEach(module('xos.synchronizerNotifier', ($provide) => {
+    $provide.value('Diag', {
+      start: () => null
+    });
+
+    $provide.value('xosNotification', xosNotification);
+  }));
+  beforeEach(module('templates'));
+
+  beforeEach(inject(function($compile, $rootScope, _XosUserPrefs_){
+
+    XosUserPrefs = _XosUserPrefs_;
+    scope = $rootScope.$new();
+    element = angular.element('<sync-status></sync-status>');
+    $compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }));
+
+  describe('when an event is received', () => {
+
+    beforeEach(() => {
+      xosNotification.notify.calls.reset()
+    });
+
+    describe('and notification have not been sent', () => {
+      
+      beforeEach(() => {
+        XosUserPrefs.setSynchronizerNotificationStatus('test', false);
+        scope.$emit('diag', failureEvent);
+      });
+
+      it('should trigger notification', () => {
+        expect(xosNotification.notify).toHaveBeenCalled();
+      });
+
+      it('should update status in the scope', () => {
+        expect(isolatedScope.synchronizers.test).toEqual(failureEvent);
+        scope.$emit('diag', successEvent);
+        expect(isolatedScope.synchronizers.test).toEqual(successEvent);
+      });
+    });
+
+    describe('and notification have been sent', () => {
+      
+      beforeEach(() => {
+        XosUserPrefs.setSynchronizerNotificationStatus('test', true);
+        scope.$emit('diag', failureEvent);
+      });
+
+      it('should not trigger multiple notification for the same synchronizer', () => {
+        expect(xosNotification.notify).not.toHaveBeenCalled();
+      });
+    });
+  });
+
+});
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/css/main.css b/views/ngXosViews/synchronizerNotifier/src/css/main.css
new file mode 100644
index 0000000..88a08e7
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/css/main.css
@@ -0,0 +1,14 @@
+#xosSynchronizerNotifier {
+  float: left; }
+  #xosSynchronizerNotifier .alert {
+    margin-bottom: 0px !important; }
+  #xosSynchronizerNotifier .sync-status-container {
+    position: relative;
+    z-index: 200; }
+  #xosSynchronizerNotifier .notification-panel {
+    position: absolute;
+    width: 200px; }
+  #xosSynchronizerNotifier sync-status .badge.success {
+    background-color: #5cb85c; }
+  #xosSynchronizerNotifier sync-status .badge.warning {
+    background-color: #f0ad4e; }
diff --git a/views/ngXosViews/synchronizerNotifier/src/index.html b/views/ngXosViews/synchronizerNotifier/src/index.html
new file mode 100644
index 0000000..cb9b7b5
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/index.html
@@ -0,0 +1,35 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.min.css" />
+<link rel="stylesheet" href="vendor/angular-chart.js/dist/angular-chart.css" />
+<!-- endbower -->
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/main.css">
+<link rel="stylesheet" href="/../../../xos/core/static/xosNgLib.css">
+<!-- endinject -->
+
+<div id="xosSynchronizerNotifier">
+  <sync-status></sync-status>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-animate/angular-animate.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/lodash/lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.min.js"></script>
+<script src="vendor/Chart.js/Chart.js"></script>
+<script src="vendor/angular-chart.js/dist/angular-chart.js"></script>
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/angular-recursion/angular-recursion.js"></script>
+<!-- endbower -->
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/ngXosHelpers.js"></script>
+<script src="/.tmp/main.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/js/main.js b/views/ngXosViews/synchronizerNotifier/src/js/main.js
new file mode 100644
index 0000000..f65c4d1
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/js/main.js
@@ -0,0 +1,135 @@
+'use strict';
+
+angular.module('xos.synchronizerNotifier', [
+  'ngResource',
+  'ngCookies',
+  'xos.helpers'
+])
+.run(function($rootScope){
+  $rootScope.$on('$locationChangeStart', function(event) {
+    event.preventDefault();
+  });
+})
+.service('Diag', function($rootScope, $http, $q, $interval){
+
+  let isRunning = false;
+
+  this.getDiags = () => {
+    let d = $q.defer();
+    $http.get('/api/core/diags')
+    .then(res => {
+      d.resolve(res.data);
+    })
+    .catch(err => {
+      d.reject(err);
+    });
+
+    return d.promise;
+  };
+
+  this.sendEvents = (diags) => {
+    diags.forEach(d => {
+      let status = JSON.parse(d.backend_register);
+      status.last_run = new Date(status.last_run * 1000);
+      status.last_duration = status.last_duration * 1000;
+      status.last_synchronizer_start = new Date(status.last_synchronizer_start * 1000);
+      status.last_syncrecord_start = status.last_syncrecord_start ? new Date(status.last_syncrecord_start * 1000) : null;
+      $rootScope.$broadcast(`diag`, {
+        name: d.name,
+        updated: d.updated,
+        info: status,
+        status: this.getSyncStatus(status)
+      });
+    });
+  };
+
+  this.start = () => {
+    isRunning = true;
+    this.getDiags()
+    .then(diags => {
+      this.sendEvents(diags);
+    });
+    return isRunning;
+  };
+
+  this.stop = () => {
+    isRunning = false;
+    return isRunning;
+  };
+
+  this.getSyncStatus = (status) => {
+
+    const now = new Date();
+    const gap = 15 * 60 * 1000; /* ms */
+    // const gap = 1 * 60 * 1000; // for demo use 1 minute
+    // if all of this values are older than 15 min,
+    // probably something is wrong
+    if (
+      (now - status.last_synchronizer_start) > gap &&
+      (now - status.last_syncrecord_start) > gap &&
+      (now - status.last_run) > gap
+    ){
+      return false;
+    }
+    else{
+      return true;
+    }
+  }
+
+  $interval(() => {
+    if(isRunning){
+      this.getDiags()
+      .then(diags => {
+        this.sendEvents(diags);
+      });
+    }
+  }, 5 * 60 * 1000);
+})
+.directive('syncStatus', function() {
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/sync-status.tpl.html',
+    controller: function($log, $rootScope, Diag, xosNotification, XosUserPrefs){
+      Diag.start();
+      // to debug set this to true,
+      // the panel will be opened by default
+      // this.showNotificationPanel = true;
+      this.synchronizers = {};
+
+      this.showNoSync = true;
+
+      $rootScope.$on('diag', (e, d) => {
+        this.synchronizers[d.name] = d;
+
+        // if errored
+        if(!d.status){
+          // and not already notified
+          if(!XosUserPrefs.getSynchronizerNotificationStatus(d.name)){
+            xosNotification.notify('CORD Synchronizer', {
+              icon: '/static/cord-logo.png',
+              body: `The ${d.name} synchronizer has not performed actions in the last 15 minutes.`
+            });
+          }
+          XosUserPrefs.setSynchronizerNotificationStatus(d.name, true);
+        }
+        else {
+          XosUserPrefs.setSynchronizerNotificationStatus(d.name, false);
+        }
+
+        // hide list if empty
+        this.showNoSync = false;
+        if(Object.keys(this.synchronizers).length === 0){
+          this.showNoSync = true;
+        }
+      });
+
+    }
+  }
+});
+
+angular.element(document).ready(function() {
+  angular.bootstrap('#xosSynchronizerNotifier', ['xos.synchronizerNotifier']);
+});
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/sass/main.scss b/views/ngXosViews/synchronizerNotifier/src/sass/main.scss
new file mode 100644
index 0000000..d101d76
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/sass/main.scss
@@ -0,0 +1,32 @@
+@import '../../../../style/sass/lib/_variables.scss';
+
+#xosSynchronizerNotifier {
+  
+  float: left;
+
+  .alert {
+    margin-bottom: 0px !important;
+  }
+
+  .sync-status-container {
+    position: relative;
+    z-index: 200;
+  }
+
+  .notification-panel {
+    position: absolute;
+    width: 200px;
+  }
+
+  sync-status {
+    .badge {
+      &.success {
+        background-color: $brand-success;
+      }
+
+      &.warning {
+        background-color: $brand-warning;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html b/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html
new file mode 100644
index 0000000..cbd794e
--- /dev/null
+++ b/views/ngXosViews/synchronizerNotifier/src/templates/sync-status.tpl.html
@@ -0,0 +1,21 @@
+<div class="sync-status-container">
+  <div class="btn btn-default" ng-click="vm.showNotificationPanel = !vm.showNotificationPanel">
+    <i class="glyphicon glyphicon-inbox"></i>
+  </div>
+  <div class="notification-panel panel panel-default" ng-show="vm.showNotificationPanel">
+    <ul class="list-group" ng-show="!vm.showNoSync">
+      <li class="list-group-item" ng-repeat="(syncName, syncStatus) in vm.synchronizers">
+        <span class="badge" ng-class="{success: syncStatus.status, warning: !syncStatus.status}">
+          <span ng-show="syncStatus.status"><i class="glyphicon glyphicon-ok"></i></span>
+          <span ng-hide="syncStatus.status"><i class="glyphicon glyphicon-time"></i></span>
+        </span>
+        <b>{{syncName}}</b>
+        <br/>
+        <small><i>{{syncStatus.info.last_run | date:'mediumTime'}}</i></small>
+      </li>
+    </ul>
+    <div class="alert alert-info" ng-show="vm.showNoSync">
+      No syncronizers are running.
+    </div>
+  </div>
+</div>
diff --git a/xos/api/tenant/ceilometer/__init__.py b/xos/api/tenant/ceilometer/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/tenant/ceilometer/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/tenant/ceilometer/monitoringchannel.py b/xos/api/tenant/ceilometer/monitoringchannel.py
new file mode 100644
index 0000000..43e1636
--- /dev/null
+++ b/xos/api/tenant/ceilometer/monitoringchannel.py
@@ -0,0 +1,94 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+from services.ceilometer.models import MonitoringChannel, CeilometerService
+
+def get_default_ceilometer_service():
+    ceilometer_services = CeilometerService.get_service_objects().all()
+    if ceilometer_services:
+        return ceilometer_services[0].id
+    return None
+
+class MonitoringChannelForAPI(MonitoringChannel):
+    class Meta:
+        proxy = True
+        app_label = "ceilometer"
+
+    @property
+    def related(self):
+        related = {}
+        if self.creator:
+            related["creator"] = self.creator.username
+        if self.instance:
+            related["instance_id"] = self.instance.id
+            related["instance_name"] = self.instance.name
+            if self.instance.node:
+                related["compute_node_name"] = self.instance.node.name
+        return related
+
+class MonitoringChannelSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        service_specific_attribute = ReadOnlyField()
+        ceilometer_url = ReadOnlyField()
+        tenant_list_str = ReadOnlyField()
+        #creator = ReadOnlyField()
+        #instance = ReadOnlyField()
+        provider_service = serializers.PrimaryKeyRelatedField(queryset=CeilometerService.get_service_objects().all(), default=get_default_ceilometer_service)
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        related = serializers.DictField(required=False)
+
+        #computeNodeName = serializers.SerializerMethodField("getComputeNodeName")
+
+        class Meta:
+            model = MonitoringChannelForAPI
+            fields = ('humanReadableName', 'id', 'provider_service', 'service_specific_attribute', 'ceilometer_url', 'tenant_list_str', 'related' )
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+        #def getComputeNodeName(self, obj):
+        #    instance = obj.instance
+        #    if not instance:
+        #        return None
+        #    return instance.node.name
+
+class MonitoringChannelSet(XOSViewSet):
+    base_name = "monitoringchannel"
+    method_name = "monitoringchannel"
+    method_kind = "viewset"
+    queryset = MonitoringChannelForAPI.get_tenant_objects().all()
+    serializer_class = MonitoringChannelSerializer
+
+    def get_queryset(self):
+        queryset = MonitoringChannelForAPI.get_tenant_objects().all()
+
+        current_user = self.request.user.username
+        if current_user is not None:
+            ids = [x.id for x in queryset if x.creator.username==current_user]
+            queryset = queryset.filter(id__in=ids)
+
+        return queryset
+
+    def create(self, request):
+        current_user = request.user.username
+        existing_obj = None
+        for obj in MonitoringChannelForAPI.get_tenant_objects().all():
+            if (obj.creator.username == current_user):
+               existing_obj = obj
+               break
+
+        if existing_obj:
+            serializer = MonitoringChannelSerializer(existing_obj)
+            headers = self.get_success_headers(serializer.data)
+            return Response( serializer.data, status=status.HTTP_200_OK )
+
+        return super(MonitoringChannelSet, self).create(request)
diff --git a/xos/api/utility/synchronizer.py b/xos/api/utility/synchronizer.py
new file mode 100644
index 0000000..84bae00
--- /dev/null
+++ b/xos/api/utility/synchronizer.py
@@ -0,0 +1,61 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework.exceptions import APIException
+from core.models import *
+from django.forms import widgets
+from core.xoslib.objects.sliceplus import SlicePlus
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+import json
+from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
+from operator import itemgetter, attrgetter
+from api.xosapi_helpers import PlusObjectMixin, PlusModelSerializer
+
+IdField = serializers.ReadOnlyField
+
+
+class SynchronizerSerializer(PlusModelSerializer):
+    id = IdField()
+
+    name = serializers.CharField(required=False)
+
+    class Meta:
+        model = Diag
+        fields = ('id', 'name', 'backend_status', 'backend_register')
+
+
+class SynchronizerList(XOSListCreateAPIView):
+    queryset = Diag.objects.all()
+    serializer_class = SynchronizerSerializer
+
+    method_kind = "list"
+    method_name = "synchronizer"
+
+    def get_queryset(self):
+        name = self.request.query_params.get('name', False)
+
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+        if(name):
+            return Diag.objects.filter(name=name)
+        return Diag.objects.all()
+
+
+class SynchronizerDetail(XOSRetrieveUpdateDestroyAPIView):
+    queryset = Diag.objects.all()
+    serializer_class = SynchronizerSerializer
+
+    method_kind = "detail"
+    method_name = "synchronizer"
+
+    def get_queryset(self):
+        if (not self.request.user.is_authenticated()):
+            raise XOSPermissionDenied("You must be authenticated in order to use this API")
+
+        print "kwargs"
+        print self.request
+        print self.kwargs['pk']
+
+        return Diag.objects.filter(id=self.kwargs['pk'])
diff --git a/xos/configurations/acord/Makefile b/xos/configurations/acord/Makefile
index cfa04f8..e9b234c 100644
--- a/xos/configurations/acord/Makefile
+++ b/xos/configurations/acord/Makefile
@@ -13,9 +13,13 @@
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
 
-acord: cord
+acord: cord exampleservice
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/acord/ceilometer.yaml
 
+exampleservice:
+	#Ensure exampleservice is enabled in xos/tools/xos-manage and xos/settings.py file before uncommenting below lines
+	#sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/acord/acord-exampleservice.yaml
+
 containers:
 	cd ../../../containers/xos; make devel
 	cd ../../../containers/synchronizer; make
diff --git a/xos/configurations/acord/acord-exampleservice.yaml b/xos/configurations/acord/acord-exampleservice.yaml
new file mode 100644
index 0000000..b6b23dd
--- /dev/null
+++ b/xos/configurations/acord/acord-exampleservice.yaml
@@ -0,0 +1,56 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the ExampleService on the ACORD setup
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/exampleservice.yaml
+
+topology_template:
+  node_templates:
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    mysite_exampleservice:
+      description: This slice holds the ExampleService
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - exmapleservice:
+              node: service_example
+              relationship: tosca.relationships.MemberOfService
+          - default_image:
+                node: trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - m1.small:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+
+    service_example:
+      type: tosca.nodes.ExampleService
+      properties:
+          view_url: /admin/exampleservice/exampleservice/$id$/
+          kind: exampleservice
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/exampleservice/exampleservice_private_key
+          service_message: hello
+      artifacts:
+          pubkey: /opt/xos/synchronizers/exampleservice/exampleservice_public_key
+
+    exampletenant1:
+        type: tosca.nodes.ExampleTenant
+        properties:
+            tenant_message: world
+        requirements:
+          - tenant:
+              node: service_example
+              relationship: tosca.relationships.TenantOfService
diff --git a/xos/configurations/acord/ceilometer.yaml b/xos/configurations/acord/ceilometer.yaml
index 66d5d32..089837d 100644
--- a/xos/configurations/acord/ceilometer.yaml
+++ b/xos/configurations/acord/ceilometer.yaml
@@ -122,38 +122,38 @@
       properties:
           view_url: /admin/ceilometer/ceilometerservice/$id$/
           kind: ceilometer
-          ceilometer_pub_sub_url: http://10.11.10.1:4455/
+          ceilometer_pub_sub_url: http://130.127.133.58:4455/
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
       artifacts:
           pubkey: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key
 
-#    service_sflow:
-#      type: tosca.nodes.SFlowService
-#      requirements:
-#      properties:
-#          view_url: /admin/ceilometer/sflowservice/$id$/
-#          kind: sflow
-#          sflow_port: 6343
-#          sflow_api_port: 33333
+    service_sflow:
+      type: tosca.nodes.SFlowService
+      requirements:
+      properties:
+          view_url: /admin/ceilometer/sflowservice/$id$/
+          kind: sflow
+          sflow_port: 6343
+          sflow_api_port: 33333
 
     Private:
       type: tosca.nodes.NetworkTemplate
-
-    ceilometer_network:
-      type: tosca.nodes.network.Network.XOS
-      properties:
-          ip_version: 4
-          labels: ceilometer_client_access
-      requirements:
-          - network_template:
-              node: Private
-              relationship: tosca.relationships.UsesNetworkTemplate
-          - owner:
-              node: mysite_ceilometer
-              relationship: tosca.relationships.MemberOfSlice
-          - connection:
-              node: mysite_ceilometer
-              relationship: tosca.relationships.ConnectsToSlice
+#
+#    ceilometer_network:
+#      type: tosca.nodes.network.Network.XOS
+#      properties:
+#          ip_version: 4
+#          labels: ceilometer_client_access
+#      requirements:
+#          - network_template:
+#              node: Private
+#              relationship: tosca.relationships.UsesNetworkTemplate
+#          - owner:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.MemberOfSlice
+#          - connection:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.ConnectsToSlice
 
     mysite:
       type: tosca.nodes.Site
@@ -186,19 +186,24 @@
       properties:
           max_instances: 2
 
-#    mysite_sflow:
-#      description: Slice for sFlow service
-#      type: tosca.nodes.Slice
-#      requirements:
-#          - sflow_service:
-#              node: service_sflow
-#              relationship: tosca.relationships.MemberOfService
-#          - site:
-#              node: mysite
-#              relationship: tosca.relationships.MemberOfSite
-#      properties:
-#          default_flavor: m1.small
-#          max_instances: 2
+    mysite_sflow:
+      description: Slice for sFlow service
+      type: tosca.nodes.Slice
+      requirements:
+          - sflow_service:
+              node: service_sflow
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - default_image:
+                node: trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - m1.small:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+      properties:
+          max_instances: 2
 
     my_ceilometer_tenant:
       description: Ceilometer Service default Tenant
@@ -209,27 +214,27 @@
               relationship: tosca.relationships.MemberOfService
        
     # Virtual machines
-#    sflow_service_instance:
-#      type: tosca.nodes.Compute
-#      capabilities:
-#        # Host container properties
-#        host:
-#         properties:
-#           num_cpus: 1
-#           disk_size: 10 GB
-#           mem_size: 4 MB
-#        # Guest Operating System properties
-#        os:
-#          properties:
-#            # host Operating System image properties
-#            architecture: x86_64
-#            type: linux
-#            distribution: Ubuntu
-#            version: 14.10
-#      requirements:
-#          - slice:
-#                node: mysite_sflow
-#                relationship: tosca.relationships.MemberOfSlice
+    sflow_service_instance:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_sflow
+                relationship: tosca.relationships.MemberOfSlice
 
     Ceilometer:
       type: tosca.nodes.DashboardView
diff --git a/xos/configurations/acord/ceilometer_pub_sub.tar.gz b/xos/configurations/acord/ceilometer_pub_sub.tar.gz
deleted file mode 100644
index eb88a2b..0000000
--- a/xos/configurations/acord/ceilometer_pub_sub.tar.gz
+++ /dev/null
Binary files differ
diff --git a/xos/configurations/acord/docker-compose.yml b/xos/configurations/acord/docker-compose.yml
index f40761a..da9562e 100644
--- a/xos/configurations/acord/docker-compose.yml
+++ b/xos/configurations/acord/docker-compose.yml
@@ -31,6 +31,19 @@
     volumes:
         - ../setup/id_rsa:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key:ro  # private key
 
+#Ensure exampleservice is enabled in xos/tools/xos-manage and xos/settings.py file before uncommenting below lines
+#xos_synchronizer_exampleservice:
+#    image: xosproject/xos-synchronizer-openstack
+#    command: bash -c "sleep 120; python /opt/xos/synchronizers/exampleservice/exampleservice-synchronizer.py -C /opt/xos/synchronizers/exampleservice/exampleservice_config"
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: exampleservice
+#    links:
+#        - xos_db
+#    volumes:
+#        - ../setup:/root/setup:ro
+#        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+#        - ../setup/id_rsa:/opt/xos/synchronizers/exampleservice/exampleservice_private_key:ro
 
 # FUTURE
 #xos_swarm_synchronizer:
@@ -51,3 +64,4 @@
       - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
       - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
       - ../setup/id_rsa.pub:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:ro
+#      - ../setup/id_rsa.pub:/opt/xos/synchronizers/exampleservice/exampleservice_public_key:ro
diff --git a/xos/configurations/acord/install_ceilometer_patch.sh b/xos/configurations/acord/install_ceilometer_patch.sh
deleted file mode 100755
index 77aa05b..0000000
--- a/xos/configurations/acord/install_ceilometer_patch.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-if [ -d /usr/lib/python2.7/dist-packages/ceilometer/network/ext_services ]; then
-    echo "Seems VCPE notification listeners are already enabled in ceilometer... so exiting gracefully..."
-    exit 0
-fi
-echo "Verifying if all the required files are present"
-if [ ! -f openstack_ceilometer_patch.tar.gz ] || [ ! -f ceilometer_pub_sub.tar.gz ];
-then
-    echo "File openstack_ceilometer_patch.tar.gz or ceilometer_pub_sub.tar.gz not found"
-    exit 1
-fi
-echo "Copying the ceilometer patch files to /usr/lib/python2.7/dist-packages/ceilometer"
-tar -xzf openstack_ceilometer_patch.tar.gz
-sudo mv ceilometer/network/ext_services /usr/lib/python2.7/dist-packages/ceilometer/network/
-sudo mv ceilometer/network/statistics/onos /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/
-sudo mv /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/__init__.py /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/orig_init.orig_py
-sudo mv ceilometer/network/statistics/__init__.py /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/
-sudo mv ceilometer-2015.1.1.egg-info/entry_points.txt /usr/lib/python2.7/dist-packages/ceilometer-*egg-info/
-sudo mv pipeline.yaml /etc/ceilometer/
-echo "Restarting ceilometer-agent-notification"
-sudo service ceilometer-agent-notification restart
-echo "Restarting ceilometer-agent-central"
-sudo service ceilometer-agent-central restart
-tar -xzf ceilometer_pub_sub.tar.gz
-echo "Starting Ceilometer PUB/SUB service"
-cd ceilometer_pub_sub
-python sub_main.py &
diff --git a/xos/configurations/acord/openstack_ceilometer_patch.tar.gz b/xos/configurations/acord/openstack_ceilometer_patch.tar.gz
deleted file mode 100644
index 2c4f02c..0000000
--- a/xos/configurations/acord/openstack_ceilometer_patch.tar.gz
+++ /dev/null
Binary files differ
diff --git a/xos/configurations/common/mydeployment.yaml b/xos/configurations/common/mydeployment.yaml
index 66bb75d..c81fd93 100644
--- a/xos/configurations/common/mydeployment.yaml
+++ b/xos/configurations/common/mydeployment.yaml
@@ -16,9 +16,15 @@
     m1.small:
       type: tosca.nodes.Flavor
 
+    m1.xlarge:
+      type: tosca.nodes.Flavor
+
     MyDeployment:
       type: tosca.nodes.Deployment
       requirements:
+          - m1.xlarge:
+             node: m1.large
+             relationship: tosca.relationships.SupportsFlavor
           - m1.large:
              node: m1.large
              relationship: tosca.relationships.SupportsFlavor
diff --git a/xos/configurations/cord-pod/cord-volt-devices.yaml b/xos/configurations/cord-pod/cord-volt-devices.yaml
new file mode 100644
index 0000000..8b41623
--- /dev/null
+++ b/xos/configurations/cord-pod/cord-volt-devices.yaml
@@ -0,0 +1,47 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Just enough Tosca to get the vSG slice running on the CORD POD
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    service#volt:
+      type: tosca.nodes.VOLTService
+      properties:
+          no-create: True
+          no-delete: True
+          no-update: True
+
+    voltdev-1:
+      type: tosca.nodes.VOLTDevice
+      properties:
+            driver: pmc-olt
+            openflow_id: of:1000000000000001
+            access_devices: >
+              2 222,
+              3 223,
+              4 224
+      requirements:
+          - volt_service:
+              node: service#volt
+              relationship: tosca.relationships.MemberOfService
+          - access_agent:
+              node: agent-1
+              relationship: tosca.relationships.UsesAgent
+
+    agent-1:
+      type: tosca.nodes.AccessAgent
+      properties:
+          mac: AA:BB:CC:DD:EE:FF
+          port_mappings: >
+            of:0000000000000002/2 DE:AD:BE:EF:BA:11,
+            of:0000000000000002/3 BE:EF:DE:AD:BE:EF
+      requirements:
+          - volt_service:
+              node: service#volt
+              relationship: tosca.relationships.MemberOfService
+
+
+
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
index bb603fe..8c73799 100644
--- a/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -16,7 +16,7 @@
           replaces: service_vtr
 
     service#volt:
-      type: tosca.nodes.Service
+      type: tosca.nodes.VOLTService
       requirements:
           - vsg_tenant:
               node: service#vsg
@@ -75,6 +75,50 @@
           view_url: /admin/fabric/fabricservice/$id$/
           replaces: service_fabric
 
+    service#ONOS_Fabric:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          no_container: true
+          rest_hostname: onos-fabric
+          replaces: service_ONOS_Fabric
+
+    service#ONOS_CORD:
+      type: tosca.nodes.ONOSService
+      properties:
+          no-delete: true
+          no-create: true
+          no-update: true
+
+    vOLT_ONOS_app:
+      type: tosca.nodes.ONOSvOLTApp
+      requirements:
+          - onos_tenant:
+              node: service#ONOS_CORD
+              relationship: tosca.relationships.TenantOfService
+          - volt_service:
+              node: service#volt
+              relationship: tosca.relationships.UsedByService
+      properties:
+          install_dependencies: onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+          dependencies: org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher
+          autogenerate: volt-network-cfg
+
+    vRouter_ONOS_app:
+      type: tosca.nodes.ONOSvRouterApp
+      requirements:
+          - onos_tenant:
+              node: service#ONOS_Fabric
+              relationship: tosca.relationships.TenantOfService
+          - vrouter_service:
+              node: service#vrouter
+              relationship: tosca.relationships.UsedByService
+      properties:
+          dependencies: org.onosproject.vrouter
+          autogenerate: vrouter-network-cfg
+
     Private:
       type: tosca.nodes.NetworkTemplate
 
diff --git a/xos/configurations/cord-pod/make-vtn-external-yaml.sh b/xos/configurations/cord-pod/make-vtn-external-yaml.sh
index 8d0885d..a7f04c1 100644
--- a/xos/configurations/cord-pod/make-vtn-external-yaml.sh
+++ b/xos/configurations/cord-pod/make-vtn-external-yaml.sh
@@ -106,4 +106,4 @@
       properties:
           dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn, org.onosproject.olt, org.onosproject.igmp, org.onosproject.cordmcast
           autogenerate: vtn-network-cfg
-EOF
\ No newline at end of file
+EOF
diff --git a/xos/configurations/cord-pod/pod-cdn.yaml b/xos/configurations/cord-pod/pod-cdn.yaml
new file mode 100644
index 0000000..2229686
--- /dev/null
+++ b/xos/configurations/cord-pod/pod-cdn.yaml
@@ -0,0 +1,52 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the CDN on the pod
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    cdn-public:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 207.141.192.128/28
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_cdn
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_cdn
+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_cdn:
+      description: This slice holds the CDN
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
diff --git a/xos/configurations/devel/Makefile b/xos/configurations/devel/Makefile
index e55f38b..524e4cd 100644
--- a/xos/configurations/devel/Makefile
+++ b/xos/configurations/devel/Makefile
@@ -1,8 +1,8 @@
 MYIP:=$(shell hostname -i)
 
-cloudlab: common_cloudlab xos
+cloudlab: common_cloudlab local_containers xos
 
-devstack: upgrade_pkgs common_devstack xos
+devstack: upgrade_pkgs common_devstack local_containers xos
 
 xos:
 	sudo MYIP=$(MYIP) docker-compose up -d
@@ -12,16 +12,25 @@
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
 
-containers:
-	cd ../../../containers/xos; make devel
-	cd ../../../containers/synchronizer; make
-
 common_cloudlab:
 	make -C ../common -f Makefile.cloudlab
 
 common_devstack:
 	make -C ../common -f Makefile.devstack
 
+base:
+	make -C ../../../containers/xos base
+
+local_containers:
+	echo "" > ../../../containers/xos/local_certs.crt
+	for CRT in $$(ls /usr/local/share/ca-certificates/*) ; do \
+		echo Adding Certificate: $$CRT ;\
+		cat $$CRT >> ../../../containers/xos/local_certs.crt ;\
+		echo "" >> ../../../containers/xos/local_certs.crt ;\
+	done
+	make -C ../../../containers/xos devel
+	make -C ../../../containers/synchronizer
+
 stop:
 	sudo MYIP=$(MYIP) docker-compose stop
 
@@ -43,8 +52,3 @@
 upgrade_pkgs:
 	sudo pip install httpie --upgrade
 
-rebuild_xos:
-	make -C ../../../containers/xos devel
-
-rebuild_synchronizer:
-	make -C ../../../containers/synchronizer
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index d6d3df1..46f39bf 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -46,25 +46,25 @@
 django-restart:
 	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
 
+clean-config-folder:
+	sudo docker exec frontend_xos_1 rm -f /opt/xos/xos_configuration/xos_mcord_config
+	sudo docker exec frontend_xos_1 rm -f /opt/xos/xos_configuration/xos_cord_config
+
 mock-cord-pod:
-	echo "make sure to add '../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro' to volumes section of docker-compose.yml"
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/mcord.yaml
-	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/mcord/xos_mcord_config /opt/xos/xos_configuration/
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/mgmt-net.yaml
-	sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
-	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord-pod/xos_cord_config /opt/xos/xos_configuration/
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/mgmt-net.yaml
-	sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
+	#sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-volt-devices.yaml
 	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord-pod/xos_cord_config /opt/xos/xos_configuration/
 	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
 
+
+
 mock-mcord:
 	# check this
-	echo "make sure to add '../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro' to volumes section of docker-compose.yml"
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/mgmt-net.yaml
-	sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/mcord.yaml
 	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/mcord/xos_mcord_config /opt/xos/xos_configuration/
 	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
 
diff --git a/xos/configurations/mcord/Makefile b/xos/configurations/mcord/Makefile
index 7f4d9a5..53fec7b 100644
--- a/xos/configurations/mcord/Makefile
+++ b/xos/configurations/mcord/Makefile
@@ -31,6 +31,9 @@
 enter-vbbu:
 	sudo docker exec -it mcord_xos_synchronizer_vbbu_1 bash
 
+enter-vpgwc:
+	sudo docker exec -it mcord_xos_synchronizer_vpgwc_1 bash
+
 upgrade_pkgs:
 	sudo pip install httpie --upgrade
 
diff --git a/xos/configurations/mcord/docker-compose.yml b/xos/configurations/mcord/docker-compose.yml
index 8598396..367b168 100644
--- a/xos/configurations/mcord/docker-compose.yml
+++ b/xos/configurations/mcord/docker-compose.yml
@@ -40,6 +40,25 @@
         - "compute9:10.102.81.9"
         - "compute10:10.102.81.10"
 
+xos_synchronizer_vpgwc:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vpgwc/vpgwc-synchronizer.py -C /opt/xos/synchronizers/vpgwc/vpgwc_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vpgwc 
+    links:
+        - xos_db
+    volumes:
+        - ../setup/id_rsa_mcord:/opt/xos/configurations/mcord/mcord_private_key:ro  # private key
+        - ../setup/id_rsa_mcord.pub:/opt/xos/configurations/mcord/mcord_public_key:ro  # public key
+        - ../setup:/root/setup:ro
+    extra_hosts:
+        - "controller:10.102.81.3"
+        - "computeBBU1:10.102.81.6"
+        - "computeBBU2:10.102.81.7"
+        - "compute9:10.102.81.9"
+        - "compute10:10.102.81.10"
+
 # FUTURE
 #xos_swarm_synchronizer:
 #    image: xosproject/xos-swarm-synchronizer
diff --git a/xos/configurations/mcord/mcord.yaml b/xos/configurations/mcord/mcord.yaml
index 42241f0..450bd23 100644
--- a/xos/configurations/mcord/mcord.yaml
+++ b/xos/configurations/mcord/mcord.yaml
@@ -92,6 +92,25 @@
                 default: New vBBU Component 

                 description: Just a message 

                 

+    tosca.nodes.VPGWCComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vPGWC Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: VPGWC_KIND

+                description: Kind of component

+            s5s8_pgw_tag:

+                type: string

+                required: false

+                default: 300

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vPGWc Component 

+                description: Just a message 

 

 topology_template:

   node_templates:

@@ -107,6 +126,18 @@
       artifacts:

           pubkey: /opt/xos/configurations/mcord/mcord_public_key

 

+    vPGWC:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: vEPC

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vpgwccomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

     m1.xlarge:

       type: tosca.nodes.Flavor

 

@@ -189,12 +220,35 @@
               node: mysite_vbbu_slice1

               relationship: tosca.relationships.ConnectsToSlice

 

+    lan_3gpp_s5s8_pgw_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s5s8_pgw_net

+          cidr: 172.17.1.0/24

+          start_ip: 172.17.1.2

+          end_ip: 172.17.1.8

+          gateway_ip: 172.17.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

     mysite:

       type: tosca.nodes.Site

 

     mcord-bbu-multi-nic:

       type: tosca.nodes.Image

 

+    mcord-vpgwc-onos-multi-nic:

+      type: tosca.nodes.Image

+

     mysite_management:

       description: This slice exists solely to own the management network

       type: tosca.nodes.Slice

@@ -238,4 +292,41 @@
           network: noauto

 #          default_flavor: m1.xlarge

           default_node: computeBBU2 

-    

+

+    mysite_vpgwc_slice1:

+      description: vPGWC Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vPGWC:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-vpgwc-onos-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - default_flavor:

+                node: m1.xlarge

+                relationship: tosca.relationships.DefaultFlavor

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+          default_node: compute10

+

+    mysite_VPGWC_Component:

+      description: MCORD Service default Component

+      type: tosca.nodes.VPGWCComponent

+      requirements:

+          - provider_service:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - vpgwc_slice:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.MemberOfSlice

+      properties:

+          display_message: vPGWC looks good!

+          s5s8_pgw_tag: 300

+

diff --git a/xos/configurations/mcord/migrations/0001_initial.py b/xos/configurations/mcord/migrations/0001_initial.py
index c53e548..a11fe30 100644
--- a/xos/configurations/mcord/migrations/0001_initial.py
+++ b/xos/configurations/mcord/migrations/0001_initial.py
@@ -31,4 +31,14 @@
             },
             bases=('core.tenantwithcontainer',),
         ),
+        migrations.CreateModel(
+            name='VPGWCComponent',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'VPGWC MCORD Service Component',
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
     ]
diff --git a/xos/configurations/mcord/nodes.yaml b/xos/configurations/mcord/nodes.yaml
index ae22112..48e7247 100644
--- a/xos/configurations/mcord/nodes.yaml
+++ b/xos/configurations/mcord/nodes.yaml
@@ -22,3 +22,23 @@
               node: MyDeployment
               relationship: tosca.relationships.MemberOfDeployment
 
+    nova-compute:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: MyDeployment
+            relationship: tosca.relationships.MemberOfDeployment
+
+    compute10:
+        type: tosca.nodes.Node
+        requirements:
+          - site:
+              node: mysite 
+              relationship: tosca.relationships.MemberOfSite
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.MemberOfDeployment
+
diff --git a/xos/configurations/mcord/setup.yaml b/xos/configurations/mcord/setup.yaml
index 0dd2769..9db865e 100644
--- a/xos/configurations/mcord/setup.yaml
+++ b/xos/configurations/mcord/setup.yaml
@@ -166,12 +166,6 @@
           icon_url: /static/mCordServices/service_server.png
           kind: vEPC
 
-    vPGW:
-      type: tosca.nodes.Service
-      properties:
-          view_url: /mcord/?service=vPGW
-          icon_url: /static/mCordServices/service_server.png
-          kind: vEPC
 
     # EDGE
     Cache:
@@ -223,10 +217,10 @@
           icon_url: /static/mCordServices/service_server.png
           kind: vEPC
 
-    vPGW:
+    vPGWC:
       type: tosca.nodes.Service
       properties:
-          view_url: /mcord/?service=vPGW
+          view_url: /mcord/?service=vPGWC
           icon_url: /static/mCordServices/service_server.png
           kind: vEPC
 
diff --git a/xos/configurations/mcord/vpgwc.yaml b/xos/configurations/mcord/vpgwc.yaml
new file mode 100644
index 0000000..d003bb2
--- /dev/null
+++ b/xos/configurations/mcord/vpgwc.yaml
@@ -0,0 +1,203 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+

+    tosca.nodes.MCORDService:

+        derived_from: tosca.nodes.Root

+        description: >

+            An XOS Service object. Services may be listed in the Service

+            directory and may be linked together via Tenancy Relationships.

+        capabilities:

+            scalable:

+                type: tosca.capabilities.Scalable

+            service:

+                type: tosca.capabilities.xos.Service

+        properties:

+            no-delete:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to delete this object

+            no-create:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to create this object

+            no-update:

+                type: boolean

+                default: false

+                description: Do not allow Tosca to update this object

+            kind:

+                type: string

+                default: VPGWC_KIND

+                description: Type of service.

+            view_url:

+                type: string

+                required: false

+                description: URL to follow when icon is clicked in the Service Directory.

+            icon_url:

+                type: string

+                required: false

+                description: ICON to display in the Service Directory.

+            enabled:

+                type: boolean

+                default: true

+            published:

+                type: boolean

+                default: true

+                description: If True then display this Service in the Service Directory.

+            public_key:

+                type: string

+                required: false

+                description: Public key to install into Instances to allows Services to SSH into them.

+            private_key_fn:

+                type: string

+                required: false

+                description: Location of private key file

+            versionNumber:

+                type: string

+                required: false

+                description: Version number of Service.

+

+    tosca.nodes.VPGWCComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vPGWC Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: VPGWC_KIND 

+                description: Kind of component

+            s5s8_pgw_tag:

+                type: string

+                required: false

+                default: 300

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vPGWC Component 

+                description: Just a message 

+                

+

+topology_template:

+  node_templates:

+    vPGWC:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: VPGWC_KIND

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vpgwccomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

+    m1.xlarge:

+      type: tosca.nodes.Flavor

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    External:

+      type: tosca.nodes.NetworkTemplate

+

+    management_template:

+      type: tosca.nodes.NetworkTemplate

+      properties:

+          visibility: private

+          translation: none

+

+    management:

+      type: tosca.nodes.network.Network.XOS

+#      properties:

+#          no-create: true

+#          no-delete: true

+#          no-update: true

+

+    lan_3gpp_s5s8_pgw_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s5s8_pgw_net

+          cidr: 172.17.1.0/24

+          start_ip: 172.17.1.2

+          end_ip: 172.17.1.8

+          gateway_ip: 172.17.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+    mcord-vpgwc-onos-multi-nic:

+      type: tosca.nodes.Image

+

+    mysite_management:

+      description: This slice exists solely to own the management network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_mobile_net:

+      description: This slice exists solely to own the mobile network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_vpgwc_slice1:

+      description: vPGWC Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vPGWC:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-vpgwc-onos-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - default_flavor:

+                node: m1.xlarge

+                relationship: tosca.relationships.DefaultFlavor

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+          default_node: compute10 

+    

+    mysite_VPGWC_Component:

+      description: MCORD Service default Component

+      type: tosca.nodes.VPGWCComponent

+      requirements:

+          - provider_service:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - vpgwc_slice:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.MemberOfSlice

+      properties:

+          display_message: vPGWC looks good!

+          s5s8_pgw_tag: 300

diff --git a/xos/configurations/test-standalone/Makefile b/xos/configurations/test-standalone/Makefile
index 1542d07..9eafa61 100644
--- a/xos/configurations/test-standalone/Makefile
+++ b/xos/configurations/test-standalone/Makefile
@@ -46,9 +46,12 @@
 	sudo docker-compose run xos bash -c "cd /opt/xos/tosca/tests; python ./alltests.py"
 
 base-container: 
+	cd ../../../containers/xos; make base
+
+devel-container: base-container
 	cd ../../../containers/xos; make devel
 
-containers: base-container
+containers: devel-container
 	cd ../../../containers/xos; make test
 
 stop:
diff --git a/xos/configurations/test-standalone/docker-compose.yml b/xos/configurations/test-standalone/docker-compose.yml
index 5039f08..a0b87ed 100644
--- a/xos/configurations/test-standalone/docker-compose.yml
+++ b/xos/configurations/test-standalone/docker-compose.yml
@@ -11,7 +11,7 @@
 #        org.xosproject.target: swarm
 
 xos:
-    image: xosproject/xos
+    image: xosproject/xos-test
     command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
     #command: sleep 86400    # For interactive session
     ports:
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 477459f..c5e36be 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -2413,6 +2413,15 @@
     def has_add_permission(self, request):
         return False
 
+class DiagAdmin(XOSBaseAdmin):
+    list_display = ("name", "backend_status", "backend_register")
+    list_display_links = ('name',)
+
+    fieldsets = [
+        (None, {'fields': ['name', 'backend_status', 'backend_register'],
+                'classes':['suit-tab suit-tab-general']}),
+    ]
+
 # Now register the new UserAdmin...
 admin.site.register(User, UserAdmin)
 # ... and, since we're not using Django's builtin permissions,
@@ -2458,3 +2467,4 @@
     admin.site.register(TenantRole, TenantRoleAdmin)
     admin.site.register(TenantAttribute, TenantAttributeAdmin)
     admin.site.register(AddressPool, AddressPoolAdmin)
+    admin.site.register(Diag, DiagAdmin)
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
index 6be949d..b84b526 100644
--- a/xos/core/models/plcorebase.py
+++ b/xos/core/models/plcorebase.py
@@ -204,7 +204,7 @@
     policed = models.DateTimeField(null=True, blank=True, default=None)
 
     # This is a scratchpad used by the Observer
-    backend_register = models.CharField(max_length=140,
+    backend_register = models.CharField(max_length=1024,
                                       default="{}", null=True)
 
     backend_status = models.CharField(max_length=1024,
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index e825933..c871c7e 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -610,7 +610,7 @@
         if self.slice.default_image:
             return self.slice.default_image
 
-        raise XOPSProgrammingError("Please set a default image for %s" % self.slice.name)
+        raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
 
     def make_new_instance(self):
         from core.models import Instance, Flavor
@@ -745,7 +745,7 @@
         if slice.default_image:
             return slice.default_image
 
-        raise XOPSProgrammingError("Please set a default image for %s" % self.slice.name)
+        raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
 
     def save_instance(self, instance):
         # Override this function to do custom pre-save or post-save processing,
diff --git a/xos/core/static/xosNgLib.css b/xos/core/static/xosNgLib.css
index 09d218a..35cb6fa 100644
--- a/xos/core/static/xosNgLib.css
+++ b/xos/core/static/xosNgLib.css
@@ -153,6 +153,9 @@
   margin-top: 15px;
   display: block; }
 
+xos-field {
+  display: block; }
+
 [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
   display: none !important; }
 
@@ -160,4 +163,4 @@
   /* TODO move in xos.scss*/
   margin-top: 15px; }
 
-/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieG9zTmdMaWIuY3NzIiwic291cmNlcyI6WyJtYWluLnNjc3MiLCJhbmltYXRpb25zLnNjc3MiLCIuLi8uLi8uLi8uLi9zdHlsZS9zYXNzL2Jvb3RzdHJhcC9ib290c3RyYXAvX3ZhcmlhYmxlcy5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy90YWJsZS90YWJsZS5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9hbGVydC9hbGVydC5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy92YWxpZGF0aW9uL3ZhbGlkYXRpb24uc2NzcyIsIi4uL3VpX2NvbXBvbmVudHMvc21hcnRDb21wb25lbnRzL3NtYXJ0VGFibGUvc21hcnRUYWJsZS5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgJy4vYW5pbWF0aW9ucy5zY3NzJztcbkBpbXBvcnQgJy4uLy4uLy4uLy4uLy4uL3ZpZXdzL3N0eWxlL3Nhc3MvYm9vdHN0cmFwL2Jvb3RzdHJhcC9fdmFyaWFibGVzLnNjc3MnO1xuXG5AaW1wb3J0ICcuLi91aV9jb21wb25lbnRzL2R1bWJDb21wb25lbnRzL3RhYmxlL3RhYmxlLnNjc3MnO1xuQGltcG9ydCAnLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9hbGVydC9hbGVydC5zY3NzJztcbkBpbXBvcnQgJy4uL3VpX2NvbXBvbmVudHMvZHVtYkNvbXBvbmVudHMvdmFsaWRhdGlvbi92YWxpZGF0aW9uLnNjc3MnO1xuXG5AaW1wb3J0ICcuLi91aV9jb21wb25lbnRzL3NtYXJ0Q29tcG9uZW50cy9zbWFydFRhYmxlL3NtYXJ0VGFibGUuc2Nzcyc7XG5cbltuZ1xcOmNsb2FrXSwgW25nLWNsb2FrXSwgW2RhdGEtbmctY2xvYWtdLCBbeC1uZy1jbG9ha10sIC5uZy1jbG9haywgLngtbmctY2xvYWsge1xuICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7XG59XG5cbi5yb3cgKyAucm93IHtcbiAgLyogVE9ETyBtb3ZlIGluIHhvcy5zY3NzKi8gXG4gIG1hcmdpbi10b3A6ICRmb3JtLWdyb3VwLW1hcmdpbi1ib3R0b207XG59IiwiQGtleWZyYW1lcyBzbGlkZUluUmlnaHQge1xuICBmcm9tIHtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZTNkKDEwMCUsIDAsIDApO1xuICAgIHZpc2liaWxpdHk6IHZpc2libGU7XG4gIH1cblxuICB0byB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzZCgwLCAwLCAwKTtcbiAgfVxufVxuXG5Aa2V5ZnJhbWVzIHNsaWRlT3V0UmlnaHQge1xuICBmcm9tIHtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZTNkKDAsIDAsIDApO1xuICB9XG5cbiAgdG8ge1xuICAgIHZpc2liaWxpdHk6IGhpZGRlbjtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZTNkKDEwMCUsIDAsIDApO1xuICB9XG59XG5cbkBrZXlmcmFtZXMgZmFkZUluVXAge1xuICBmcm9tIHtcbiAgICBvcGFjaXR5OiAwO1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMCwgMTAwJSwgMCk7XG4gIH1cblxuICB0byB7XG4gICAgb3BhY2l0eTogMTtcbiAgICB0cmFuc2Zvcm06IG5vbmU7XG4gIH1cbn1cblxuQGtleWZyYW1lcyBmYWRlT3V0RG93biB7XG4gIGZyb20ge1xuICAgIG9wYWNpdHk6IDE7XG4gIH1cblxuICB0byB7XG4gICAgb3BhY2l0eTogMDtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZTNkKDAsIDEwMCUsIDApO1xuICB9XG59IiwiJGJvb3RzdHJhcC1zYXNzLWFzc2V0LWhlbHBlcjogZmFsc2UgIWRlZmF1bHQ7XG4vL1xuLy8gVmFyaWFibGVzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbi8vPT0gQ29sb3JzXG4vL1xuLy8jIyBHcmF5IGFuZCBicmFuZCBjb2xvcnMgZm9yIHVzZSBhY3Jvc3MgQm9vdHN0cmFwLlxuXG4kZ3JheS1iYXNlOiAgICAgICAgICAgICAgIzAwMCAhZGVmYXVsdDtcbiRncmF5LWRhcmtlcjogICAgICAgICAgICBsaWdodGVuKCRncmF5LWJhc2UsIDEzLjUlKSAhZGVmYXVsdDsgLy8gIzIyMlxuJGdyYXktZGFyazogICAgICAgICAgICAgIGxpZ2h0ZW4oJGdyYXktYmFzZSwgMjAlKSAhZGVmYXVsdDsgICAvLyAjMzMzXG4kZ3JheTogICAgICAgICAgICAgICAgICAgbGlnaHRlbigkZ3JheS1iYXNlLCAzMy41JSkgIWRlZmF1bHQ7IC8vICM1NTVcbiRncmF5LWxpZ2h0OiAgICAgICAgICAgICBsaWdodGVuKCRncmF5LWJhc2UsIDQ2LjclKSAhZGVmYXVsdDsgLy8gIzc3N1xuJGdyYXktbGlnaHRlcjogICAgICAgICAgIGxpZ2h0ZW4oJGdyYXktYmFzZSwgOTMuNSUpICFkZWZhdWx0OyAvLyAjZWVlXG5cbiRicmFuZC1wcmltYXJ5OiAgICAgICAgIGRhcmtlbigjNDI4YmNhLCA2LjUlKSAhZGVmYXVsdDsgLy8gIzMzN2FiN1xuJGJyYW5kLXN1Y2Nlc3M6ICAgICAgICAgIzVjYjg1YyAhZGVmYXVsdDtcbiRicmFuZC1pbmZvOiAgICAgICAgICAgICM1YmMwZGUgIWRlZmF1bHQ7XG4kYnJhbmQtd2FybmluZzogICAgICAgICAjZjBhZDRlICFkZWZhdWx0O1xuJGJyYW5kLWRhbmdlcjogICAgICAgICAgI2Q5NTM0ZiAhZGVmYXVsdDtcblxuXG4vLz09IFNjYWZmb2xkaW5nXG4vL1xuLy8jIyBTZXR0aW5ncyBmb3Igc29tZSBvZiB0aGUgbW9zdCBnbG9iYWwgc3R5bGVzLlxuXG4vLyoqIEJhY2tncm91bmQgY29sb3IgZm9yIGA8Ym9keT5gLlxuJGJvZHktYmc6ICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogR2xvYmFsIHRleHQgY29sb3Igb24gYDxib2R5PmAuXG4kdGV4dC1jb2xvcjogICAgICAgICAgICAkZ3JheS1kYXJrICFkZWZhdWx0O1xuXG4vLyoqIEdsb2JhbCB0ZXh0dWFsIGxpbmsgY29sb3IuXG4kbGluay1jb2xvcjogICAgICAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcbi8vKiogTGluayBob3ZlciBjb2xvciBzZXQgdmlhIGBkYXJrZW4oKWAgZnVuY3Rpb24uXG4kbGluay1ob3Zlci1jb2xvcjogICAgICBkYXJrZW4oJGxpbmstY29sb3IsIDE1JSkgIWRlZmF1bHQ7XG4vLyoqIExpbmsgaG92ZXIgZGVjb3JhdGlvbi5cbiRsaW5rLWhvdmVyLWRlY29yYXRpb246IHVuZGVybGluZSAhZGVmYXVsdDtcblxuXG4vLz09IFR5cG9ncmFwaHlcbi8vXG4vLyMjIEZvbnQsIGxpbmUtaGVpZ2h0LCBhbmQgY29sb3IgZm9yIGJvZHkgdGV4dCwgaGVhZGluZ3MsIGFuZCBtb3JlLlxuXG4kZm9udC1mYW1pbHktc2Fucy1zZXJpZjogIFwiSGVsdmV0aWNhIE5ldWVcIiwgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiAhZGVmYXVsdDtcbiRmb250LWZhbWlseS1zZXJpZjogICAgICAgR2VvcmdpYSwgXCJUaW1lcyBOZXcgUm9tYW5cIiwgVGltZXMsIHNlcmlmICFkZWZhdWx0O1xuLy8qKiBEZWZhdWx0IG1vbm9zcGFjZSBmb250cyBmb3IgYDxjb2RlPmAsIGA8a2JkPmAsIGFuZCBgPHByZT5gLlxuJGZvbnQtZmFtaWx5LW1vbm9zcGFjZTogICBNZW5sbywgTW9uYWNvLCBDb25zb2xhcywgXCJDb3VyaWVyIE5ld1wiLCBtb25vc3BhY2UgIWRlZmF1bHQ7XG4kZm9udC1mYW1pbHktYmFzZTogICAgICAgICRmb250LWZhbWlseS1zYW5zLXNlcmlmICFkZWZhdWx0O1xuXG4kZm9udC1zaXplLWJhc2U6ICAgICAgICAgIDE0cHggIWRlZmF1bHQ7XG4kZm9udC1zaXplLWxhcmdlOiAgICAgICAgIGNlaWwoKCRmb250LXNpemUtYmFzZSAqIDEuMjUpKSAhZGVmYXVsdDsgLy8gfjE4cHhcbiRmb250LXNpemUtc21hbGw6ICAgICAgICAgY2VpbCgoJGZvbnQtc2l6ZS1iYXNlICogMC44NSkpICFkZWZhdWx0OyAvLyB+MTJweFxuXG4kZm9udC1zaXplLWgxOiAgICAgICAgICAgIGZsb29yKCgkZm9udC1zaXplLWJhc2UgKiAyLjYpKSAhZGVmYXVsdDsgLy8gfjM2cHhcbiRmb250LXNpemUtaDI6ICAgICAgICAgICAgZmxvb3IoKCRmb250LXNpemUtYmFzZSAqIDIuMTUpKSAhZGVmYXVsdDsgLy8gfjMwcHhcbiRmb250LXNpemUtaDM6ICAgICAgICAgICAgY2VpbCgoJGZvbnQtc2l6ZS1iYXNlICogMS43KSkgIWRlZmF1bHQ7IC8vIH4yNHB4XG4kZm9udC1zaXplLWg0OiAgICAgICAgICAgIGNlaWwoKCRmb250LXNpemUtYmFzZSAqIDEuMjUpKSAhZGVmYXVsdDsgLy8gfjE4cHhcbiRmb250LXNpemUtaDU6ICAgICAgICAgICAgJGZvbnQtc2l6ZS1iYXNlICFkZWZhdWx0O1xuJGZvbnQtc2l6ZS1oNjogICAgICAgICAgICBjZWlsKCgkZm9udC1zaXplLWJhc2UgKiAwLjg1KSkgIWRlZmF1bHQ7IC8vIH4xMnB4XG5cbi8vKiogVW5pdC1sZXNzIGBsaW5lLWhlaWdodGAgZm9yIHVzZSBpbiBjb21wb25lbnRzIGxpa2UgYnV0dG9ucy5cbiRsaW5lLWhlaWdodC1iYXNlOiAgICAgICAgMS40Mjg1NzE0MjkgIWRlZmF1bHQ7IC8vIDIwLzE0XG4vLyoqIENvbXB1dGVkIFwibGluZS1oZWlnaHRcIiAoYGZvbnQtc2l6ZWAgKiBgbGluZS1oZWlnaHRgKSBmb3IgdXNlIHdpdGggYG1hcmdpbmAsIGBwYWRkaW5nYCwgZXRjLlxuJGxpbmUtaGVpZ2h0LWNvbXB1dGVkOiAgICBmbG9vcigoJGZvbnQtc2l6ZS1iYXNlICogJGxpbmUtaGVpZ2h0LWJhc2UpKSAhZGVmYXVsdDsgLy8gfjIwcHhcblxuLy8qKiBCeSBkZWZhdWx0LCB0aGlzIGluaGVyaXRzIGZyb20gdGhlIGA8Ym9keT5gLlxuJGhlYWRpbmdzLWZvbnQtZmFtaWx5OiAgICBpbmhlcml0ICFkZWZhdWx0O1xuJGhlYWRpbmdzLWZvbnQtd2VpZ2h0OiAgICA1MDAgIWRlZmF1bHQ7XG4kaGVhZGluZ3MtbGluZS1oZWlnaHQ6ICAgIDEuMSAhZGVmYXVsdDtcbiRoZWFkaW5ncy1jb2xvcjogICAgICAgICAgaW5oZXJpdCAhZGVmYXVsdDtcblxuXG4vLz09IEljb25vZ3JhcGh5XG4vL1xuLy8jIyBTcGVjaWZ5IGN1c3RvbSBsb2NhdGlvbiBhbmQgZmlsZW5hbWUgb2YgdGhlIGluY2x1ZGVkIEdseXBoaWNvbnMgaWNvbiBmb250LiBVc2VmdWwgZm9yIHRob3NlIGluY2x1ZGluZyBCb290c3RyYXAgdmlhIEJvd2VyLlxuXG4vLyoqIExvYWQgZm9udHMgZnJvbSB0aGlzIGRpcmVjdG9yeS5cblxuLy8gW2NvbnZlcnRlcl0gSWYgJGJvb3RzdHJhcC1zYXNzLWFzc2V0LWhlbHBlciBpZiB1c2VkLCBwcm92aWRlIHBhdGggcmVsYXRpdmUgdG8gdGhlIGFzc2V0cyBsb2FkIHBhdGguXG4vLyBbY29udmVydGVyXSBUaGlzIGlzIGJlY2F1c2Ugc29tZSBhc3NldCBoZWxwZXJzLCBzdWNoIGFzIFNwcm9ja2V0cywgZG8gbm90IHdvcmsgd2l0aCBmaWxlLXJlbGF0aXZlIHBhdGhzLlxuJGljb24tZm9udC1wYXRoOiBpZigkYm9vdHN0cmFwLXNhc3MtYXNzZXQtaGVscGVyLCBcImJvb3RzdHJhcC9cIiwgXCIuLi9mb250cy9ib290c3RyYXAvXCIpICFkZWZhdWx0O1xuXG4vLyoqIEZpbGUgbmFtZSBmb3IgYWxsIGZvbnQgZmlsZXMuXG4kaWNvbi1mb250LW5hbWU6ICAgICAgICAgIFwiZ2x5cGhpY29ucy1oYWxmbGluZ3MtcmVndWxhclwiICFkZWZhdWx0O1xuLy8qKiBFbGVtZW50IElEIHdpdGhpbiBTVkcgaWNvbiBmaWxlLlxuJGljb24tZm9udC1zdmctaWQ6ICAgICAgICBcImdseXBoaWNvbnNfaGFsZmxpbmdzcmVndWxhclwiICFkZWZhdWx0O1xuXG5cbi8vPT0gQ29tcG9uZW50c1xuLy9cbi8vIyMgRGVmaW5lIGNvbW1vbiBwYWRkaW5nIGFuZCBib3JkZXIgcmFkaXVzIHNpemVzIGFuZCBtb3JlLiBWYWx1ZXMgYmFzZWQgb24gMTRweCB0ZXh0IGFuZCAxLjQyOCBsaW5lLWhlaWdodCAofjIwcHggdG8gc3RhcnQpLlxuXG4kcGFkZGluZy1iYXNlLXZlcnRpY2FsOiAgICAgNnB4ICFkZWZhdWx0O1xuJHBhZGRpbmctYmFzZS1ob3Jpem9udGFsOiAgIDEycHggIWRlZmF1bHQ7XG5cbiRwYWRkaW5nLWxhcmdlLXZlcnRpY2FsOiAgICAxMHB4ICFkZWZhdWx0O1xuJHBhZGRpbmctbGFyZ2UtaG9yaXpvbnRhbDogIDE2cHggIWRlZmF1bHQ7XG5cbiRwYWRkaW5nLXNtYWxsLXZlcnRpY2FsOiAgICA1cHggIWRlZmF1bHQ7XG4kcGFkZGluZy1zbWFsbC1ob3Jpem9udGFsOiAgMTBweCAhZGVmYXVsdDtcblxuJHBhZGRpbmcteHMtdmVydGljYWw6ICAgICAgIDFweCAhZGVmYXVsdDtcbiRwYWRkaW5nLXhzLWhvcml6b250YWw6ICAgICA1cHggIWRlZmF1bHQ7XG5cbiRsaW5lLWhlaWdodC1sYXJnZTogICAgICAgICAxLjMzMzMzMzMgIWRlZmF1bHQ7IC8vIGV4dHJhIGRlY2ltYWxzIGZvciBXaW4gOC4xIENocm9tZVxuJGxpbmUtaGVpZ2h0LXNtYWxsOiAgICAgICAgIDEuNSAhZGVmYXVsdDtcblxuJGJvcmRlci1yYWRpdXMtYmFzZTogICAgICAgIDRweCAhZGVmYXVsdDtcbiRib3JkZXItcmFkaXVzLWxhcmdlOiAgICAgICA2cHggIWRlZmF1bHQ7XG4kYm9yZGVyLXJhZGl1cy1zbWFsbDogICAgICAgM3B4ICFkZWZhdWx0O1xuXG4vLyoqIEdsb2JhbCBjb2xvciBmb3IgYWN0aXZlIGl0ZW1zIChlLmcuLCBuYXZzIG9yIGRyb3Bkb3ducykuXG4kY29tcG9uZW50LWFjdGl2ZS1jb2xvcjogICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogR2xvYmFsIGJhY2tncm91bmQgY29sb3IgZm9yIGFjdGl2ZSBpdGVtcyAoZS5nLiwgbmF2cyBvciBkcm9wZG93bnMpLlxuJGNvbXBvbmVudC1hY3RpdmUtYmc6ICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuXG4vLyoqIFdpZHRoIG9mIHRoZSBgYm9yZGVyYCBmb3IgZ2VuZXJhdGluZyBjYXJldHMgdGhhdCBpbmRpY2F0b3IgZHJvcGRvd25zLlxuJGNhcmV0LXdpZHRoLWJhc2U6ICAgICAgICAgIDRweCAhZGVmYXVsdDtcbi8vKiogQ2FyZXRzIGluY3JlYXNlIHNsaWdodGx5IGluIHNpemUgZm9yIGxhcmdlciBjb21wb25lbnRzLlxuJGNhcmV0LXdpZHRoLWxhcmdlOiAgICAgICAgIDVweCAhZGVmYXVsdDtcblxuXG4vLz09IFRhYmxlc1xuLy9cbi8vIyMgQ3VzdG9taXplcyB0aGUgYC50YWJsZWAgY29tcG9uZW50IHdpdGggYmFzaWMgdmFsdWVzLCBlYWNoIHVzZWQgYWNyb3NzIGFsbCB0YWJsZSB2YXJpYXRpb25zLlxuXG4vLyoqIFBhZGRpbmcgZm9yIGA8dGg+YHMgYW5kIGA8dGQ+YHMuXG4kdGFibGUtY2VsbC1wYWRkaW5nOiAgICAgICAgICAgIDhweCAhZGVmYXVsdDtcbi8vKiogUGFkZGluZyBmb3IgY2VsbHMgaW4gYC50YWJsZS1jb25kZW5zZWRgLlxuJHRhYmxlLWNvbmRlbnNlZC1jZWxsLXBhZGRpbmc6ICA1cHggIWRlZmF1bHQ7XG5cbi8vKiogRGVmYXVsdCBiYWNrZ3JvdW5kIGNvbG9yIHVzZWQgZm9yIGFsbCB0YWJsZXMuXG4kdGFibGUtYmc6ICAgICAgICAgICAgICAgICAgICAgIHRyYW5zcGFyZW50ICFkZWZhdWx0O1xuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIHVzZWQgZm9yIGAudGFibGUtc3RyaXBlZGAuXG4kdGFibGUtYmctYWNjZW50OiAgICAgICAgICAgICAgICNmOWY5ZjkgIWRlZmF1bHQ7XG4vLyoqIEJhY2tncm91bmQgY29sb3IgdXNlZCBmb3IgYC50YWJsZS1ob3ZlcmAuXG4kdGFibGUtYmctaG92ZXI6ICAgICAgICAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG4kdGFibGUtYmctYWN0aXZlOiAgICAgICAgICAgICAgICR0YWJsZS1iZy1ob3ZlciAhZGVmYXVsdDtcblxuLy8qKiBCb3JkZXIgY29sb3IgZm9yIHRhYmxlIGFuZCBjZWxsIGJvcmRlcnMuXG4kdGFibGUtYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG5cblxuLy89PSBCdXR0b25zXG4vL1xuLy8jIyBGb3IgZWFjaCBvZiBCb290c3RyYXAncyBidXR0b25zLCBkZWZpbmUgdGV4dCwgYmFja2dyb3VuZCBhbmQgYm9yZGVyIGNvbG9yLlxuXG4kYnRuLWZvbnQtd2VpZ2h0OiAgICAgICAgICAgICAgICBub3JtYWwgIWRlZmF1bHQ7XG5cbiRidG4tZGVmYXVsdC1jb2xvcjogICAgICAgICAgICAgICMzMzMgIWRlZmF1bHQ7XG4kYnRuLWRlZmF1bHQtYmc6ICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGJ0bi1kZWZhdWx0LWJvcmRlcjogICAgICAgICAgICAgI2NjYyAhZGVmYXVsdDtcblxuJGJ0bi1wcmltYXJ5LWNvbG9yOiAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRidG4tcHJpbWFyeS1iZzogICAgICAgICAgICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuJGJ0bi1wcmltYXJ5LWJvcmRlcjogICAgICAgICAgICAgZGFya2VuKCRidG4tcHJpbWFyeS1iZywgNSUpICFkZWZhdWx0O1xuXG4kYnRuLXN1Y2Nlc3MtY29sb3I6ICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGJ0bi1zdWNjZXNzLWJnOiAgICAgICAgICAgICAgICAgJGJyYW5kLXN1Y2Nlc3MgIWRlZmF1bHQ7XG4kYnRuLXN1Y2Nlc3MtYm9yZGVyOiAgICAgICAgICAgICBkYXJrZW4oJGJ0bi1zdWNjZXNzLWJnLCA1JSkgIWRlZmF1bHQ7XG5cbiRidG4taW5mby1jb2xvcjogICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kYnRuLWluZm8tYmc6ICAgICAgICAgICAgICAgICAgICAkYnJhbmQtaW5mbyAhZGVmYXVsdDtcbiRidG4taW5mby1ib3JkZXI6ICAgICAgICAgICAgICAgIGRhcmtlbigkYnRuLWluZm8tYmcsIDUlKSAhZGVmYXVsdDtcblxuJGJ0bi13YXJuaW5nLWNvbG9yOiAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRidG4td2FybmluZy1iZzogICAgICAgICAgICAgICAgICRicmFuZC13YXJuaW5nICFkZWZhdWx0O1xuJGJ0bi13YXJuaW5nLWJvcmRlcjogICAgICAgICAgICAgZGFya2VuKCRidG4td2FybmluZy1iZywgNSUpICFkZWZhdWx0O1xuXG4kYnRuLWRhbmdlci1jb2xvcjogICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGJ0bi1kYW5nZXItYmc6ICAgICAgICAgICAgICAgICAgJGJyYW5kLWRhbmdlciAhZGVmYXVsdDtcbiRidG4tZGFuZ2VyLWJvcmRlcjogICAgICAgICAgICAgIGRhcmtlbigkYnRuLWRhbmdlci1iZywgNSUpICFkZWZhdWx0O1xuXG4kYnRuLWxpbmstZGlzYWJsZWQtY29sb3I6ICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcblxuLy8gQWxsb3dzIGZvciBjdXN0b21pemluZyBidXR0b24gcmFkaXVzIGluZGVwZW5kZW50bHkgZnJvbSBnbG9iYWwgYm9yZGVyIHJhZGl1c1xuJGJ0bi1ib3JkZXItcmFkaXVzLWJhc2U6ICAgICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcbiRidG4tYm9yZGVyLXJhZGl1cy1sYXJnZTogICAgICAgICRib3JkZXItcmFkaXVzLWxhcmdlICFkZWZhdWx0O1xuJGJ0bi1ib3JkZXItcmFkaXVzLXNtYWxsOiAgICAgICAgJGJvcmRlci1yYWRpdXMtc21hbGwgIWRlZmF1bHQ7XG5cblxuLy89PSBGb3Jtc1xuLy9cbi8vIyNcblxuLy8qKiBgPGlucHV0PmAgYmFja2dyb3VuZCBjb2xvclxuJGlucHV0LWJnOiAgICAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogYDxpbnB1dCBkaXNhYmxlZD5gIGJhY2tncm91bmQgY29sb3JcbiRpbnB1dC1iZy1kaXNhYmxlZDogICAgICAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG5cbi8vKiogVGV4dCBjb2xvciBmb3IgYDxpbnB1dD5gc1xuJGlucHV0LWNvbG9yOiAgICAgICAgICAgICAgICAgICAgJGdyYXkgIWRlZmF1bHQ7XG4vLyoqIGA8aW5wdXQ+YCBib3JkZXIgY29sb3JcbiRpbnB1dC1ib3JkZXI6ICAgICAgICAgICAgICAgICAgICNjY2MgIWRlZmF1bHQ7XG5cbi8vIFRPRE86IFJlbmFtZSBgJGlucHV0LWJvcmRlci1yYWRpdXNgIHRvIGAkaW5wdXQtYm9yZGVyLXJhZGl1cy1iYXNlYCBpbiB2NFxuLy8qKiBEZWZhdWx0IGAuZm9ybS1jb250cm9sYCBib3JkZXIgcmFkaXVzXG4vLyBUaGlzIGhhcyBubyBlZmZlY3Qgb24gYDxzZWxlY3Q+YHMgaW4gc29tZSBicm93c2VycywgZHVlIHRvIHRoZSBsaW1pdGVkIHN0eWxhYmlsaXR5IG9mIGA8c2VsZWN0PmBzIGluIENTUy5cbiRpbnB1dC1ib3JkZXItcmFkaXVzOiAgICAgICAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG4vLyoqIExhcmdlIGAuZm9ybS1jb250cm9sYCBib3JkZXIgcmFkaXVzXG4kaW5wdXQtYm9yZGVyLXJhZGl1cy1sYXJnZTogICAgICAkYm9yZGVyLXJhZGl1cy1sYXJnZSAhZGVmYXVsdDtcbi8vKiogU21hbGwgYC5mb3JtLWNvbnRyb2xgIGJvcmRlciByYWRpdXNcbiRpbnB1dC1ib3JkZXItcmFkaXVzLXNtYWxsOiAgICAgICRib3JkZXItcmFkaXVzLXNtYWxsICFkZWZhdWx0O1xuXG4vLyoqIEJvcmRlciBjb2xvciBmb3IgaW5wdXRzIG9uIGZvY3VzXG4kaW5wdXQtYm9yZGVyLWZvY3VzOiAgICAgICAgICAgICAjNjZhZmU5ICFkZWZhdWx0O1xuXG4vLyoqIFBsYWNlaG9sZGVyIHRleHQgY29sb3JcbiRpbnB1dC1jb2xvci1wbGFjZWhvbGRlcjogICAgICAgICM5OTkgIWRlZmF1bHQ7XG5cbi8vKiogRGVmYXVsdCBgLmZvcm0tY29udHJvbGAgaGVpZ2h0XG4kaW5wdXQtaGVpZ2h0LWJhc2U6ICAgICAgICAgICAgICAoJGxpbmUtaGVpZ2h0LWNvbXB1dGVkICsgKCRwYWRkaW5nLWJhc2UtdmVydGljYWwgKiAyKSArIDIpICFkZWZhdWx0O1xuLy8qKiBMYXJnZSBgLmZvcm0tY29udHJvbGAgaGVpZ2h0XG4kaW5wdXQtaGVpZ2h0LWxhcmdlOiAgICAgICAgICAgICAoY2VpbCgkZm9udC1zaXplLWxhcmdlICogJGxpbmUtaGVpZ2h0LWxhcmdlKSArICgkcGFkZGluZy1sYXJnZS12ZXJ0aWNhbCAqIDIpICsgMikgIWRlZmF1bHQ7XG4vLyoqIFNtYWxsIGAuZm9ybS1jb250cm9sYCBoZWlnaHRcbiRpbnB1dC1oZWlnaHQtc21hbGw6ICAgICAgICAgICAgIChmbG9vcigkZm9udC1zaXplLXNtYWxsICogJGxpbmUtaGVpZ2h0LXNtYWxsKSArICgkcGFkZGluZy1zbWFsbC12ZXJ0aWNhbCAqIDIpICsgMikgIWRlZmF1bHQ7XG5cbi8vKiogYC5mb3JtLWdyb3VwYCBtYXJnaW5cbiRmb3JtLWdyb3VwLW1hcmdpbi1ib3R0b206ICAgICAgIDE1cHggIWRlZmF1bHQ7XG5cbiRsZWdlbmQtY29sb3I6ICAgICAgICAgICAgICAgICAgICRncmF5LWRhcmsgIWRlZmF1bHQ7XG4kbGVnZW5kLWJvcmRlci1jb2xvcjogICAgICAgICAgICAjZTVlNWU1ICFkZWZhdWx0O1xuXG4vLyoqIEJhY2tncm91bmQgY29sb3IgZm9yIHRleHR1YWwgaW5wdXQgYWRkb25zXG4kaW5wdXQtZ3JvdXAtYWRkb24tYmc6ICAgICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuLy8qKiBCb3JkZXIgY29sb3IgZm9yIHRleHR1YWwgaW5wdXQgYWRkb25zXG4kaW5wdXQtZ3JvdXAtYWRkb24tYm9yZGVyLWNvbG9yOiAkaW5wdXQtYm9yZGVyICFkZWZhdWx0O1xuXG4vLyoqIERpc2FibGVkIGN1cnNvciBmb3IgZm9ybSBjb250cm9scyBhbmQgYnV0dG9ucy5cbiRjdXJzb3ItZGlzYWJsZWQ6ICAgICAgICAgICAgICAgIG5vdC1hbGxvd2VkICFkZWZhdWx0O1xuXG5cbi8vPT0gRHJvcGRvd25zXG4vL1xuLy8jIyBEcm9wZG93biBtZW51IGNvbnRhaW5lciBhbmQgY29udGVudHMuXG5cbi8vKiogQmFja2dyb3VuZCBmb3IgdGhlIGRyb3Bkb3duIG1lbnUuXG4kZHJvcGRvd24tYmc6ICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBEcm9wZG93biBtZW51IGBib3JkZXItY29sb3JgLlxuJGRyb3Bkb3duLWJvcmRlcjogICAgICAgICAgICAgICAgcmdiYSgwLDAsMCwuMTUpICFkZWZhdWx0O1xuLy8qKiBEcm9wZG93biBtZW51IGBib3JkZXItY29sb3JgICoqZm9yIElFOCoqLlxuJGRyb3Bkb3duLWZhbGxiYWNrLWJvcmRlcjogICAgICAgI2NjYyAhZGVmYXVsdDtcbi8vKiogRGl2aWRlciBjb2xvciBmb3IgYmV0d2VlbiBkcm9wZG93biBpdGVtcy5cbiRkcm9wZG93bi1kaXZpZGVyLWJnOiAgICAgICAgICAgICNlNWU1ZTUgIWRlZmF1bHQ7XG5cbi8vKiogRHJvcGRvd24gbGluayB0ZXh0IGNvbG9yLlxuJGRyb3Bkb3duLWxpbmstY29sb3I6ICAgICAgICAgICAgJGdyYXktZGFyayAhZGVmYXVsdDtcbi8vKiogSG92ZXIgY29sb3IgZm9yIGRyb3Bkb3duIGxpbmtzLlxuJGRyb3Bkb3duLWxpbmstaG92ZXItY29sb3I6ICAgICAgZGFya2VuKCRncmF5LWRhcmssIDUlKSAhZGVmYXVsdDtcbi8vKiogSG92ZXIgYmFja2dyb3VuZCBmb3IgZHJvcGRvd24gbGlua3MuXG4kZHJvcGRvd24tbGluay1ob3Zlci1iZzogICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuXG4vLyoqIEFjdGl2ZSBkcm9wZG93biBtZW51IGl0ZW0gdGV4dCBjb2xvci5cbiRkcm9wZG93bi1saW5rLWFjdGl2ZS1jb2xvcjogICAgICRjb21wb25lbnQtYWN0aXZlLWNvbG9yICFkZWZhdWx0O1xuLy8qKiBBY3RpdmUgZHJvcGRvd24gbWVudSBpdGVtIGJhY2tncm91bmQgY29sb3IuXG4kZHJvcGRvd24tbGluay1hY3RpdmUtYmc6ICAgICAgICAkY29tcG9uZW50LWFjdGl2ZS1iZyAhZGVmYXVsdDtcblxuLy8qKiBEaXNhYmxlZCBkcm9wZG93biBtZW51IGl0ZW0gYmFja2dyb3VuZCBjb2xvci5cbiRkcm9wZG93bi1saW5rLWRpc2FibGVkLWNvbG9yOiAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuXG4vLyoqIFRleHQgY29sb3IgZm9yIGhlYWRlcnMgd2l0aGluIGRyb3Bkb3duIG1lbnVzLlxuJGRyb3Bkb3duLWhlYWRlci1jb2xvcjogICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG5cbi8vKiogRGVwcmVjYXRlZCBgJGRyb3Bkb3duLWNhcmV0LWNvbG9yYCBhcyBvZiB2My4xLjBcbiRkcm9wZG93bi1jYXJldC1jb2xvcjogICAgICAgICAgICMwMDAgIWRlZmF1bHQ7XG5cblxuLy8tLSBaLWluZGV4IG1hc3RlciBsaXN0XG4vL1xuLy8gV2FybmluZzogQXZvaWQgY3VzdG9taXppbmcgdGhlc2UgdmFsdWVzLiBUaGV5J3JlIHVzZWQgZm9yIGEgYmlyZCdzIGV5ZSB2aWV3XG4vLyBvZiBjb21wb25lbnRzIGRlcGVuZGVudCBvbiB0aGUgei1heGlzIGFuZCBhcmUgZGVzaWduZWQgdG8gYWxsIHdvcmsgdG9nZXRoZXIuXG4vL1xuLy8gTm90ZTogVGhlc2UgdmFyaWFibGVzIGFyZSBub3QgZ2VuZXJhdGVkIGludG8gdGhlIEN1c3RvbWl6ZXIuXG5cbiR6aW5kZXgtbmF2YmFyOiAgICAgICAgICAgIDEwMDAgIWRlZmF1bHQ7XG4kemluZGV4LWRyb3Bkb3duOiAgICAgICAgICAxMDAwICFkZWZhdWx0O1xuJHppbmRleC1wb3BvdmVyOiAgICAgICAgICAgMTA2MCAhZGVmYXVsdDtcbiR6aW5kZXgtdG9vbHRpcDogICAgICAgICAgIDEwNzAgIWRlZmF1bHQ7XG4kemluZGV4LW5hdmJhci1maXhlZDogICAgICAxMDMwICFkZWZhdWx0O1xuJHppbmRleC1tb2RhbC1iYWNrZ3JvdW5kOiAgMTA0MCAhZGVmYXVsdDtcbiR6aW5kZXgtbW9kYWw6ICAgICAgICAgICAgIDEwNTAgIWRlZmF1bHQ7XG5cblxuLy89PSBNZWRpYSBxdWVyaWVzIGJyZWFrcG9pbnRzXG4vL1xuLy8jIyBEZWZpbmUgdGhlIGJyZWFrcG9pbnRzIGF0IHdoaWNoIHlvdXIgbGF5b3V0IHdpbGwgY2hhbmdlLCBhZGFwdGluZyB0byBkaWZmZXJlbnQgc2NyZWVuIHNpemVzLlxuXG4vLyBFeHRyYSBzbWFsbCBzY3JlZW4gLyBwaG9uZVxuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLXhzYCBhcyBvZiB2My4wLjFcbiRzY3JlZW4teHM6ICAgICAgICAgICAgICAgICAgNDgwcHggIWRlZmF1bHQ7XG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4teHMtbWluYCBhcyBvZiB2My4yLjBcbiRzY3JlZW4teHMtbWluOiAgICAgICAgICAgICAgJHNjcmVlbi14cyAhZGVmYXVsdDtcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi1waG9uZWAgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLXBob25lOiAgICAgICAgICAgICAgICRzY3JlZW4teHMtbWluICFkZWZhdWx0O1xuXG4vLyBTbWFsbCBzY3JlZW4gLyB0YWJsZXRcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi1zbWAgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLXNtOiAgICAgICAgICAgICAgICAgIDc2OHB4ICFkZWZhdWx0O1xuJHNjcmVlbi1zbS1taW46ICAgICAgICAgICAgICAkc2NyZWVuLXNtICFkZWZhdWx0O1xuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLXRhYmxldGAgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLXRhYmxldDogICAgICAgICAgICAgICRzY3JlZW4tc20tbWluICFkZWZhdWx0O1xuXG4vLyBNZWRpdW0gc2NyZWVuIC8gZGVza3RvcFxuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLW1kYCBhcyBvZiB2My4wLjFcbiRzY3JlZW4tbWQ6ICAgICAgICAgICAgICAgICAgOTkycHggIWRlZmF1bHQ7XG4kc2NyZWVuLW1kLW1pbjogICAgICAgICAgICAgICRzY3JlZW4tbWQgIWRlZmF1bHQ7XG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4tZGVza3RvcGAgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLWRlc2t0b3A6ICAgICAgICAgICAgICRzY3JlZW4tbWQtbWluICFkZWZhdWx0O1xuXG4vLyBMYXJnZSBzY3JlZW4gLyB3aWRlIGRlc2t0b3Bcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi1sZ2AgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLWxnOiAgICAgICAgICAgICAgICAgIDEyMDBweCAhZGVmYXVsdDtcbiRzY3JlZW4tbGctbWluOiAgICAgICAgICAgICAgJHNjcmVlbi1sZyAhZGVmYXVsdDtcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi1sZy1kZXNrdG9wYCBhcyBvZiB2My4wLjFcbiRzY3JlZW4tbGctZGVza3RvcDogICAgICAgICAgJHNjcmVlbi1sZy1taW4gIWRlZmF1bHQ7XG5cbi8vIFNvIG1lZGlhIHF1ZXJpZXMgZG9uJ3Qgb3ZlcmxhcCB3aGVuIHJlcXVpcmVkLCBwcm92aWRlIGEgbWF4aW11bVxuJHNjcmVlbi14cy1tYXg6ICAgICAgICAgICAgICAoJHNjcmVlbi1zbS1taW4gLSAxKSAhZGVmYXVsdDtcbiRzY3JlZW4tc20tbWF4OiAgICAgICAgICAgICAgKCRzY3JlZW4tbWQtbWluIC0gMSkgIWRlZmF1bHQ7XG4kc2NyZWVuLW1kLW1heDogICAgICAgICAgICAgICgkc2NyZWVuLWxnLW1pbiAtIDEpICFkZWZhdWx0O1xuXG5cbi8vPT0gR3JpZCBzeXN0ZW1cbi8vXG4vLyMjIERlZmluZSB5b3VyIGN1c3RvbSByZXNwb25zaXZlIGdyaWQuXG5cbi8vKiogTnVtYmVyIG9mIGNvbHVtbnMgaW4gdGhlIGdyaWQuXG4kZ3JpZC1jb2x1bW5zOiAgICAgICAgICAgICAgMTIgIWRlZmF1bHQ7XG4vLyoqIFBhZGRpbmcgYmV0d2VlbiBjb2x1bW5zLiBHZXRzIGRpdmlkZWQgaW4gaGFsZiBmb3IgdGhlIGxlZnQgYW5kIHJpZ2h0LlxuJGdyaWQtZ3V0dGVyLXdpZHRoOiAgICAgICAgIDMwcHggIWRlZmF1bHQ7XG4vLyBOYXZiYXIgY29sbGFwc2Vcbi8vKiogUG9pbnQgYXQgd2hpY2ggdGhlIG5hdmJhciBiZWNvbWVzIHVuY29sbGFwc2VkLlxuJGdyaWQtZmxvYXQtYnJlYWtwb2ludDogICAgICRzY3JlZW4tc20tbWluICFkZWZhdWx0O1xuLy8qKiBQb2ludCBhdCB3aGljaCB0aGUgbmF2YmFyIGJlZ2lucyBjb2xsYXBzaW5nLlxuJGdyaWQtZmxvYXQtYnJlYWtwb2ludC1tYXg6ICgkZ3JpZC1mbG9hdC1icmVha3BvaW50IC0gMSkgIWRlZmF1bHQ7XG5cblxuLy89PSBDb250YWluZXIgc2l6ZXNcbi8vXG4vLyMjIERlZmluZSB0aGUgbWF4aW11bSB3aWR0aCBvZiBgLmNvbnRhaW5lcmAgZm9yIGRpZmZlcmVudCBzY3JlZW4gc2l6ZXMuXG5cbi8vIFNtYWxsIHNjcmVlbiAvIHRhYmxldFxuJGNvbnRhaW5lci10YWJsZXQ6ICAgICAgICAgICAgICg3MjBweCArICRncmlkLWd1dHRlci13aWR0aCkgIWRlZmF1bHQ7XG4vLyoqIEZvciBgJHNjcmVlbi1zbS1taW5gIGFuZCB1cC5cbiRjb250YWluZXItc206ICAgICAgICAgICAgICAgICAkY29udGFpbmVyLXRhYmxldCAhZGVmYXVsdDtcblxuLy8gTWVkaXVtIHNjcmVlbiAvIGRlc2t0b3BcbiRjb250YWluZXItZGVza3RvcDogICAgICAgICAgICAoOTQwcHggKyAkZ3JpZC1ndXR0ZXItd2lkdGgpICFkZWZhdWx0O1xuLy8qKiBGb3IgYCRzY3JlZW4tbWQtbWluYCBhbmQgdXAuXG4kY29udGFpbmVyLW1kOiAgICAgICAgICAgICAgICAgJGNvbnRhaW5lci1kZXNrdG9wICFkZWZhdWx0O1xuXG4vLyBMYXJnZSBzY3JlZW4gLyB3aWRlIGRlc2t0b3BcbiRjb250YWluZXItbGFyZ2UtZGVza3RvcDogICAgICAoMTE0MHB4ICsgJGdyaWQtZ3V0dGVyLXdpZHRoKSAhZGVmYXVsdDtcbi8vKiogRm9yIGAkc2NyZWVuLWxnLW1pbmAgYW5kIHVwLlxuJGNvbnRhaW5lci1sZzogICAgICAgICAgICAgICAgICRjb250YWluZXItbGFyZ2UtZGVza3RvcCAhZGVmYXVsdDtcblxuXG4vLz09IE5hdmJhclxuLy9cbi8vIyNcblxuLy8gQmFzaWNzIG9mIGEgbmF2YmFyXG4kbmF2YmFyLWhlaWdodDogICAgICAgICAgICAgICAgICAgIDUwcHggIWRlZmF1bHQ7XG4kbmF2YmFyLW1hcmdpbi1ib3R0b206ICAgICAgICAgICAgICRsaW5lLWhlaWdodC1jb21wdXRlZCAhZGVmYXVsdDtcbiRuYXZiYXItYm9yZGVyLXJhZGl1czogICAgICAgICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcbiRuYXZiYXItcGFkZGluZy1ob3Jpem9udGFsOiAgICAgICAgZmxvb3IoKCRncmlkLWd1dHRlci13aWR0aCAvIDIpKSAhZGVmYXVsdDtcbiRuYXZiYXItcGFkZGluZy12ZXJ0aWNhbDogICAgICAgICAgKCgkbmF2YmFyLWhlaWdodCAtICRsaW5lLWhlaWdodC1jb21wdXRlZCkgLyAyKSAhZGVmYXVsdDtcbiRuYXZiYXItY29sbGFwc2UtbWF4LWhlaWdodDogICAgICAgMzQwcHggIWRlZmF1bHQ7XG5cbiRuYXZiYXItZGVmYXVsdC1jb2xvcjogICAgICAgICAgICAgIzc3NyAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1iZzogICAgICAgICAgICAgICAgI2Y4ZjhmOCAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1ib3JkZXI6ICAgICAgICAgICAgZGFya2VuKCRuYXZiYXItZGVmYXVsdC1iZywgNi41JSkgIWRlZmF1bHQ7XG5cbi8vIE5hdmJhciBsaW5rc1xuJG5hdmJhci1kZWZhdWx0LWxpbmstY29sb3I6ICAgICAgICAgICAgICAgICM3NzcgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtbGluay1ob3Zlci1jb2xvcjogICAgICAgICAgIzMzMyAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1saW5rLWhvdmVyLWJnOiAgICAgICAgICAgICB0cmFuc3BhcmVudCAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1saW5rLWFjdGl2ZS1jb2xvcjogICAgICAgICAjNTU1ICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWxpbmstYWN0aXZlLWJnOiAgICAgICAgICAgIGRhcmtlbigkbmF2YmFyLWRlZmF1bHQtYmcsIDYuNSUpICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWxpbmstZGlzYWJsZWQtY29sb3I6ICAgICAgICNjY2MgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtbGluay1kaXNhYmxlZC1iZzogICAgICAgICAgdHJhbnNwYXJlbnQgIWRlZmF1bHQ7XG5cbi8vIE5hdmJhciBicmFuZCBsYWJlbFxuJG5hdmJhci1kZWZhdWx0LWJyYW5kLWNvbG9yOiAgICAgICAgICAgICAgICRuYXZiYXItZGVmYXVsdC1saW5rLWNvbG9yICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWJyYW5kLWhvdmVyLWNvbG9yOiAgICAgICAgIGRhcmtlbigkbmF2YmFyLWRlZmF1bHQtYnJhbmQtY29sb3IsIDEwJSkgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtYnJhbmQtaG92ZXItYmc6ICAgICAgICAgICAgdHJhbnNwYXJlbnQgIWRlZmF1bHQ7XG5cbi8vIE5hdmJhciB0b2dnbGVcbiRuYXZiYXItZGVmYXVsdC10b2dnbGUtaG92ZXItYmc6ICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LXRvZ2dsZS1pY29uLWJhci1iZzogICAgICAgICM4ODggIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtdG9nZ2xlLWJvcmRlci1jb2xvcjogICAgICAgI2RkZCAhZGVmYXVsdDtcblxuXG4vLz09PSBJbnZlcnRlZCBuYXZiYXJcbi8vIFJlc2V0IGludmVydGVkIG5hdmJhciBiYXNpY3NcbiRuYXZiYXItaW52ZXJzZS1jb2xvcjogICAgICAgICAgICAgICAgICAgICAgbGlnaHRlbigkZ3JheS1saWdodCwgMTUlKSAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1iZzogICAgICAgICAgICAgICAgICAgICAgICAgIzIyMiAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1ib3JkZXI6ICAgICAgICAgICAgICAgICAgICAgZGFya2VuKCRuYXZiYXItaW52ZXJzZS1iZywgMTAlKSAhZGVmYXVsdDtcblxuLy8gSW52ZXJ0ZWQgbmF2YmFyIGxpbmtzXG4kbmF2YmFyLWludmVyc2UtbGluay1jb2xvcjogICAgICAgICAgICAgICAgIGxpZ2h0ZW4oJGdyYXktbGlnaHQsIDE1JSkgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtbGluay1ob3Zlci1jb2xvcjogICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtbGluay1ob3Zlci1iZzogICAgICAgICAgICAgIHRyYW5zcGFyZW50ICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWxpbmstYWN0aXZlLWNvbG9yOiAgICAgICAgICAkbmF2YmFyLWludmVyc2UtbGluay1ob3Zlci1jb2xvciAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1saW5rLWFjdGl2ZS1iZzogICAgICAgICAgICAgZGFya2VuKCRuYXZiYXItaW52ZXJzZS1iZywgMTAlKSAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1saW5rLWRpc2FibGVkLWNvbG9yOiAgICAgICAgIzQ0NCAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1saW5rLWRpc2FibGVkLWJnOiAgICAgICAgICAgdHJhbnNwYXJlbnQgIWRlZmF1bHQ7XG5cbi8vIEludmVydGVkIG5hdmJhciBicmFuZCBsYWJlbFxuJG5hdmJhci1pbnZlcnNlLWJyYW5kLWNvbG9yOiAgICAgICAgICAgICAgICAkbmF2YmFyLWludmVyc2UtbGluay1jb2xvciAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1icmFuZC1ob3Zlci1jb2xvcjogICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1icmFuZC1ob3Zlci1iZzogICAgICAgICAgICAgdHJhbnNwYXJlbnQgIWRlZmF1bHQ7XG5cbi8vIEludmVydGVkIG5hdmJhciB0b2dnbGVcbiRuYXZiYXItaW52ZXJzZS10b2dnbGUtaG92ZXItYmc6ICAgICAgICAgICAgIzMzMyAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS10b2dnbGUtaWNvbi1iYXItYmc6ICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS10b2dnbGUtYm9yZGVyLWNvbG9yOiAgICAgICAgIzMzMyAhZGVmYXVsdDtcblxuXG4vLz09IE5hdnNcbi8vXG4vLyMjXG5cbi8vPT09IFNoYXJlZCBuYXYgc3R5bGVzXG4kbmF2LWxpbmstcGFkZGluZzogICAgICAgICAgICAgICAgICAgICAgICAgIDEwcHggMTVweCAhZGVmYXVsdDtcbiRuYXYtbGluay1ob3Zlci1iZzogICAgICAgICAgICAgICAgICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcblxuJG5hdi1kaXNhYmxlZC1saW5rLWNvbG9yOiAgICAgICAgICAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbiRuYXYtZGlzYWJsZWQtbGluay1ob3Zlci1jb2xvcjogICAgICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG5cbi8vPT0gVGFic1xuJG5hdi10YWJzLWJvcmRlci1jb2xvcjogICAgICAgICAgICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuXG4kbmF2LXRhYnMtbGluay1ob3Zlci1ib3JkZXItY29sb3I6ICAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG5cbiRuYXYtdGFicy1hY3RpdmUtbGluay1ob3Zlci1iZzogICAgICAgICAgICAgJGJvZHktYmcgIWRlZmF1bHQ7XG4kbmF2LXRhYnMtYWN0aXZlLWxpbmstaG92ZXItY29sb3I6ICAgICAgICAgICRncmF5ICFkZWZhdWx0O1xuJG5hdi10YWJzLWFjdGl2ZS1saW5rLWhvdmVyLWJvcmRlci1jb2xvcjogICAjZGRkICFkZWZhdWx0O1xuXG4kbmF2LXRhYnMtanVzdGlmaWVkLWxpbmstYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG4kbmF2LXRhYnMtanVzdGlmaWVkLWFjdGl2ZS1saW5rLWJvcmRlci1jb2xvcjogICAgICRib2R5LWJnICFkZWZhdWx0O1xuXG4vLz09IFBpbGxzXG4kbmF2LXBpbGxzLWJvcmRlci1yYWRpdXM6ICAgICAgICAgICAgICAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG4kbmF2LXBpbGxzLWFjdGl2ZS1saW5rLWhvdmVyLWJnOiAgICAgICAgICAgICRjb21wb25lbnQtYWN0aXZlLWJnICFkZWZhdWx0O1xuJG5hdi1waWxscy1hY3RpdmUtbGluay1ob3Zlci1jb2xvcjogICAgICAgICAkY29tcG9uZW50LWFjdGl2ZS1jb2xvciAhZGVmYXVsdDtcblxuXG4vLz09IFBhZ2luYXRpb25cbi8vXG4vLyMjXG5cbiRwYWdpbmF0aW9uLWNvbG9yOiAgICAgICAgICAgICAgICAgICAgICRsaW5rLWNvbG9yICFkZWZhdWx0O1xuJHBhZ2luYXRpb24tYmc6ICAgICAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWJvcmRlcjogICAgICAgICAgICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG5cbiRwYWdpbmF0aW9uLWhvdmVyLWNvbG9yOiAgICAgICAgICAgICAgICRsaW5rLWhvdmVyLWNvbG9yICFkZWZhdWx0O1xuJHBhZ2luYXRpb24taG92ZXItYmc6ICAgICAgICAgICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWhvdmVyLWJvcmRlcjogICAgICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG5cbiRwYWdpbmF0aW9uLWFjdGl2ZS1jb2xvcjogICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1hY3RpdmUtYmc6ICAgICAgICAgICAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWFjdGl2ZS1ib3JkZXI6ICAgICAgICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuXG4kcGFnaW5hdGlvbi1kaXNhYmxlZC1jb2xvcjogICAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWRpc2FibGVkLWJnOiAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1kaXNhYmxlZC1ib3JkZXI6ICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuXG5cbi8vPT0gUGFnZXJcbi8vXG4vLyMjXG5cbiRwYWdlci1iZzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICRwYWdpbmF0aW9uLWJnICFkZWZhdWx0O1xuJHBhZ2VyLWJvcmRlcjogICAgICAgICAgICAgICAgICAgICAgICAgJHBhZ2luYXRpb24tYm9yZGVyICFkZWZhdWx0O1xuJHBhZ2VyLWJvcmRlci1yYWRpdXM6ICAgICAgICAgICAgICAgICAgMTVweCAhZGVmYXVsdDtcblxuJHBhZ2VyLWhvdmVyLWJnOiAgICAgICAgICAgICAgICAgICAgICAgJHBhZ2luYXRpb24taG92ZXItYmcgIWRlZmF1bHQ7XG5cbiRwYWdlci1hY3RpdmUtYmc6ICAgICAgICAgICAgICAgICAgICAgICRwYWdpbmF0aW9uLWFjdGl2ZS1iZyAhZGVmYXVsdDtcbiRwYWdlci1hY3RpdmUtY29sb3I6ICAgICAgICAgICAgICAgICAgICRwYWdpbmF0aW9uLWFjdGl2ZS1jb2xvciAhZGVmYXVsdDtcblxuJHBhZ2VyLWRpc2FibGVkLWNvbG9yOiAgICAgICAgICAgICAgICAgJHBhZ2luYXRpb24tZGlzYWJsZWQtY29sb3IgIWRlZmF1bHQ7XG5cblxuLy89PSBKdW1ib3Ryb25cbi8vXG4vLyMjXG5cbiRqdW1ib3Ryb24tcGFkZGluZzogICAgICAgICAgICAgIDMwcHggIWRlZmF1bHQ7XG4kanVtYm90cm9uLWNvbG9yOiAgICAgICAgICAgICAgICBpbmhlcml0ICFkZWZhdWx0O1xuJGp1bWJvdHJvbi1iZzogICAgICAgICAgICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcbiRqdW1ib3Ryb24taGVhZGluZy1jb2xvcjogICAgICAgIGluaGVyaXQgIWRlZmF1bHQ7XG4kanVtYm90cm9uLWZvbnQtc2l6ZTogICAgICAgICAgICBjZWlsKCgkZm9udC1zaXplLWJhc2UgKiAxLjUpKSAhZGVmYXVsdDtcbiRqdW1ib3Ryb24taGVhZGluZy1mb250LXNpemU6ICAgIGNlaWwoKCRmb250LXNpemUtYmFzZSAqIDQuNSkpICFkZWZhdWx0O1xuXG5cbi8vPT0gRm9ybSBzdGF0ZXMgYW5kIGFsZXJ0c1xuLy9cbi8vIyMgRGVmaW5lIGNvbG9ycyBmb3IgZm9ybSBmZWVkYmFjayBzdGF0ZXMgYW5kLCBieSBkZWZhdWx0LCBhbGVydHMuXG5cbiRzdGF0ZS1zdWNjZXNzLXRleHQ6ICAgICAgICAgICAgICMzYzc2M2QgIWRlZmF1bHQ7XG4kc3RhdGUtc3VjY2Vzcy1iZzogICAgICAgICAgICAgICAjZGZmMGQ4ICFkZWZhdWx0O1xuJHN0YXRlLXN1Y2Nlc3MtYm9yZGVyOiAgICAgICAgICAgZGFya2VuKGFkanVzdC1odWUoJHN0YXRlLXN1Y2Nlc3MtYmcsIC0xMCksIDUlKSAhZGVmYXVsdDtcblxuJHN0YXRlLWluZm8tdGV4dDogICAgICAgICAgICAgICAgIzMxNzA4ZiAhZGVmYXVsdDtcbiRzdGF0ZS1pbmZvLWJnOiAgICAgICAgICAgICAgICAgICNkOWVkZjcgIWRlZmF1bHQ7XG4kc3RhdGUtaW5mby1ib3JkZXI6ICAgICAgICAgICAgICBkYXJrZW4oYWRqdXN0LWh1ZSgkc3RhdGUtaW5mby1iZywgLTEwKSwgNyUpICFkZWZhdWx0O1xuXG4kc3RhdGUtd2FybmluZy10ZXh0OiAgICAgICAgICAgICAjOGE2ZDNiICFkZWZhdWx0O1xuJHN0YXRlLXdhcm5pbmctYmc6ICAgICAgICAgICAgICAgI2ZjZjhlMyAhZGVmYXVsdDtcbiRzdGF0ZS13YXJuaW5nLWJvcmRlcjogICAgICAgICAgIGRhcmtlbihhZGp1c3QtaHVlKCRzdGF0ZS13YXJuaW5nLWJnLCAtMTApLCA1JSkgIWRlZmF1bHQ7XG5cbiRzdGF0ZS1kYW5nZXItdGV4dDogICAgICAgICAgICAgICNhOTQ0NDIgIWRlZmF1bHQ7XG4kc3RhdGUtZGFuZ2VyLWJnOiAgICAgICAgICAgICAgICAjZjJkZWRlICFkZWZhdWx0O1xuJHN0YXRlLWRhbmdlci1ib3JkZXI6ICAgICAgICAgICAgZGFya2VuKGFkanVzdC1odWUoJHN0YXRlLWRhbmdlci1iZywgLTEwKSwgNSUpICFkZWZhdWx0O1xuXG5cbi8vPT0gVG9vbHRpcHNcbi8vXG4vLyMjXG5cbi8vKiogVG9vbHRpcCBtYXggd2lkdGhcbiR0b29sdGlwLW1heC13aWR0aDogICAgICAgICAgIDIwMHB4ICFkZWZhdWx0O1xuLy8qKiBUb29sdGlwIHRleHQgY29sb3JcbiR0b29sdGlwLWNvbG9yOiAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIFRvb2x0aXAgYmFja2dyb3VuZCBjb2xvclxuJHRvb2x0aXAtYmc6ICAgICAgICAgICAgICAgICAgIzAwMCAhZGVmYXVsdDtcbiR0b29sdGlwLW9wYWNpdHk6ICAgICAgICAgICAgIC45ICFkZWZhdWx0O1xuXG4vLyoqIFRvb2x0aXAgYXJyb3cgd2lkdGhcbiR0b29sdGlwLWFycm93LXdpZHRoOiAgICAgICAgIDVweCAhZGVmYXVsdDtcbi8vKiogVG9vbHRpcCBhcnJvdyBjb2xvclxuJHRvb2x0aXAtYXJyb3ctY29sb3I6ICAgICAgICAgJHRvb2x0aXAtYmcgIWRlZmF1bHQ7XG5cblxuLy89PSBQb3BvdmVyc1xuLy9cbi8vIyNcblxuLy8qKiBQb3BvdmVyIGJvZHkgYmFja2dyb3VuZCBjb2xvclxuJHBvcG92ZXItYmc6ICAgICAgICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBQb3BvdmVyIG1heGltdW0gd2lkdGhcbiRwb3BvdmVyLW1heC13aWR0aDogICAgICAgICAgICAgICAgICAgMjc2cHggIWRlZmF1bHQ7XG4vLyoqIFBvcG92ZXIgYm9yZGVyIGNvbG9yXG4kcG9wb3Zlci1ib3JkZXItY29sb3I6ICAgICAgICAgICAgICAgIHJnYmEoMCwwLDAsLjIpICFkZWZhdWx0O1xuLy8qKiBQb3BvdmVyIGZhbGxiYWNrIGJvcmRlciBjb2xvclxuJHBvcG92ZXItZmFsbGJhY2stYm9yZGVyLWNvbG9yOiAgICAgICAjY2NjICFkZWZhdWx0O1xuXG4vLyoqIFBvcG92ZXIgdGl0bGUgYmFja2dyb3VuZCBjb2xvclxuJHBvcG92ZXItdGl0bGUtYmc6ICAgICAgICAgICAgICAgICAgICBkYXJrZW4oJHBvcG92ZXItYmcsIDMlKSAhZGVmYXVsdDtcblxuLy8qKiBQb3BvdmVyIGFycm93IHdpZHRoXG4kcG9wb3Zlci1hcnJvdy13aWR0aDogICAgICAgICAgICAgICAgIDEwcHggIWRlZmF1bHQ7XG4vLyoqIFBvcG92ZXIgYXJyb3cgY29sb3JcbiRwb3BvdmVyLWFycm93LWNvbG9yOiAgICAgICAgICAgICAgICAgJHBvcG92ZXItYmcgIWRlZmF1bHQ7XG5cbi8vKiogUG9wb3ZlciBvdXRlciBhcnJvdyB3aWR0aFxuJHBvcG92ZXItYXJyb3ctb3V0ZXItd2lkdGg6ICAgICAgICAgICAoJHBvcG92ZXItYXJyb3ctd2lkdGggKyAxKSAhZGVmYXVsdDtcbi8vKiogUG9wb3ZlciBvdXRlciBhcnJvdyBjb2xvclxuJHBvcG92ZXItYXJyb3ctb3V0ZXItY29sb3I6ICAgICAgICAgICBmYWRlX2luKCRwb3BvdmVyLWJvcmRlci1jb2xvciwgMC4wNSkgIWRlZmF1bHQ7XG4vLyoqIFBvcG92ZXIgb3V0ZXIgYXJyb3cgZmFsbGJhY2sgY29sb3JcbiRwb3BvdmVyLWFycm93LW91dGVyLWZhbGxiYWNrLWNvbG9yOiAgZGFya2VuKCRwb3BvdmVyLWZhbGxiYWNrLWJvcmRlci1jb2xvciwgMjAlKSAhZGVmYXVsdDtcblxuXG4vLz09IExhYmVsc1xuLy9cbi8vIyNcblxuLy8qKiBEZWZhdWx0IGxhYmVsIGJhY2tncm91bmQgY29sb3JcbiRsYWJlbC1kZWZhdWx0LWJnOiAgICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuLy8qKiBQcmltYXJ5IGxhYmVsIGJhY2tncm91bmQgY29sb3JcbiRsYWJlbC1wcmltYXJ5LWJnOiAgICAgICAgICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuLy8qKiBTdWNjZXNzIGxhYmVsIGJhY2tncm91bmQgY29sb3JcbiRsYWJlbC1zdWNjZXNzLWJnOiAgICAgICAgICAgICRicmFuZC1zdWNjZXNzICFkZWZhdWx0O1xuLy8qKiBJbmZvIGxhYmVsIGJhY2tncm91bmQgY29sb3JcbiRsYWJlbC1pbmZvLWJnOiAgICAgICAgICAgICAgICRicmFuZC1pbmZvICFkZWZhdWx0O1xuLy8qKiBXYXJuaW5nIGxhYmVsIGJhY2tncm91bmQgY29sb3JcbiRsYWJlbC13YXJuaW5nLWJnOiAgICAgICAgICAgICRicmFuZC13YXJuaW5nICFkZWZhdWx0O1xuLy8qKiBEYW5nZXIgbGFiZWwgYmFja2dyb3VuZCBjb2xvclxuJGxhYmVsLWRhbmdlci1iZzogICAgICAgICAgICAgJGJyYW5kLWRhbmdlciAhZGVmYXVsdDtcblxuLy8qKiBEZWZhdWx0IGxhYmVsIHRleHQgY29sb3JcbiRsYWJlbC1jb2xvcjogICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIERlZmF1bHQgdGV4dCBjb2xvciBvZiBhIGxpbmtlZCBsYWJlbFxuJGxhYmVsLWxpbmstaG92ZXItY29sb3I6ICAgICAgI2ZmZiAhZGVmYXVsdDtcblxuXG4vLz09IE1vZGFsc1xuLy9cbi8vIyNcblxuLy8qKiBQYWRkaW5nIGFwcGxpZWQgdG8gdGhlIG1vZGFsIGJvZHlcbiRtb2RhbC1pbm5lci1wYWRkaW5nOiAgICAgICAgIDE1cHggIWRlZmF1bHQ7XG5cbi8vKiogUGFkZGluZyBhcHBsaWVkIHRvIHRoZSBtb2RhbCB0aXRsZVxuJG1vZGFsLXRpdGxlLXBhZGRpbmc6ICAgICAgICAgMTVweCAhZGVmYXVsdDtcbi8vKiogTW9kYWwgdGl0bGUgbGluZS1oZWlnaHRcbiRtb2RhbC10aXRsZS1saW5lLWhlaWdodDogICAgICRsaW5lLWhlaWdodC1iYXNlICFkZWZhdWx0O1xuXG4vLyoqIEJhY2tncm91bmQgY29sb3Igb2YgbW9kYWwgY29udGVudCBhcmVhXG4kbW9kYWwtY29udGVudC1iZzogICAgICAgICAgICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIE1vZGFsIGNvbnRlbnQgYm9yZGVyIGNvbG9yXG4kbW9kYWwtY29udGVudC1ib3JkZXItY29sb3I6ICAgICAgICAgICAgICAgICAgIHJnYmEoMCwwLDAsLjIpICFkZWZhdWx0O1xuLy8qKiBNb2RhbCBjb250ZW50IGJvcmRlciBjb2xvciAqKmZvciBJRTgqKlxuJG1vZGFsLWNvbnRlbnQtZmFsbGJhY2stYm9yZGVyLWNvbG9yOiAgICAgICAgICAjOTk5ICFkZWZhdWx0O1xuXG4vLyoqIE1vZGFsIGJhY2tkcm9wIGJhY2tncm91bmQgY29sb3JcbiRtb2RhbC1iYWNrZHJvcC1iZzogICAgICAgICAgICMwMDAgIWRlZmF1bHQ7XG4vLyoqIE1vZGFsIGJhY2tkcm9wIG9wYWNpdHlcbiRtb2RhbC1iYWNrZHJvcC1vcGFjaXR5OiAgICAgIC41ICFkZWZhdWx0O1xuLy8qKiBNb2RhbCBoZWFkZXIgYm9yZGVyIGNvbG9yXG4kbW9kYWwtaGVhZGVyLWJvcmRlci1jb2xvcjogICAjZTVlNWU1ICFkZWZhdWx0O1xuLy8qKiBNb2RhbCBmb290ZXIgYm9yZGVyIGNvbG9yXG4kbW9kYWwtZm9vdGVyLWJvcmRlci1jb2xvcjogICAkbW9kYWwtaGVhZGVyLWJvcmRlci1jb2xvciAhZGVmYXVsdDtcblxuJG1vZGFsLWxnOiAgICAgICAgICAgICAgICAgICAgOTAwcHggIWRlZmF1bHQ7XG4kbW9kYWwtbWQ6ICAgICAgICAgICAgICAgICAgICA2MDBweCAhZGVmYXVsdDtcbiRtb2RhbC1zbTogICAgICAgICAgICAgICAgICAgIDMwMHB4ICFkZWZhdWx0O1xuXG5cbi8vPT0gQWxlcnRzXG4vL1xuLy8jIyBEZWZpbmUgYWxlcnQgY29sb3JzLCBib3JkZXIgcmFkaXVzLCBhbmQgcGFkZGluZy5cblxuJGFsZXJ0LXBhZGRpbmc6ICAgICAgICAgICAgICAgMTVweCAhZGVmYXVsdDtcbiRhbGVydC1ib3JkZXItcmFkaXVzOiAgICAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG4kYWxlcnQtbGluay1mb250LXdlaWdodDogICAgICBib2xkICFkZWZhdWx0O1xuXG4kYWxlcnQtc3VjY2Vzcy1iZzogICAgICAgICAgICAkc3RhdGUtc3VjY2Vzcy1iZyAhZGVmYXVsdDtcbiRhbGVydC1zdWNjZXNzLXRleHQ6ICAgICAgICAgICRzdGF0ZS1zdWNjZXNzLXRleHQgIWRlZmF1bHQ7XG4kYWxlcnQtc3VjY2Vzcy1ib3JkZXI6ICAgICAgICAkc3RhdGUtc3VjY2Vzcy1ib3JkZXIgIWRlZmF1bHQ7XG5cbiRhbGVydC1pbmZvLWJnOiAgICAgICAgICAgICAgICRzdGF0ZS1pbmZvLWJnICFkZWZhdWx0O1xuJGFsZXJ0LWluZm8tdGV4dDogICAgICAgICAgICAgJHN0YXRlLWluZm8tdGV4dCAhZGVmYXVsdDtcbiRhbGVydC1pbmZvLWJvcmRlcjogICAgICAgICAgICRzdGF0ZS1pbmZvLWJvcmRlciAhZGVmYXVsdDtcblxuJGFsZXJ0LXdhcm5pbmctYmc6ICAgICAgICAgICAgJHN0YXRlLXdhcm5pbmctYmcgIWRlZmF1bHQ7XG4kYWxlcnQtd2FybmluZy10ZXh0OiAgICAgICAgICAkc3RhdGUtd2FybmluZy10ZXh0ICFkZWZhdWx0O1xuJGFsZXJ0LXdhcm5pbmctYm9yZGVyOiAgICAgICAgJHN0YXRlLXdhcm5pbmctYm9yZGVyICFkZWZhdWx0O1xuXG4kYWxlcnQtZGFuZ2VyLWJnOiAgICAgICAgICAgICAkc3RhdGUtZGFuZ2VyLWJnICFkZWZhdWx0O1xuJGFsZXJ0LWRhbmdlci10ZXh0OiAgICAgICAgICAgJHN0YXRlLWRhbmdlci10ZXh0ICFkZWZhdWx0O1xuJGFsZXJ0LWRhbmdlci1ib3JkZXI6ICAgICAgICAgJHN0YXRlLWRhbmdlci1ib3JkZXIgIWRlZmF1bHQ7XG5cblxuLy89PSBQcm9ncmVzcyBiYXJzXG4vL1xuLy8jI1xuXG4vLyoqIEJhY2tncm91bmQgY29sb3Igb2YgdGhlIHdob2xlIHByb2dyZXNzIGNvbXBvbmVudFxuJHByb2dyZXNzLWJnOiAgICAgICAgICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcbi8vKiogUHJvZ3Jlc3MgYmFyIHRleHQgY29sb3JcbiRwcm9ncmVzcy1iYXItY29sb3I6ICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIFZhcmlhYmxlIGZvciBzZXR0aW5nIHJvdW5kZWQgY29ybmVycyBvbiBwcm9ncmVzcyBiYXIuXG4kcHJvZ3Jlc3MtYm9yZGVyLXJhZGl1czogICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuXG4vLyoqIERlZmF1bHQgcHJvZ3Jlc3MgYmFyIGNvbG9yXG4kcHJvZ3Jlc3MtYmFyLWJnOiAgICAgICAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcbi8vKiogU3VjY2VzcyBwcm9ncmVzcyBiYXIgY29sb3JcbiRwcm9ncmVzcy1iYXItc3VjY2Vzcy1iZzogICAgICRicmFuZC1zdWNjZXNzICFkZWZhdWx0O1xuLy8qKiBXYXJuaW5nIHByb2dyZXNzIGJhciBjb2xvclxuJHByb2dyZXNzLWJhci13YXJuaW5nLWJnOiAgICAgJGJyYW5kLXdhcm5pbmcgIWRlZmF1bHQ7XG4vLyoqIERhbmdlciBwcm9ncmVzcyBiYXIgY29sb3JcbiRwcm9ncmVzcy1iYXItZGFuZ2VyLWJnOiAgICAgICRicmFuZC1kYW5nZXIgIWRlZmF1bHQ7XG4vLyoqIEluZm8gcHJvZ3Jlc3MgYmFyIGNvbG9yXG4kcHJvZ3Jlc3MtYmFyLWluZm8tYmc6ICAgICAgICAkYnJhbmQtaW5mbyAhZGVmYXVsdDtcblxuXG4vLz09IExpc3QgZ3JvdXBcbi8vXG4vLyMjXG5cbi8vKiogQmFja2dyb3VuZCBjb2xvciBvbiBgLmxpc3QtZ3JvdXAtaXRlbWBcbiRsaXN0LWdyb3VwLWJnOiAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogYC5saXN0LWdyb3VwLWl0ZW1gIGJvcmRlciBjb2xvclxuJGxpc3QtZ3JvdXAtYm9yZGVyOiAgICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuLy8qKiBMaXN0IGdyb3VwIGJvcmRlciByYWRpdXNcbiRsaXN0LWdyb3VwLWJvcmRlci1yYWRpdXM6ICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcblxuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9mIHNpbmdsZSBsaXN0IGl0ZW1zIG9uIGhvdmVyXG4kbGlzdC1ncm91cC1ob3Zlci1iZzogICAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG4vLyoqIFRleHQgY29sb3Igb2YgYWN0aXZlIGxpc3QgaXRlbXNcbiRsaXN0LWdyb3VwLWFjdGl2ZS1jb2xvcjogICAgICAgJGNvbXBvbmVudC1hY3RpdmUtY29sb3IgIWRlZmF1bHQ7XG4vLyoqIEJhY2tncm91bmQgY29sb3Igb2YgYWN0aXZlIGxpc3QgaXRlbXNcbiRsaXN0LWdyb3VwLWFjdGl2ZS1iZzogICAgICAgICAgJGNvbXBvbmVudC1hY3RpdmUtYmcgIWRlZmF1bHQ7XG4vLyoqIEJvcmRlciBjb2xvciBvZiBhY3RpdmUgbGlzdCBlbGVtZW50c1xuJGxpc3QtZ3JvdXAtYWN0aXZlLWJvcmRlcjogICAgICAkbGlzdC1ncm91cC1hY3RpdmUtYmcgIWRlZmF1bHQ7XG4vLyoqIFRleHQgY29sb3IgZm9yIGNvbnRlbnQgd2l0aGluIGFjdGl2ZSBsaXN0IGl0ZW1zXG4kbGlzdC1ncm91cC1hY3RpdmUtdGV4dC1jb2xvcjogIGxpZ2h0ZW4oJGxpc3QtZ3JvdXAtYWN0aXZlLWJnLCA0MCUpICFkZWZhdWx0O1xuXG4vLyoqIFRleHQgY29sb3Igb2YgZGlzYWJsZWQgbGlzdCBpdGVtc1xuJGxpc3QtZ3JvdXAtZGlzYWJsZWQtY29sb3I6ICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4vLyoqIEJhY2tncm91bmQgY29sb3Igb2YgZGlzYWJsZWQgbGlzdCBpdGVtc1xuJGxpc3QtZ3JvdXAtZGlzYWJsZWQtYmc6ICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcbi8vKiogVGV4dCBjb2xvciBmb3IgY29udGVudCB3aXRoaW4gZGlzYWJsZWQgbGlzdCBpdGVtc1xuJGxpc3QtZ3JvdXAtZGlzYWJsZWQtdGV4dC1jb2xvcjogJGxpc3QtZ3JvdXAtZGlzYWJsZWQtY29sb3IgIWRlZmF1bHQ7XG5cbiRsaXN0LWdyb3VwLWxpbmstY29sb3I6ICAgICAgICAgIzU1NSAhZGVmYXVsdDtcbiRsaXN0LWdyb3VwLWxpbmstaG92ZXItY29sb3I6ICAgJGxpc3QtZ3JvdXAtbGluay1jb2xvciAhZGVmYXVsdDtcbiRsaXN0LWdyb3VwLWxpbmstaGVhZGluZy1jb2xvcjogIzMzMyAhZGVmYXVsdDtcblxuXG4vLz09IFBhbmVsc1xuLy9cbi8vIyNcblxuJHBhbmVsLWJnOiAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRwYW5lbC1ib2R5LXBhZGRpbmc6ICAgICAgICAgIDE1cHggIWRlZmF1bHQ7XG4kcGFuZWwtaGVhZGluZy1wYWRkaW5nOiAgICAgICAxMHB4IDE1cHggIWRlZmF1bHQ7XG4kcGFuZWwtZm9vdGVyLXBhZGRpbmc6ICAgICAgICAkcGFuZWwtaGVhZGluZy1wYWRkaW5nICFkZWZhdWx0O1xuJHBhbmVsLWJvcmRlci1yYWRpdXM6ICAgICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcblxuLy8qKiBCb3JkZXIgY29sb3IgZm9yIGVsZW1lbnRzIHdpdGhpbiBwYW5lbHNcbiRwYW5lbC1pbm5lci1ib3JkZXI6ICAgICAgICAgICNkZGQgIWRlZmF1bHQ7XG4kcGFuZWwtZm9vdGVyLWJnOiAgICAgICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuXG4kcGFuZWwtZGVmYXVsdC10ZXh0OiAgICAgICAgICAkZ3JheS1kYXJrICFkZWZhdWx0O1xuJHBhbmVsLWRlZmF1bHQtYm9yZGVyOiAgICAgICAgI2RkZCAhZGVmYXVsdDtcbiRwYW5lbC1kZWZhdWx0LWhlYWRpbmctYmc6ICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG5cbiRwYW5lbC1wcmltYXJ5LXRleHQ6ICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kcGFuZWwtcHJpbWFyeS1ib3JkZXI6ICAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcbiRwYW5lbC1wcmltYXJ5LWhlYWRpbmctYmc6ICAgICRicmFuZC1wcmltYXJ5ICFkZWZhdWx0O1xuXG4kcGFuZWwtc3VjY2Vzcy10ZXh0OiAgICAgICAgICAkc3RhdGUtc3VjY2Vzcy10ZXh0ICFkZWZhdWx0O1xuJHBhbmVsLXN1Y2Nlc3MtYm9yZGVyOiAgICAgICAgJHN0YXRlLXN1Y2Nlc3MtYm9yZGVyICFkZWZhdWx0O1xuJHBhbmVsLXN1Y2Nlc3MtaGVhZGluZy1iZzogICAgJHN0YXRlLXN1Y2Nlc3MtYmcgIWRlZmF1bHQ7XG5cbiRwYW5lbC1pbmZvLXRleHQ6ICAgICAgICAgICAgICRzdGF0ZS1pbmZvLXRleHQgIWRlZmF1bHQ7XG4kcGFuZWwtaW5mby1ib3JkZXI6ICAgICAgICAgICAkc3RhdGUtaW5mby1ib3JkZXIgIWRlZmF1bHQ7XG4kcGFuZWwtaW5mby1oZWFkaW5nLWJnOiAgICAgICAkc3RhdGUtaW5mby1iZyAhZGVmYXVsdDtcblxuJHBhbmVsLXdhcm5pbmctdGV4dDogICAgICAgICAgJHN0YXRlLXdhcm5pbmctdGV4dCAhZGVmYXVsdDtcbiRwYW5lbC13YXJuaW5nLWJvcmRlcjogICAgICAgICRzdGF0ZS13YXJuaW5nLWJvcmRlciAhZGVmYXVsdDtcbiRwYW5lbC13YXJuaW5nLWhlYWRpbmctYmc6ICAgICRzdGF0ZS13YXJuaW5nLWJnICFkZWZhdWx0O1xuXG4kcGFuZWwtZGFuZ2VyLXRleHQ6ICAgICAgICAgICAkc3RhdGUtZGFuZ2VyLXRleHQgIWRlZmF1bHQ7XG4kcGFuZWwtZGFuZ2VyLWJvcmRlcjogICAgICAgICAkc3RhdGUtZGFuZ2VyLWJvcmRlciAhZGVmYXVsdDtcbiRwYW5lbC1kYW5nZXItaGVhZGluZy1iZzogICAgICRzdGF0ZS1kYW5nZXItYmcgIWRlZmF1bHQ7XG5cblxuLy89PSBUaHVtYm5haWxzXG4vL1xuLy8jI1xuXG4vLyoqIFBhZGRpbmcgYXJvdW5kIHRoZSB0aHVtYm5haWwgaW1hZ2VcbiR0aHVtYm5haWwtcGFkZGluZzogICAgICAgICAgIDRweCAhZGVmYXVsdDtcbi8vKiogVGh1bWJuYWlsIGJhY2tncm91bmQgY29sb3JcbiR0aHVtYm5haWwtYmc6ICAgICAgICAgICAgICAgICRib2R5LWJnICFkZWZhdWx0O1xuLy8qKiBUaHVtYm5haWwgYm9yZGVyIGNvbG9yXG4kdGh1bWJuYWlsLWJvcmRlcjogICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuLy8qKiBUaHVtYm5haWwgYm9yZGVyIHJhZGl1c1xuJHRodW1ibmFpbC1ib3JkZXItcmFkaXVzOiAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcblxuLy8qKiBDdXN0b20gdGV4dCBjb2xvciBmb3IgdGh1bWJuYWlsIGNhcHRpb25zXG4kdGh1bWJuYWlsLWNhcHRpb24tY29sb3I6ICAgICAkdGV4dC1jb2xvciAhZGVmYXVsdDtcbi8vKiogUGFkZGluZyBhcm91bmQgdGhlIHRodW1ibmFpbCBjYXB0aW9uXG4kdGh1bWJuYWlsLWNhcHRpb24tcGFkZGluZzogICA5cHggIWRlZmF1bHQ7XG5cblxuLy89PSBXZWxsc1xuLy9cbi8vIyNcblxuJHdlbGwtYmc6ICAgICAgICAgICAgICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcbiR3ZWxsLWJvcmRlcjogICAgICAgICAgICAgICAgIGRhcmtlbigkd2VsbC1iZywgNyUpICFkZWZhdWx0O1xuXG5cbi8vPT0gQmFkZ2VzXG4vL1xuLy8jI1xuXG4kYmFkZ2UtY29sb3I6ICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBMaW5rZWQgYmFkZ2UgdGV4dCBjb2xvciBvbiBob3ZlclxuJGJhZGdlLWxpbmstaG92ZXItY29sb3I6ICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRiYWRnZS1iZzogICAgICAgICAgICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuXG4vLyoqIEJhZGdlIHRleHQgY29sb3IgaW4gYWN0aXZlIG5hdiBsaW5rXG4kYmFkZ2UtYWN0aXZlLWNvbG9yOiAgICAgICAgICAkbGluay1jb2xvciAhZGVmYXVsdDtcbi8vKiogQmFkZ2UgYmFja2dyb3VuZCBjb2xvciBpbiBhY3RpdmUgbmF2IGxpbmtcbiRiYWRnZS1hY3RpdmUtYmc6ICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG5cbiRiYWRnZS1mb250LXdlaWdodDogICAgICAgICAgIGJvbGQgIWRlZmF1bHQ7XG4kYmFkZ2UtbGluZS1oZWlnaHQ6ICAgICAgICAgICAxICFkZWZhdWx0O1xuJGJhZGdlLWJvcmRlci1yYWRpdXM6ICAgICAgICAgMTBweCAhZGVmYXVsdDtcblxuXG4vLz09IEJyZWFkY3J1bWJzXG4vL1xuLy8jI1xuXG4kYnJlYWRjcnVtYi1wYWRkaW5nLXZlcnRpY2FsOiAgIDhweCAhZGVmYXVsdDtcbiRicmVhZGNydW1iLXBhZGRpbmctaG9yaXpvbnRhbDogMTVweCAhZGVmYXVsdDtcbi8vKiogQnJlYWRjcnVtYiBiYWNrZ3JvdW5kIGNvbG9yXG4kYnJlYWRjcnVtYi1iZzogICAgICAgICAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG4vLyoqIEJyZWFkY3J1bWIgdGV4dCBjb2xvclxuJGJyZWFkY3J1bWItY29sb3I6ICAgICAgICAgICAgICAjY2NjICFkZWZhdWx0O1xuLy8qKiBUZXh0IGNvbG9yIG9mIGN1cnJlbnQgcGFnZSBpbiB0aGUgYnJlYWRjcnVtYlxuJGJyZWFkY3J1bWItYWN0aXZlLWNvbG9yOiAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbi8vKiogVGV4dHVhbCBzZXBhcmF0b3IgZm9yIGJldHdlZW4gYnJlYWRjcnVtYiBlbGVtZW50c1xuJGJyZWFkY3J1bWItc2VwYXJhdG9yOiAgICAgICAgICBcIi9cIiAhZGVmYXVsdDtcblxuXG4vLz09IENhcm91c2VsXG4vL1xuLy8jI1xuXG4kY2Fyb3VzZWwtdGV4dC1zaGFkb3c6ICAgICAgICAgICAgICAgICAgICAgICAgMCAxcHggMnB4IHJnYmEoMCwwLDAsLjYpICFkZWZhdWx0O1xuXG4kY2Fyb3VzZWwtY29udHJvbC1jb2xvcjogICAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRjYXJvdXNlbC1jb250cm9sLXdpZHRoOiAgICAgICAgICAgICAgICAgICAgICAxNSUgIWRlZmF1bHQ7XG4kY2Fyb3VzZWwtY29udHJvbC1vcGFjaXR5OiAgICAgICAgICAgICAgICAgICAgLjUgIWRlZmF1bHQ7XG4kY2Fyb3VzZWwtY29udHJvbC1mb250LXNpemU6ICAgICAgICAgICAgICAgICAgMjBweCAhZGVmYXVsdDtcblxuJGNhcm91c2VsLWluZGljYXRvci1hY3RpdmUtYmc6ICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kY2Fyb3VzZWwtaW5kaWNhdG9yLWJvcmRlci1jb2xvcjogICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcblxuJGNhcm91c2VsLWNhcHRpb24tY29sb3I6ICAgICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG5cblxuLy89PSBDbG9zZVxuLy9cbi8vIyNcblxuJGNsb3NlLWZvbnQtd2VpZ2h0OiAgICAgICAgICAgYm9sZCAhZGVmYXVsdDtcbiRjbG9zZS1jb2xvcjogICAgICAgICAgICAgICAgICMwMDAgIWRlZmF1bHQ7XG4kY2xvc2UtdGV4dC1zaGFkb3c6ICAgICAgICAgICAwIDFweCAwICNmZmYgIWRlZmF1bHQ7XG5cblxuLy89PSBDb2RlXG4vL1xuLy8jI1xuXG4kY29kZS1jb2xvcjogICAgICAgICAgICAgICAgICAjYzcyNTRlICFkZWZhdWx0O1xuJGNvZGUtYmc6ICAgICAgICAgICAgICAgICAgICAgI2Y5ZjJmNCAhZGVmYXVsdDtcblxuJGtiZC1jb2xvcjogICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRrYmQtYmc6ICAgICAgICAgICAgICAgICAgICAgICMzMzMgIWRlZmF1bHQ7XG5cbiRwcmUtYmc6ICAgICAgICAgICAgICAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG4kcHJlLWNvbG9yOiAgICAgICAgICAgICAgICAgICAkZ3JheS1kYXJrICFkZWZhdWx0O1xuJHByZS1ib3JkZXItY29sb3I6ICAgICAgICAgICAgI2NjYyAhZGVmYXVsdDtcbiRwcmUtc2Nyb2xsYWJsZS1tYXgtaGVpZ2h0OiAgIDM0MHB4ICFkZWZhdWx0O1xuXG5cbi8vPT0gVHlwZVxuLy9cbi8vIyNcblxuLy8qKiBIb3Jpem9udGFsIG9mZnNldCBmb3IgZm9ybXMgYW5kIGxpc3RzLlxuJGNvbXBvbmVudC1vZmZzZXQtaG9yaXpvbnRhbDogMTgwcHggIWRlZmF1bHQ7XG4vLyoqIFRleHQgbXV0ZWQgY29sb3JcbiR0ZXh0LW11dGVkOiAgICAgICAgICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuLy8qKiBBYmJyZXZpYXRpb25zIGFuZCBhY3JvbnltcyBib3JkZXIgY29sb3JcbiRhYmJyLWJvcmRlci1jb2xvcjogICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuLy8qKiBIZWFkaW5ncyBzbWFsbCBjb2xvclxuJGhlYWRpbmdzLXNtYWxsLWNvbG9yOiAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4vLyoqIEJsb2NrcXVvdGUgc21hbGwgY29sb3JcbiRibG9ja3F1b3RlLXNtYWxsLWNvbG9yOiAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuLy8qKiBCbG9ja3F1b3RlIGZvbnQgc2l6ZVxuJGJsb2NrcXVvdGUtZm9udC1zaXplOiAgICAgICAgKCRmb250LXNpemUtYmFzZSAqIDEuMjUpICFkZWZhdWx0O1xuLy8qKiBCbG9ja3F1b3RlIGJvcmRlciBjb2xvclxuJGJsb2NrcXVvdGUtYm9yZGVyLWNvbG9yOiAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcbi8vKiogUGFnZSBoZWFkZXIgYm9yZGVyIGNvbG9yXG4kcGFnZS1oZWFkZXItYm9yZGVyLWNvbG9yOiAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuLy8qKiBXaWR0aCBvZiBob3Jpem9udGFsIGRlc2NyaXB0aW9uIGxpc3QgdGl0bGVzXG4kZGwtaG9yaXpvbnRhbC1vZmZzZXQ6ICAgICAgICAkY29tcG9uZW50LW9mZnNldC1ob3Jpem9udGFsICFkZWZhdWx0O1xuLy8qKiBQb2ludCBhdCB3aGljaCAuZGwtaG9yaXpvbnRhbCBiZWNvbWVzIGhvcml6b250YWxcbiRkbC1ob3Jpem9udGFsLWJyZWFrcG9pbnQ6ICAgICRncmlkLWZsb2F0LWJyZWFrcG9pbnQgIWRlZmF1bHQ7XG4vLyoqIEhvcml6b250YWwgbGluZSBjb2xvci5cbiRoci1ib3JkZXI6ICAgICAgICAgICAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG4iLCJAaW1wb3J0ICcuLi8uLi8uLi9zdHlsZXMvYW5pbWF0aW9ucy5zY3NzJztcblxueG9zLXRhYmxlIHtcblxuICBkaXNwbGF5OiBibG9jaztcblxuICB0ci5uZy1tb3ZlLFxuICB0ci5uZy1lbnRlcixcbiAgdHIubmctbGVhdmUge1xuICAgIHRyYW5zaXRpb246YWxsIGxpbmVhciAwLjVzO1xuICB9XG5cbiAgdHIubmctbGVhdmUubmctbGVhdmUtYWN0aXZlLFxuICB0ci5uZy1tb3ZlLFxuICB0ci5uZy1lbnRlciB7XG4gICAgb3BhY2l0eTowO1xuICAgIGFuaW1hdGlvbjogMC41cyBzbGlkZU91dFJpZ2h0IGVhc2UtaW4tb3V0O1xuICB9XG5cbiAgdHIubmctbGVhdmUsXG4gIHRyLm5nLW1vdmUubmctbW92ZS1hY3RpdmUsXG4gIHRyLm5nLWVudGVyLm5nLWVudGVyLWFjdGl2ZSB7XG4gICAgb3BhY2l0eToxO1xuICAgIGFuaW1hdGlvbjogMC41cyBzbGlkZUluUmlnaHQgZWFzZS1pbi1vdXQ7XG4gIH1cblxuICB0ZCBkbCB7XG4gICAgbWFyZ2luLWJvdHRvbTogMDtcblxuICAgIGR0IHtcbiAgICAgIHdpZHRoOiBhdXRvICFpbXBvcnRhbnQ7XG4gICAgICBtYXJnaW4tcmlnaHQ6IDEwcHg7XG4gICAgfVxuICAgIFxuICAgIGR0OmFmdGVyIHtcbiAgICAgIC8qZGlzcGxheTogYmxvY2s7Ki9cbiAgICAgIGNvbnRlbnQ6ICc6JztcbiAgICB9XG5cbiAgICBkZCB7XG4gICAgICBtYXJnaW4tbGVmdDogMCAhaW1wb3J0YW50O1xuICAgIH1cbiAgfVxufSIsIkBpbXBvcnQgJy4uLy4uLy4uL3N0eWxlcy9hbmltYXRpb25zLnNjc3MnO1xuXG54b3MtYWxlcnQge1xuXG4gIC8qIHdoZW4gaGlkaW5nICovXG4gIC5uZy1oaWRlLWFkZCAgICAgICAgIHsgYW5pbWF0aW9uOjAuNXMgZmFkZU91dERvd24gZWFzZS1pbi1vdXQ7IH1cblxuICAvKiB3aGVuIHNob3dpbmcgKi9cbiAgLm5nLWhpZGUtcmVtb3ZlICAgICAgeyBhbmltYXRpb246MC41cyBmYWRlSW5VcCBlYXNlLWluLW91dDsgfVxufSIsIkBpbXBvcnQgJy4uLy4uLy4uL3N0eWxlcy9hbmltYXRpb25zLnNjc3MnO1xuQGltcG9ydCAnLi4vLi4vLi4vLi4vLi4vLi4vc3R5bGUvc2Fzcy9ib290c3RyYXAvYm9vdHN0cmFwL192YXJpYWJsZXMuc2Nzcyc7XG5cbmlucHV0ICsgeG9zLXZhbGlkYXRpb24ge1xuICBtYXJnaW4tdG9wOiAkZm9ybS1ncm91cC1tYXJnaW4tYm90dG9tO1xuICBkaXNwbGF5OiBibG9jaztcbn0iLCJ4b3Mtc21hcnQtdGFibGV7XG4gIFxufSJdLCJtYXBwaW5ncyI6IkFDQUEsVUFBVSxDQUFWLFlBQVU7RUFDUixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsdUJBQVc7SUFDdEIsVUFBVSxFQUFFLE9BQVE7RUFHdEIsQUFBQSxFQUFFO0lBQ0EsU0FBUyxFQUFFLG9CQUFXOztBQUkxQixVQUFVLENBQVYsYUFBVTtFQUNSLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSxvQkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxVQUFVLEVBQUUsTUFBTztJQUNuQixTQUFTLEVBQUUsdUJBQVc7O0FBSTFCLFVBQVUsQ0FBVixRQUFVO0VBQ1IsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsSUFBSzs7QUFJcEIsVUFBVSxDQUFWLFdBQVU7RUFDUixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtFQUdiLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXOztBQXpDMUIsVUFBVSxDQUFWLFlBQVU7RUFDUixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsdUJBQVc7SUFDdEIsVUFBVSxFQUFFLE9BQVE7RUFHdEIsQUFBQSxFQUFFO0lBQ0EsU0FBUyxFQUFFLG9CQUFXOztBQUkxQixVQUFVLENBQVYsYUFBVTtFQUNSLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSxvQkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxVQUFVLEVBQUUsTUFBTztJQUNuQixTQUFTLEVBQUUsdUJBQVc7O0FBSTFCLFVBQVUsQ0FBVixRQUFVO0VBQ1IsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsSUFBSzs7QUFJcEIsVUFBVSxDQUFWLFdBQVU7RUFDUixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtFQUdiLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXOztBRXZDMUIsQUFBQSxTQUFTLENBQUM7RUFFUixPQUFPLEVBQUUsS0FBTSxHQXVDaEI7RUF6Q0QsQUFJSSxTQUpLLENBSVAsRUFBRSxBQUFBLFFBQVE7RUFKWixBQUtJLFNBTEssQ0FLUCxFQUFFLEFBQUEsU0FBUztFQUxiLEFBTUksU0FOSyxDQU1QLEVBQUUsQUFBQSxTQUFTLENBQUM7SUFDVixVQUFVLEVBQUMsZUFBZ0IsR0FDNUI7RUFSSCxBQVVhLFNBVkosQ0FVUCxFQUFFLEFBQUEsU0FBUyxBQUFBLGdCQUFnQjtFQVY3QixBQVdJLFNBWEssQ0FXUCxFQUFFLEFBQUEsUUFBUTtFQVhaLEFBWUksU0FaSyxDQVlQLEVBQUUsQUFBQSxTQUFTLENBQUM7SUFDVixPQUFPLEVBQUMsQ0FBRTtJQUNWLFNBQVMsRUFBRSw4QkFBK0IsR0FDM0M7RUFmSCxBQWlCSSxTQWpCSyxDQWlCUCxFQUFFLEFBQUEsU0FBUztFQWpCYixBQWtCWSxTQWxCSCxDQWtCUCxFQUFFLEFBQUEsUUFBUSxBQUFBLGVBQWU7RUFsQjNCLEFBbUJhLFNBbkJKLENBbUJQLEVBQUUsQUFBQSxTQUFTLEFBQUEsZ0JBQWdCLENBQUM7SUFDMUIsT0FBTyxFQUFDLENBQUU7SUFDVixTQUFTLEVBQUUsNkJBQThCLEdBQzFDO0VBdEJILEFBd0JLLFNBeEJJLENBd0JQLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDSixhQUFhLEVBQUUsQ0FBRSxHQWVsQjtJQXhDSCxBQTJCSSxTQTNCSyxDQXdCUCxFQUFFLENBQUMsRUFBRSxDQUdILEVBQUUsQ0FBQztNQUNELEtBQUssRUFBRSxlQUFnQjtNQUN2QixZQUFZLEVBQUUsSUFBSyxHQUNwQjtJQTlCTCxBQWdDTSxTQWhDRyxDQXdCUCxFQUFFLENBQUMsRUFBRSxDQVFILEVBQUUsQUFBQSxNQUFNLENBQUM7TUFDUCxtQkFBbUI7TUFDbkIsT0FBTyxFQUFFLEdBQUksR0FDZDtJQW5DTCxBQXFDSSxTQXJDSyxDQXdCUCxFQUFFLENBQUMsRUFBRSxDQWFILEVBQUUsQ0FBQztNQUNELFdBQVcsRUFBRSxZQUFhLEdBQzNCOztBRnpDTCxVQUFVLENBQVYsWUFBVTtFQUNSLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSx1QkFBVztJQUN0QixVQUFVLEVBQUUsT0FBUTtFQUd0QixBQUFBLEVBQUU7SUFDQSxTQUFTLEVBQUUsb0JBQVc7O0FBSTFCLFVBQVUsQ0FBVixhQUFVO0VBQ1IsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLG9CQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLFVBQVUsRUFBRSxNQUFPO0lBQ25CLFNBQVMsRUFBRSx1QkFBVzs7QUFJMUIsVUFBVSxDQUFWLFFBQVU7RUFDUixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSxJQUFLOztBQUlwQixVQUFVLENBQVYsV0FBVTtFQUNSLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0VBR2IsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7O0FHdkMxQixBQUFBLFNBQVMsQ0FBQztFQUVSLGlCQUFpQjtFQUdqQixrQkFBa0IsRUFFbkI7RUFQRCxBQUdFLFNBSE8sQ0FHUCxZQUFZLENBQVM7SUFBRSxTQUFTLEVBQUMsNEJBQTZCLEdBQUk7RUFIcEUsQUFNRSxTQU5PLENBTVAsZUFBZSxDQUFNO0lBQUUsU0FBUyxFQUFDLHlCQUEwQixHQUFJOztBSFJqRSxVQUFVLENBQVYsWUFBVTtFQUNSLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSx1QkFBVztJQUN0QixVQUFVLEVBQUUsT0FBUTtFQUd0QixBQUFBLEVBQUU7SUFDQSxTQUFTLEVBQUUsb0JBQVc7O0FBSTFCLFVBQVUsQ0FBVixhQUFVO0VBQ1IsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLG9CQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLFVBQVUsRUFBRSxNQUFPO0lBQ25CLFNBQVMsRUFBRSx1QkFBVzs7QUFJMUIsVUFBVSxDQUFWLFFBQVU7RUFDUixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSxJQUFLOztBQUlwQixVQUFVLENBQVYsV0FBVTtFQUNSLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0VBR2IsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7O0FJdEMxQixBQUFRLEtBQUgsR0FBRyxjQUFjLENBQUM7RUFDckIsVUFBVSxFSHdOcUIsSUFBSTtFR3ZObkMsT0FBTyxFQUFFLEtBQU0sR0FDaEI7O0NMR0QsQUFBQSxBQUFVLFNBQVQsQUFBQSxJQUFZLEFBQUEsQUFBUyxRQUFSLEFBQUEsSUFBVyxBQUFBLEFBQWMsYUFBYixBQUFBLElBQWdCLEFBQUEsQUFBVyxVQUFWLEFBQUEsR0FBYSxBQUFBLFNBQVMsRUFBRSxBQUFBLFdBQVcsQ0FBQztFQUM3RSxPQUFPLEVBQUUsZUFBZ0IsR0FDMUI7O0FBRUQsQUFBTyxJQUFILEdBQUcsSUFBSSxDQUFDO0VBQ1YsMEJBQTBCO0VBQzFCLFVBQVUsRUU2TXFCLElBQUksR0Y1TXBDIiwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiL3NvdXJjZS8ifQ== */
+/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieG9zTmdMaWIuY3NzIiwic291cmNlcyI6WyJtYWluLnNjc3MiLCJhbmltYXRpb25zLnNjc3MiLCIuLi8uLi8uLi8uLi9zdHlsZS9zYXNzL2Jvb3RzdHJhcC9ib290c3RyYXAvX3ZhcmlhYmxlcy5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy90YWJsZS90YWJsZS5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9hbGVydC9hbGVydC5zY3NzIiwiLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy92YWxpZGF0aW9uL3ZhbGlkYXRpb24uc2NzcyIsIi4uL3VpX2NvbXBvbmVudHMvZHVtYkNvbXBvbmVudHMvZmllbGQvZmllbGQuc2NzcyIsIi4uL3VpX2NvbXBvbmVudHMvc21hcnRDb21wb25lbnRzL3NtYXJ0VGFibGUvc21hcnRUYWJsZS5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgJy4vYW5pbWF0aW9ucy5zY3NzJztcbkBpbXBvcnQgJy4uLy4uLy4uLy4uLy4uL3ZpZXdzL3N0eWxlL3Nhc3MvYm9vdHN0cmFwL2Jvb3RzdHJhcC9fdmFyaWFibGVzLnNjc3MnO1xuXG5AaW1wb3J0ICcuLi91aV9jb21wb25lbnRzL2R1bWJDb21wb25lbnRzL3RhYmxlL3RhYmxlLnNjc3MnO1xuQGltcG9ydCAnLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9hbGVydC9hbGVydC5zY3NzJztcbkBpbXBvcnQgJy4uL3VpX2NvbXBvbmVudHMvZHVtYkNvbXBvbmVudHMvdmFsaWRhdGlvbi92YWxpZGF0aW9uLnNjc3MnO1xuQGltcG9ydCAnLi4vdWlfY29tcG9uZW50cy9kdW1iQ29tcG9uZW50cy9maWVsZC9maWVsZC5zY3NzJztcblxuQGltcG9ydCAnLi4vdWlfY29tcG9uZW50cy9zbWFydENvbXBvbmVudHMvc21hcnRUYWJsZS9zbWFydFRhYmxlLnNjc3MnO1xuXG5bbmdcXDpjbG9ha10sIFtuZy1jbG9ha10sIFtkYXRhLW5nLWNsb2FrXSwgW3gtbmctY2xvYWtdLCAubmctY2xvYWssIC54LW5nLWNsb2FrIHtcbiAgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50O1xufVxuXG4ucm93ICsgLnJvdyB7XG4gIC8qIFRPRE8gbW92ZSBpbiB4b3Muc2NzcyovIFxuICBtYXJnaW4tdG9wOiAkZm9ybS1ncm91cC1tYXJnaW4tYm90dG9tO1xufSIsIkBrZXlmcmFtZXMgc2xpZGVJblJpZ2h0IHtcbiAgZnJvbSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzZCgxMDAlLCAwLCAwKTtcbiAgICB2aXNpYmlsaXR5OiB2aXNpYmxlO1xuICB9XG5cbiAgdG8ge1xuICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMCwgMCwgMCk7XG4gIH1cbn1cblxuQGtleWZyYW1lcyBzbGlkZU91dFJpZ2h0IHtcbiAgZnJvbSB7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzZCgwLCAwLCAwKTtcbiAgfVxuXG4gIHRvIHtcbiAgICB2aXNpYmlsaXR5OiBoaWRkZW47XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzZCgxMDAlLCAwLCAwKTtcbiAgfVxufVxuXG5Aa2V5ZnJhbWVzIGZhZGVJblVwIHtcbiAgZnJvbSB7XG4gICAgb3BhY2l0eTogMDtcbiAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZTNkKDAsIDEwMCUsIDApO1xuICB9XG5cbiAgdG8ge1xuICAgIG9wYWNpdHk6IDE7XG4gICAgdHJhbnNmb3JtOiBub25lO1xuICB9XG59XG5cbkBrZXlmcmFtZXMgZmFkZU91dERvd24ge1xuICBmcm9tIHtcbiAgICBvcGFjaXR5OiAxO1xuICB9XG5cbiAgdG8ge1xuICAgIG9wYWNpdHk6IDA7XG4gICAgdHJhbnNmb3JtOiB0cmFuc2xhdGUzZCgwLCAxMDAlLCAwKTtcbiAgfVxufSIsIiRib290c3RyYXAtc2Fzcy1hc3NldC1oZWxwZXI6IGZhbHNlICFkZWZhdWx0O1xuLy9cbi8vIFZhcmlhYmxlc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4vLz09IENvbG9yc1xuLy9cbi8vIyMgR3JheSBhbmQgYnJhbmQgY29sb3JzIGZvciB1c2UgYWNyb3NzIEJvb3RzdHJhcC5cblxuJGdyYXktYmFzZTogICAgICAgICAgICAgICMwMDAgIWRlZmF1bHQ7XG4kZ3JheS1kYXJrZXI6ICAgICAgICAgICAgbGlnaHRlbigkZ3JheS1iYXNlLCAxMy41JSkgIWRlZmF1bHQ7IC8vICMyMjJcbiRncmF5LWRhcms6ICAgICAgICAgICAgICBsaWdodGVuKCRncmF5LWJhc2UsIDIwJSkgIWRlZmF1bHQ7ICAgLy8gIzMzM1xuJGdyYXk6ICAgICAgICAgICAgICAgICAgIGxpZ2h0ZW4oJGdyYXktYmFzZSwgMzMuNSUpICFkZWZhdWx0OyAvLyAjNTU1XG4kZ3JheS1saWdodDogICAgICAgICAgICAgbGlnaHRlbigkZ3JheS1iYXNlLCA0Ni43JSkgIWRlZmF1bHQ7IC8vICM3NzdcbiRncmF5LWxpZ2h0ZXI6ICAgICAgICAgICBsaWdodGVuKCRncmF5LWJhc2UsIDkzLjUlKSAhZGVmYXVsdDsgLy8gI2VlZVxuXG4kYnJhbmQtcHJpbWFyeTogICAgICAgICBkYXJrZW4oIzQyOGJjYSwgNi41JSkgIWRlZmF1bHQ7IC8vICMzMzdhYjdcbiRicmFuZC1zdWNjZXNzOiAgICAgICAgICM1Y2I4NWMgIWRlZmF1bHQ7XG4kYnJhbmQtaW5mbzogICAgICAgICAgICAjNWJjMGRlICFkZWZhdWx0O1xuJGJyYW5kLXdhcm5pbmc6ICAgICAgICAgI2YwYWQ0ZSAhZGVmYXVsdDtcbiRicmFuZC1kYW5nZXI6ICAgICAgICAgICNkOTUzNGYgIWRlZmF1bHQ7XG5cblxuLy89PSBTY2FmZm9sZGluZ1xuLy9cbi8vIyMgU2V0dGluZ3MgZm9yIHNvbWUgb2YgdGhlIG1vc3QgZ2xvYmFsIHN0eWxlcy5cblxuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIGZvciBgPGJvZHk+YC5cbiRib2R5LWJnOiAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIEdsb2JhbCB0ZXh0IGNvbG9yIG9uIGA8Ym9keT5gLlxuJHRleHQtY29sb3I6ICAgICAgICAgICAgJGdyYXktZGFyayAhZGVmYXVsdDtcblxuLy8qKiBHbG9iYWwgdGV4dHVhbCBsaW5rIGNvbG9yLlxuJGxpbmstY29sb3I6ICAgICAgICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG4vLyoqIExpbmsgaG92ZXIgY29sb3Igc2V0IHZpYSBgZGFya2VuKClgIGZ1bmN0aW9uLlxuJGxpbmstaG92ZXItY29sb3I6ICAgICAgZGFya2VuKCRsaW5rLWNvbG9yLCAxNSUpICFkZWZhdWx0O1xuLy8qKiBMaW5rIGhvdmVyIGRlY29yYXRpb24uXG4kbGluay1ob3Zlci1kZWNvcmF0aW9uOiB1bmRlcmxpbmUgIWRlZmF1bHQ7XG5cblxuLy89PSBUeXBvZ3JhcGh5XG4vL1xuLy8jIyBGb250LCBsaW5lLWhlaWdodCwgYW5kIGNvbG9yIGZvciBib2R5IHRleHQsIGhlYWRpbmdzLCBhbmQgbW9yZS5cblxuJGZvbnQtZmFtaWx5LXNhbnMtc2VyaWY6ICBcIkhlbHZldGljYSBOZXVlXCIsIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYgIWRlZmF1bHQ7XG4kZm9udC1mYW1pbHktc2VyaWY6ICAgICAgIEdlb3JnaWEsIFwiVGltZXMgTmV3IFJvbWFuXCIsIFRpbWVzLCBzZXJpZiAhZGVmYXVsdDtcbi8vKiogRGVmYXVsdCBtb25vc3BhY2UgZm9udHMgZm9yIGA8Y29kZT5gLCBgPGtiZD5gLCBhbmQgYDxwcmU+YC5cbiRmb250LWZhbWlseS1tb25vc3BhY2U6ICAgTWVubG8sIE1vbmFjbywgQ29uc29sYXMsIFwiQ291cmllciBOZXdcIiwgbW9ub3NwYWNlICFkZWZhdWx0O1xuJGZvbnQtZmFtaWx5LWJhc2U6ICAgICAgICAkZm9udC1mYW1pbHktc2Fucy1zZXJpZiAhZGVmYXVsdDtcblxuJGZvbnQtc2l6ZS1iYXNlOiAgICAgICAgICAxNHB4ICFkZWZhdWx0O1xuJGZvbnQtc2l6ZS1sYXJnZTogICAgICAgICBjZWlsKCgkZm9udC1zaXplLWJhc2UgKiAxLjI1KSkgIWRlZmF1bHQ7IC8vIH4xOHB4XG4kZm9udC1zaXplLXNtYWxsOiAgICAgICAgIGNlaWwoKCRmb250LXNpemUtYmFzZSAqIDAuODUpKSAhZGVmYXVsdDsgLy8gfjEycHhcblxuJGZvbnQtc2l6ZS1oMTogICAgICAgICAgICBmbG9vcigoJGZvbnQtc2l6ZS1iYXNlICogMi42KSkgIWRlZmF1bHQ7IC8vIH4zNnB4XG4kZm9udC1zaXplLWgyOiAgICAgICAgICAgIGZsb29yKCgkZm9udC1zaXplLWJhc2UgKiAyLjE1KSkgIWRlZmF1bHQ7IC8vIH4zMHB4XG4kZm9udC1zaXplLWgzOiAgICAgICAgICAgIGNlaWwoKCRmb250LXNpemUtYmFzZSAqIDEuNykpICFkZWZhdWx0OyAvLyB+MjRweFxuJGZvbnQtc2l6ZS1oNDogICAgICAgICAgICBjZWlsKCgkZm9udC1zaXplLWJhc2UgKiAxLjI1KSkgIWRlZmF1bHQ7IC8vIH4xOHB4XG4kZm9udC1zaXplLWg1OiAgICAgICAgICAgICRmb250LXNpemUtYmFzZSAhZGVmYXVsdDtcbiRmb250LXNpemUtaDY6ICAgICAgICAgICAgY2VpbCgoJGZvbnQtc2l6ZS1iYXNlICogMC44NSkpICFkZWZhdWx0OyAvLyB+MTJweFxuXG4vLyoqIFVuaXQtbGVzcyBgbGluZS1oZWlnaHRgIGZvciB1c2UgaW4gY29tcG9uZW50cyBsaWtlIGJ1dHRvbnMuXG4kbGluZS1oZWlnaHQtYmFzZTogICAgICAgIDEuNDI4NTcxNDI5ICFkZWZhdWx0OyAvLyAyMC8xNFxuLy8qKiBDb21wdXRlZCBcImxpbmUtaGVpZ2h0XCIgKGBmb250LXNpemVgICogYGxpbmUtaGVpZ2h0YCkgZm9yIHVzZSB3aXRoIGBtYXJnaW5gLCBgcGFkZGluZ2AsIGV0Yy5cbiRsaW5lLWhlaWdodC1jb21wdXRlZDogICAgZmxvb3IoKCRmb250LXNpemUtYmFzZSAqICRsaW5lLWhlaWdodC1iYXNlKSkgIWRlZmF1bHQ7IC8vIH4yMHB4XG5cbi8vKiogQnkgZGVmYXVsdCwgdGhpcyBpbmhlcml0cyBmcm9tIHRoZSBgPGJvZHk+YC5cbiRoZWFkaW5ncy1mb250LWZhbWlseTogICAgaW5oZXJpdCAhZGVmYXVsdDtcbiRoZWFkaW5ncy1mb250LXdlaWdodDogICAgNTAwICFkZWZhdWx0O1xuJGhlYWRpbmdzLWxpbmUtaGVpZ2h0OiAgICAxLjEgIWRlZmF1bHQ7XG4kaGVhZGluZ3MtY29sb3I6ICAgICAgICAgIGluaGVyaXQgIWRlZmF1bHQ7XG5cblxuLy89PSBJY29ub2dyYXBoeVxuLy9cbi8vIyMgU3BlY2lmeSBjdXN0b20gbG9jYXRpb24gYW5kIGZpbGVuYW1lIG9mIHRoZSBpbmNsdWRlZCBHbHlwaGljb25zIGljb24gZm9udC4gVXNlZnVsIGZvciB0aG9zZSBpbmNsdWRpbmcgQm9vdHN0cmFwIHZpYSBCb3dlci5cblxuLy8qKiBMb2FkIGZvbnRzIGZyb20gdGhpcyBkaXJlY3RvcnkuXG5cbi8vIFtjb252ZXJ0ZXJdIElmICRib290c3RyYXAtc2Fzcy1hc3NldC1oZWxwZXIgaWYgdXNlZCwgcHJvdmlkZSBwYXRoIHJlbGF0aXZlIHRvIHRoZSBhc3NldHMgbG9hZCBwYXRoLlxuLy8gW2NvbnZlcnRlcl0gVGhpcyBpcyBiZWNhdXNlIHNvbWUgYXNzZXQgaGVscGVycywgc3VjaCBhcyBTcHJvY2tldHMsIGRvIG5vdCB3b3JrIHdpdGggZmlsZS1yZWxhdGl2ZSBwYXRocy5cbiRpY29uLWZvbnQtcGF0aDogaWYoJGJvb3RzdHJhcC1zYXNzLWFzc2V0LWhlbHBlciwgXCJib290c3RyYXAvXCIsIFwiLi4vZm9udHMvYm9vdHN0cmFwL1wiKSAhZGVmYXVsdDtcblxuLy8qKiBGaWxlIG5hbWUgZm9yIGFsbCBmb250IGZpbGVzLlxuJGljb24tZm9udC1uYW1lOiAgICAgICAgICBcImdseXBoaWNvbnMtaGFsZmxpbmdzLXJlZ3VsYXJcIiAhZGVmYXVsdDtcbi8vKiogRWxlbWVudCBJRCB3aXRoaW4gU1ZHIGljb24gZmlsZS5cbiRpY29uLWZvbnQtc3ZnLWlkOiAgICAgICAgXCJnbHlwaGljb25zX2hhbGZsaW5nc3JlZ3VsYXJcIiAhZGVmYXVsdDtcblxuXG4vLz09IENvbXBvbmVudHNcbi8vXG4vLyMjIERlZmluZSBjb21tb24gcGFkZGluZyBhbmQgYm9yZGVyIHJhZGl1cyBzaXplcyBhbmQgbW9yZS4gVmFsdWVzIGJhc2VkIG9uIDE0cHggdGV4dCBhbmQgMS40MjggbGluZS1oZWlnaHQgKH4yMHB4IHRvIHN0YXJ0KS5cblxuJHBhZGRpbmctYmFzZS12ZXJ0aWNhbDogICAgIDZweCAhZGVmYXVsdDtcbiRwYWRkaW5nLWJhc2UtaG9yaXpvbnRhbDogICAxMnB4ICFkZWZhdWx0O1xuXG4kcGFkZGluZy1sYXJnZS12ZXJ0aWNhbDogICAgMTBweCAhZGVmYXVsdDtcbiRwYWRkaW5nLWxhcmdlLWhvcml6b250YWw6ICAxNnB4ICFkZWZhdWx0O1xuXG4kcGFkZGluZy1zbWFsbC12ZXJ0aWNhbDogICAgNXB4ICFkZWZhdWx0O1xuJHBhZGRpbmctc21hbGwtaG9yaXpvbnRhbDogIDEwcHggIWRlZmF1bHQ7XG5cbiRwYWRkaW5nLXhzLXZlcnRpY2FsOiAgICAgICAxcHggIWRlZmF1bHQ7XG4kcGFkZGluZy14cy1ob3Jpem9udGFsOiAgICAgNXB4ICFkZWZhdWx0O1xuXG4kbGluZS1oZWlnaHQtbGFyZ2U6ICAgICAgICAgMS4zMzMzMzMzICFkZWZhdWx0OyAvLyBleHRyYSBkZWNpbWFscyBmb3IgV2luIDguMSBDaHJvbWVcbiRsaW5lLWhlaWdodC1zbWFsbDogICAgICAgICAxLjUgIWRlZmF1bHQ7XG5cbiRib3JkZXItcmFkaXVzLWJhc2U6ICAgICAgICA0cHggIWRlZmF1bHQ7XG4kYm9yZGVyLXJhZGl1cy1sYXJnZTogICAgICAgNnB4ICFkZWZhdWx0O1xuJGJvcmRlci1yYWRpdXMtc21hbGw6ICAgICAgIDNweCAhZGVmYXVsdDtcblxuLy8qKiBHbG9iYWwgY29sb3IgZm9yIGFjdGl2ZSBpdGVtcyAoZS5nLiwgbmF2cyBvciBkcm9wZG93bnMpLlxuJGNvbXBvbmVudC1hY3RpdmUtY29sb3I6ICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIEdsb2JhbCBiYWNrZ3JvdW5kIGNvbG9yIGZvciBhY3RpdmUgaXRlbXMgKGUuZy4sIG5hdnMgb3IgZHJvcGRvd25zKS5cbiRjb21wb25lbnQtYWN0aXZlLWJnOiAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcblxuLy8qKiBXaWR0aCBvZiB0aGUgYGJvcmRlcmAgZm9yIGdlbmVyYXRpbmcgY2FyZXRzIHRoYXQgaW5kaWNhdG9yIGRyb3Bkb3ducy5cbiRjYXJldC13aWR0aC1iYXNlOiAgICAgICAgICA0cHggIWRlZmF1bHQ7XG4vLyoqIENhcmV0cyBpbmNyZWFzZSBzbGlnaHRseSBpbiBzaXplIGZvciBsYXJnZXIgY29tcG9uZW50cy5cbiRjYXJldC13aWR0aC1sYXJnZTogICAgICAgICA1cHggIWRlZmF1bHQ7XG5cblxuLy89PSBUYWJsZXNcbi8vXG4vLyMjIEN1c3RvbWl6ZXMgdGhlIGAudGFibGVgIGNvbXBvbmVudCB3aXRoIGJhc2ljIHZhbHVlcywgZWFjaCB1c2VkIGFjcm9zcyBhbGwgdGFibGUgdmFyaWF0aW9ucy5cblxuLy8qKiBQYWRkaW5nIGZvciBgPHRoPmBzIGFuZCBgPHRkPmBzLlxuJHRhYmxlLWNlbGwtcGFkZGluZzogICAgICAgICAgICA4cHggIWRlZmF1bHQ7XG4vLyoqIFBhZGRpbmcgZm9yIGNlbGxzIGluIGAudGFibGUtY29uZGVuc2VkYC5cbiR0YWJsZS1jb25kZW5zZWQtY2VsbC1wYWRkaW5nOiAgNXB4ICFkZWZhdWx0O1xuXG4vLyoqIERlZmF1bHQgYmFja2dyb3VuZCBjb2xvciB1c2VkIGZvciBhbGwgdGFibGVzLlxuJHRhYmxlLWJnOiAgICAgICAgICAgICAgICAgICAgICB0cmFuc3BhcmVudCAhZGVmYXVsdDtcbi8vKiogQmFja2dyb3VuZCBjb2xvciB1c2VkIGZvciBgLnRhYmxlLXN0cmlwZWRgLlxuJHRhYmxlLWJnLWFjY2VudDogICAgICAgICAgICAgICAjZjlmOWY5ICFkZWZhdWx0O1xuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIHVzZWQgZm9yIGAudGFibGUtaG92ZXJgLlxuJHRhYmxlLWJnLWhvdmVyOiAgICAgICAgICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuJHRhYmxlLWJnLWFjdGl2ZTogICAgICAgICAgICAgICAkdGFibGUtYmctaG92ZXIgIWRlZmF1bHQ7XG5cbi8vKiogQm9yZGVyIGNvbG9yIGZvciB0YWJsZSBhbmQgY2VsbCBib3JkZXJzLlxuJHRhYmxlLWJvcmRlci1jb2xvcjogICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuXG5cbi8vPT0gQnV0dG9uc1xuLy9cbi8vIyMgRm9yIGVhY2ggb2YgQm9vdHN0cmFwJ3MgYnV0dG9ucywgZGVmaW5lIHRleHQsIGJhY2tncm91bmQgYW5kIGJvcmRlciBjb2xvci5cblxuJGJ0bi1mb250LXdlaWdodDogICAgICAgICAgICAgICAgbm9ybWFsICFkZWZhdWx0O1xuXG4kYnRuLWRlZmF1bHQtY29sb3I6ICAgICAgICAgICAgICAjMzMzICFkZWZhdWx0O1xuJGJ0bi1kZWZhdWx0LWJnOiAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRidG4tZGVmYXVsdC1ib3JkZXI6ICAgICAgICAgICAgICNjY2MgIWRlZmF1bHQ7XG5cbiRidG4tcHJpbWFyeS1jb2xvcjogICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kYnRuLXByaW1hcnktYmc6ICAgICAgICAgICAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcbiRidG4tcHJpbWFyeS1ib3JkZXI6ICAgICAgICAgICAgIGRhcmtlbigkYnRuLXByaW1hcnktYmcsIDUlKSAhZGVmYXVsdDtcblxuJGJ0bi1zdWNjZXNzLWNvbG9yOiAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRidG4tc3VjY2Vzcy1iZzogICAgICAgICAgICAgICAgICRicmFuZC1zdWNjZXNzICFkZWZhdWx0O1xuJGJ0bi1zdWNjZXNzLWJvcmRlcjogICAgICAgICAgICAgZGFya2VuKCRidG4tc3VjY2Vzcy1iZywgNSUpICFkZWZhdWx0O1xuXG4kYnRuLWluZm8tY29sb3I6ICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGJ0bi1pbmZvLWJnOiAgICAgICAgICAgICAgICAgICAgJGJyYW5kLWluZm8gIWRlZmF1bHQ7XG4kYnRuLWluZm8tYm9yZGVyOiAgICAgICAgICAgICAgICBkYXJrZW4oJGJ0bi1pbmZvLWJnLCA1JSkgIWRlZmF1bHQ7XG5cbiRidG4td2FybmluZy1jb2xvcjogICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kYnRuLXdhcm5pbmctYmc6ICAgICAgICAgICAgICAgICAkYnJhbmQtd2FybmluZyAhZGVmYXVsdDtcbiRidG4td2FybmluZy1ib3JkZXI6ICAgICAgICAgICAgIGRhcmtlbigkYnRuLXdhcm5pbmctYmcsIDUlKSAhZGVmYXVsdDtcblxuJGJ0bi1kYW5nZXItY29sb3I6ICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbiRidG4tZGFuZ2VyLWJnOiAgICAgICAgICAgICAgICAgICRicmFuZC1kYW5nZXIgIWRlZmF1bHQ7XG4kYnRuLWRhbmdlci1ib3JkZXI6ICAgICAgICAgICAgICBkYXJrZW4oJGJ0bi1kYW5nZXItYmcsIDUlKSAhZGVmYXVsdDtcblxuJGJ0bi1saW5rLWRpc2FibGVkLWNvbG9yOiAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG5cbi8vIEFsbG93cyBmb3IgY3VzdG9taXppbmcgYnV0dG9uIHJhZGl1cyBpbmRlcGVuZGVudGx5IGZyb20gZ2xvYmFsIGJvcmRlciByYWRpdXNcbiRidG4tYm9yZGVyLXJhZGl1cy1iYXNlOiAgICAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG4kYnRuLWJvcmRlci1yYWRpdXMtbGFyZ2U6ICAgICAgICAkYm9yZGVyLXJhZGl1cy1sYXJnZSAhZGVmYXVsdDtcbiRidG4tYm9yZGVyLXJhZGl1cy1zbWFsbDogICAgICAgICRib3JkZXItcmFkaXVzLXNtYWxsICFkZWZhdWx0O1xuXG5cbi8vPT0gRm9ybXNcbi8vXG4vLyMjXG5cbi8vKiogYDxpbnB1dD5gIGJhY2tncm91bmQgY29sb3JcbiRpbnB1dC1iZzogICAgICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIGA8aW5wdXQgZGlzYWJsZWQ+YCBiYWNrZ3JvdW5kIGNvbG9yXG4kaW5wdXQtYmctZGlzYWJsZWQ6ICAgICAgICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuXG4vLyoqIFRleHQgY29sb3IgZm9yIGA8aW5wdXQ+YHNcbiRpbnB1dC1jb2xvcjogICAgICAgICAgICAgICAgICAgICRncmF5ICFkZWZhdWx0O1xuLy8qKiBgPGlucHV0PmAgYm9yZGVyIGNvbG9yXG4kaW5wdXQtYm9yZGVyOiAgICAgICAgICAgICAgICAgICAjY2NjICFkZWZhdWx0O1xuXG4vLyBUT0RPOiBSZW5hbWUgYCRpbnB1dC1ib3JkZXItcmFkaXVzYCB0byBgJGlucHV0LWJvcmRlci1yYWRpdXMtYmFzZWAgaW4gdjRcbi8vKiogRGVmYXVsdCBgLmZvcm0tY29udHJvbGAgYm9yZGVyIHJhZGl1c1xuLy8gVGhpcyBoYXMgbm8gZWZmZWN0IG9uIGA8c2VsZWN0PmBzIGluIHNvbWUgYnJvd3NlcnMsIGR1ZSB0byB0aGUgbGltaXRlZCBzdHlsYWJpbGl0eSBvZiBgPHNlbGVjdD5gcyBpbiBDU1MuXG4kaW5wdXQtYm9yZGVyLXJhZGl1czogICAgICAgICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuLy8qKiBMYXJnZSBgLmZvcm0tY29udHJvbGAgYm9yZGVyIHJhZGl1c1xuJGlucHV0LWJvcmRlci1yYWRpdXMtbGFyZ2U6ICAgICAgJGJvcmRlci1yYWRpdXMtbGFyZ2UgIWRlZmF1bHQ7XG4vLyoqIFNtYWxsIGAuZm9ybS1jb250cm9sYCBib3JkZXIgcmFkaXVzXG4kaW5wdXQtYm9yZGVyLXJhZGl1cy1zbWFsbDogICAgICAkYm9yZGVyLXJhZGl1cy1zbWFsbCAhZGVmYXVsdDtcblxuLy8qKiBCb3JkZXIgY29sb3IgZm9yIGlucHV0cyBvbiBmb2N1c1xuJGlucHV0LWJvcmRlci1mb2N1czogICAgICAgICAgICAgIzY2YWZlOSAhZGVmYXVsdDtcblxuLy8qKiBQbGFjZWhvbGRlciB0ZXh0IGNvbG9yXG4kaW5wdXQtY29sb3ItcGxhY2Vob2xkZXI6ICAgICAgICAjOTk5ICFkZWZhdWx0O1xuXG4vLyoqIERlZmF1bHQgYC5mb3JtLWNvbnRyb2xgIGhlaWdodFxuJGlucHV0LWhlaWdodC1iYXNlOiAgICAgICAgICAgICAgKCRsaW5lLWhlaWdodC1jb21wdXRlZCArICgkcGFkZGluZy1iYXNlLXZlcnRpY2FsICogMikgKyAyKSAhZGVmYXVsdDtcbi8vKiogTGFyZ2UgYC5mb3JtLWNvbnRyb2xgIGhlaWdodFxuJGlucHV0LWhlaWdodC1sYXJnZTogICAgICAgICAgICAgKGNlaWwoJGZvbnQtc2l6ZS1sYXJnZSAqICRsaW5lLWhlaWdodC1sYXJnZSkgKyAoJHBhZGRpbmctbGFyZ2UtdmVydGljYWwgKiAyKSArIDIpICFkZWZhdWx0O1xuLy8qKiBTbWFsbCBgLmZvcm0tY29udHJvbGAgaGVpZ2h0XG4kaW5wdXQtaGVpZ2h0LXNtYWxsOiAgICAgICAgICAgICAoZmxvb3IoJGZvbnQtc2l6ZS1zbWFsbCAqICRsaW5lLWhlaWdodC1zbWFsbCkgKyAoJHBhZGRpbmctc21hbGwtdmVydGljYWwgKiAyKSArIDIpICFkZWZhdWx0O1xuXG4vLyoqIGAuZm9ybS1ncm91cGAgbWFyZ2luXG4kZm9ybS1ncm91cC1tYXJnaW4tYm90dG9tOiAgICAgICAxNXB4ICFkZWZhdWx0O1xuXG4kbGVnZW5kLWNvbG9yOiAgICAgICAgICAgICAgICAgICAkZ3JheS1kYXJrICFkZWZhdWx0O1xuJGxlZ2VuZC1ib3JkZXItY29sb3I6ICAgICAgICAgICAgI2U1ZTVlNSAhZGVmYXVsdDtcblxuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIGZvciB0ZXh0dWFsIGlucHV0IGFkZG9uc1xuJGlucHV0LWdyb3VwLWFkZG9uLWJnOiAgICAgICAgICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcbi8vKiogQm9yZGVyIGNvbG9yIGZvciB0ZXh0dWFsIGlucHV0IGFkZG9uc1xuJGlucHV0LWdyb3VwLWFkZG9uLWJvcmRlci1jb2xvcjogJGlucHV0LWJvcmRlciAhZGVmYXVsdDtcblxuLy8qKiBEaXNhYmxlZCBjdXJzb3IgZm9yIGZvcm0gY29udHJvbHMgYW5kIGJ1dHRvbnMuXG4kY3Vyc29yLWRpc2FibGVkOiAgICAgICAgICAgICAgICBub3QtYWxsb3dlZCAhZGVmYXVsdDtcblxuXG4vLz09IERyb3Bkb3duc1xuLy9cbi8vIyMgRHJvcGRvd24gbWVudSBjb250YWluZXIgYW5kIGNvbnRlbnRzLlxuXG4vLyoqIEJhY2tncm91bmQgZm9yIHRoZSBkcm9wZG93biBtZW51LlxuJGRyb3Bkb3duLWJnOiAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogRHJvcGRvd24gbWVudSBgYm9yZGVyLWNvbG9yYC5cbiRkcm9wZG93bi1ib3JkZXI6ICAgICAgICAgICAgICAgIHJnYmEoMCwwLDAsLjE1KSAhZGVmYXVsdDtcbi8vKiogRHJvcGRvd24gbWVudSBgYm9yZGVyLWNvbG9yYCAqKmZvciBJRTgqKi5cbiRkcm9wZG93bi1mYWxsYmFjay1ib3JkZXI6ICAgICAgICNjY2MgIWRlZmF1bHQ7XG4vLyoqIERpdmlkZXIgY29sb3IgZm9yIGJldHdlZW4gZHJvcGRvd24gaXRlbXMuXG4kZHJvcGRvd24tZGl2aWRlci1iZzogICAgICAgICAgICAjZTVlNWU1ICFkZWZhdWx0O1xuXG4vLyoqIERyb3Bkb3duIGxpbmsgdGV4dCBjb2xvci5cbiRkcm9wZG93bi1saW5rLWNvbG9yOiAgICAgICAgICAgICRncmF5LWRhcmsgIWRlZmF1bHQ7XG4vLyoqIEhvdmVyIGNvbG9yIGZvciBkcm9wZG93biBsaW5rcy5cbiRkcm9wZG93bi1saW5rLWhvdmVyLWNvbG9yOiAgICAgIGRhcmtlbigkZ3JheS1kYXJrLCA1JSkgIWRlZmF1bHQ7XG4vLyoqIEhvdmVyIGJhY2tncm91bmQgZm9yIGRyb3Bkb3duIGxpbmtzLlxuJGRyb3Bkb3duLWxpbmstaG92ZXItYmc6ICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcblxuLy8qKiBBY3RpdmUgZHJvcGRvd24gbWVudSBpdGVtIHRleHQgY29sb3IuXG4kZHJvcGRvd24tbGluay1hY3RpdmUtY29sb3I6ICAgICAkY29tcG9uZW50LWFjdGl2ZS1jb2xvciAhZGVmYXVsdDtcbi8vKiogQWN0aXZlIGRyb3Bkb3duIG1lbnUgaXRlbSBiYWNrZ3JvdW5kIGNvbG9yLlxuJGRyb3Bkb3duLWxpbmstYWN0aXZlLWJnOiAgICAgICAgJGNvbXBvbmVudC1hY3RpdmUtYmcgIWRlZmF1bHQ7XG5cbi8vKiogRGlzYWJsZWQgZHJvcGRvd24gbWVudSBpdGVtIGJhY2tncm91bmQgY29sb3IuXG4kZHJvcGRvd24tbGluay1kaXNhYmxlZC1jb2xvcjogICAkZ3JheS1saWdodCAhZGVmYXVsdDtcblxuLy8qKiBUZXh0IGNvbG9yIGZvciBoZWFkZXJzIHdpdGhpbiBkcm9wZG93biBtZW51cy5cbiRkcm9wZG93bi1oZWFkZXItY29sb3I6ICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuXG4vLyoqIERlcHJlY2F0ZWQgYCRkcm9wZG93bi1jYXJldC1jb2xvcmAgYXMgb2YgdjMuMS4wXG4kZHJvcGRvd24tY2FyZXQtY29sb3I6ICAgICAgICAgICAjMDAwICFkZWZhdWx0O1xuXG5cbi8vLS0gWi1pbmRleCBtYXN0ZXIgbGlzdFxuLy9cbi8vIFdhcm5pbmc6IEF2b2lkIGN1c3RvbWl6aW5nIHRoZXNlIHZhbHVlcy4gVGhleSdyZSB1c2VkIGZvciBhIGJpcmQncyBleWUgdmlld1xuLy8gb2YgY29tcG9uZW50cyBkZXBlbmRlbnQgb24gdGhlIHotYXhpcyBhbmQgYXJlIGRlc2lnbmVkIHRvIGFsbCB3b3JrIHRvZ2V0aGVyLlxuLy9cbi8vIE5vdGU6IFRoZXNlIHZhcmlhYmxlcyBhcmUgbm90IGdlbmVyYXRlZCBpbnRvIHRoZSBDdXN0b21pemVyLlxuXG4kemluZGV4LW5hdmJhcjogICAgICAgICAgICAxMDAwICFkZWZhdWx0O1xuJHppbmRleC1kcm9wZG93bjogICAgICAgICAgMTAwMCAhZGVmYXVsdDtcbiR6aW5kZXgtcG9wb3ZlcjogICAgICAgICAgIDEwNjAgIWRlZmF1bHQ7XG4kemluZGV4LXRvb2x0aXA6ICAgICAgICAgICAxMDcwICFkZWZhdWx0O1xuJHppbmRleC1uYXZiYXItZml4ZWQ6ICAgICAgMTAzMCAhZGVmYXVsdDtcbiR6aW5kZXgtbW9kYWwtYmFja2dyb3VuZDogIDEwNDAgIWRlZmF1bHQ7XG4kemluZGV4LW1vZGFsOiAgICAgICAgICAgICAxMDUwICFkZWZhdWx0O1xuXG5cbi8vPT0gTWVkaWEgcXVlcmllcyBicmVha3BvaW50c1xuLy9cbi8vIyMgRGVmaW5lIHRoZSBicmVha3BvaW50cyBhdCB3aGljaCB5b3VyIGxheW91dCB3aWxsIGNoYW5nZSwgYWRhcHRpbmcgdG8gZGlmZmVyZW50IHNjcmVlbiBzaXplcy5cblxuLy8gRXh0cmEgc21hbGwgc2NyZWVuIC8gcGhvbmVcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi14c2AgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLXhzOiAgICAgICAgICAgICAgICAgIDQ4MHB4ICFkZWZhdWx0O1xuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLXhzLW1pbmAgYXMgb2YgdjMuMi4wXG4kc2NyZWVuLXhzLW1pbjogICAgICAgICAgICAgICRzY3JlZW4teHMgIWRlZmF1bHQ7XG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4tcGhvbmVgIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi1waG9uZTogICAgICAgICAgICAgICAkc2NyZWVuLXhzLW1pbiAhZGVmYXVsdDtcblxuLy8gU21hbGwgc2NyZWVuIC8gdGFibGV0XG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4tc21gIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi1zbTogICAgICAgICAgICAgICAgICA3NjhweCAhZGVmYXVsdDtcbiRzY3JlZW4tc20tbWluOiAgICAgICAgICAgICAgJHNjcmVlbi1zbSAhZGVmYXVsdDtcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi10YWJsZXRgIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi10YWJsZXQ6ICAgICAgICAgICAgICAkc2NyZWVuLXNtLW1pbiAhZGVmYXVsdDtcblxuLy8gTWVkaXVtIHNjcmVlbiAvIGRlc2t0b3Bcbi8vKiogRGVwcmVjYXRlZCBgJHNjcmVlbi1tZGAgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLW1kOiAgICAgICAgICAgICAgICAgIDk5MnB4ICFkZWZhdWx0O1xuJHNjcmVlbi1tZC1taW46ICAgICAgICAgICAgICAkc2NyZWVuLW1kICFkZWZhdWx0O1xuLy8qKiBEZXByZWNhdGVkIGAkc2NyZWVuLWRlc2t0b3BgIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi1kZXNrdG9wOiAgICAgICAgICAgICAkc2NyZWVuLW1kLW1pbiAhZGVmYXVsdDtcblxuLy8gTGFyZ2Ugc2NyZWVuIC8gd2lkZSBkZXNrdG9wXG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4tbGdgIGFzIG9mIHYzLjAuMVxuJHNjcmVlbi1sZzogICAgICAgICAgICAgICAgICAxMjAwcHggIWRlZmF1bHQ7XG4kc2NyZWVuLWxnLW1pbjogICAgICAgICAgICAgICRzY3JlZW4tbGcgIWRlZmF1bHQ7XG4vLyoqIERlcHJlY2F0ZWQgYCRzY3JlZW4tbGctZGVza3RvcGAgYXMgb2YgdjMuMC4xXG4kc2NyZWVuLWxnLWRlc2t0b3A6ICAgICAgICAgICRzY3JlZW4tbGctbWluICFkZWZhdWx0O1xuXG4vLyBTbyBtZWRpYSBxdWVyaWVzIGRvbid0IG92ZXJsYXAgd2hlbiByZXF1aXJlZCwgcHJvdmlkZSBhIG1heGltdW1cbiRzY3JlZW4teHMtbWF4OiAgICAgICAgICAgICAgKCRzY3JlZW4tc20tbWluIC0gMSkgIWRlZmF1bHQ7XG4kc2NyZWVuLXNtLW1heDogICAgICAgICAgICAgICgkc2NyZWVuLW1kLW1pbiAtIDEpICFkZWZhdWx0O1xuJHNjcmVlbi1tZC1tYXg6ICAgICAgICAgICAgICAoJHNjcmVlbi1sZy1taW4gLSAxKSAhZGVmYXVsdDtcblxuXG4vLz09IEdyaWQgc3lzdGVtXG4vL1xuLy8jIyBEZWZpbmUgeW91ciBjdXN0b20gcmVzcG9uc2l2ZSBncmlkLlxuXG4vLyoqIE51bWJlciBvZiBjb2x1bW5zIGluIHRoZSBncmlkLlxuJGdyaWQtY29sdW1uczogICAgICAgICAgICAgIDEyICFkZWZhdWx0O1xuLy8qKiBQYWRkaW5nIGJldHdlZW4gY29sdW1ucy4gR2V0cyBkaXZpZGVkIGluIGhhbGYgZm9yIHRoZSBsZWZ0IGFuZCByaWdodC5cbiRncmlkLWd1dHRlci13aWR0aDogICAgICAgICAzMHB4ICFkZWZhdWx0O1xuLy8gTmF2YmFyIGNvbGxhcHNlXG4vLyoqIFBvaW50IGF0IHdoaWNoIHRoZSBuYXZiYXIgYmVjb21lcyB1bmNvbGxhcHNlZC5cbiRncmlkLWZsb2F0LWJyZWFrcG9pbnQ6ICAgICAkc2NyZWVuLXNtLW1pbiAhZGVmYXVsdDtcbi8vKiogUG9pbnQgYXQgd2hpY2ggdGhlIG5hdmJhciBiZWdpbnMgY29sbGFwc2luZy5cbiRncmlkLWZsb2F0LWJyZWFrcG9pbnQtbWF4OiAoJGdyaWQtZmxvYXQtYnJlYWtwb2ludCAtIDEpICFkZWZhdWx0O1xuXG5cbi8vPT0gQ29udGFpbmVyIHNpemVzXG4vL1xuLy8jIyBEZWZpbmUgdGhlIG1heGltdW0gd2lkdGggb2YgYC5jb250YWluZXJgIGZvciBkaWZmZXJlbnQgc2NyZWVuIHNpemVzLlxuXG4vLyBTbWFsbCBzY3JlZW4gLyB0YWJsZXRcbiRjb250YWluZXItdGFibGV0OiAgICAgICAgICAgICAoNzIwcHggKyAkZ3JpZC1ndXR0ZXItd2lkdGgpICFkZWZhdWx0O1xuLy8qKiBGb3IgYCRzY3JlZW4tc20tbWluYCBhbmQgdXAuXG4kY29udGFpbmVyLXNtOiAgICAgICAgICAgICAgICAgJGNvbnRhaW5lci10YWJsZXQgIWRlZmF1bHQ7XG5cbi8vIE1lZGl1bSBzY3JlZW4gLyBkZXNrdG9wXG4kY29udGFpbmVyLWRlc2t0b3A6ICAgICAgICAgICAgKDk0MHB4ICsgJGdyaWQtZ3V0dGVyLXdpZHRoKSAhZGVmYXVsdDtcbi8vKiogRm9yIGAkc2NyZWVuLW1kLW1pbmAgYW5kIHVwLlxuJGNvbnRhaW5lci1tZDogICAgICAgICAgICAgICAgICRjb250YWluZXItZGVza3RvcCAhZGVmYXVsdDtcblxuLy8gTGFyZ2Ugc2NyZWVuIC8gd2lkZSBkZXNrdG9wXG4kY29udGFpbmVyLWxhcmdlLWRlc2t0b3A6ICAgICAgKDExNDBweCArICRncmlkLWd1dHRlci13aWR0aCkgIWRlZmF1bHQ7XG4vLyoqIEZvciBgJHNjcmVlbi1sZy1taW5gIGFuZCB1cC5cbiRjb250YWluZXItbGc6ICAgICAgICAgICAgICAgICAkY29udGFpbmVyLWxhcmdlLWRlc2t0b3AgIWRlZmF1bHQ7XG5cblxuLy89PSBOYXZiYXJcbi8vXG4vLyMjXG5cbi8vIEJhc2ljcyBvZiBhIG5hdmJhclxuJG5hdmJhci1oZWlnaHQ6ICAgICAgICAgICAgICAgICAgICA1MHB4ICFkZWZhdWx0O1xuJG5hdmJhci1tYXJnaW4tYm90dG9tOiAgICAgICAgICAgICAkbGluZS1oZWlnaHQtY29tcHV0ZWQgIWRlZmF1bHQ7XG4kbmF2YmFyLWJvcmRlci1yYWRpdXM6ICAgICAgICAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG4kbmF2YmFyLXBhZGRpbmctaG9yaXpvbnRhbDogICAgICAgIGZsb29yKCgkZ3JpZC1ndXR0ZXItd2lkdGggLyAyKSkgIWRlZmF1bHQ7XG4kbmF2YmFyLXBhZGRpbmctdmVydGljYWw6ICAgICAgICAgICgoJG5hdmJhci1oZWlnaHQgLSAkbGluZS1oZWlnaHQtY29tcHV0ZWQpIC8gMikgIWRlZmF1bHQ7XG4kbmF2YmFyLWNvbGxhcHNlLW1heC1oZWlnaHQ6ICAgICAgIDM0MHB4ICFkZWZhdWx0O1xuXG4kbmF2YmFyLWRlZmF1bHQtY29sb3I6ICAgICAgICAgICAgICM3NzcgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtYmc6ICAgICAgICAgICAgICAgICNmOGY4ZjggIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtYm9yZGVyOiAgICAgICAgICAgIGRhcmtlbigkbmF2YmFyLWRlZmF1bHQtYmcsIDYuNSUpICFkZWZhdWx0O1xuXG4vLyBOYXZiYXIgbGlua3NcbiRuYXZiYXItZGVmYXVsdC1saW5rLWNvbG9yOiAgICAgICAgICAgICAgICAjNzc3ICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWxpbmstaG92ZXItY29sb3I6ICAgICAgICAgICMzMzMgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtbGluay1ob3Zlci1iZzogICAgICAgICAgICAgdHJhbnNwYXJlbnQgIWRlZmF1bHQ7XG4kbmF2YmFyLWRlZmF1bHQtbGluay1hY3RpdmUtY29sb3I6ICAgICAgICAgIzU1NSAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1saW5rLWFjdGl2ZS1iZzogICAgICAgICAgICBkYXJrZW4oJG5hdmJhci1kZWZhdWx0LWJnLCA2LjUlKSAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1saW5rLWRpc2FibGVkLWNvbG9yOiAgICAgICAjY2NjICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWxpbmstZGlzYWJsZWQtYmc6ICAgICAgICAgIHRyYW5zcGFyZW50ICFkZWZhdWx0O1xuXG4vLyBOYXZiYXIgYnJhbmQgbGFiZWxcbiRuYXZiYXItZGVmYXVsdC1icmFuZC1jb2xvcjogICAgICAgICAgICAgICAkbmF2YmFyLWRlZmF1bHQtbGluay1jb2xvciAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC1icmFuZC1ob3Zlci1jb2xvcjogICAgICAgICBkYXJrZW4oJG5hdmJhci1kZWZhdWx0LWJyYW5kLWNvbG9yLCAxMCUpICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LWJyYW5kLWhvdmVyLWJnOiAgICAgICAgICAgIHRyYW5zcGFyZW50ICFkZWZhdWx0O1xuXG4vLyBOYXZiYXIgdG9nZ2xlXG4kbmF2YmFyLWRlZmF1bHQtdG9nZ2xlLWhvdmVyLWJnOiAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcbiRuYXZiYXItZGVmYXVsdC10b2dnbGUtaWNvbi1iYXItYmc6ICAgICAgICAjODg4ICFkZWZhdWx0O1xuJG5hdmJhci1kZWZhdWx0LXRvZ2dsZS1ib3JkZXItY29sb3I6ICAgICAgICNkZGQgIWRlZmF1bHQ7XG5cblxuLy89PT0gSW52ZXJ0ZWQgbmF2YmFyXG4vLyBSZXNldCBpbnZlcnRlZCBuYXZiYXIgYmFzaWNzXG4kbmF2YmFyLWludmVyc2UtY29sb3I6ICAgICAgICAgICAgICAgICAgICAgIGxpZ2h0ZW4oJGdyYXktbGlnaHQsIDE1JSkgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtYmc6ICAgICAgICAgICAgICAgICAgICAgICAgICMyMjIgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtYm9yZGVyOiAgICAgICAgICAgICAgICAgICAgIGRhcmtlbigkbmF2YmFyLWludmVyc2UtYmcsIDEwJSkgIWRlZmF1bHQ7XG5cbi8vIEludmVydGVkIG5hdmJhciBsaW5rc1xuJG5hdmJhci1pbnZlcnNlLWxpbmstY29sb3I6ICAgICAgICAgICAgICAgICBsaWdodGVuKCRncmF5LWxpZ2h0LCAxNSUpICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWxpbmstaG92ZXItY29sb3I6ICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJG5hdmJhci1pbnZlcnNlLWxpbmstaG92ZXItYmc6ICAgICAgICAgICAgICB0cmFuc3BhcmVudCAhZGVmYXVsdDtcbiRuYXZiYXItaW52ZXJzZS1saW5rLWFjdGl2ZS1jb2xvcjogICAgICAgICAgJG5hdmJhci1pbnZlcnNlLWxpbmstaG92ZXItY29sb3IgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtbGluay1hY3RpdmUtYmc6ICAgICAgICAgICAgIGRhcmtlbigkbmF2YmFyLWludmVyc2UtYmcsIDEwJSkgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtbGluay1kaXNhYmxlZC1jb2xvcjogICAgICAgICM0NDQgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtbGluay1kaXNhYmxlZC1iZzogICAgICAgICAgIHRyYW5zcGFyZW50ICFkZWZhdWx0O1xuXG4vLyBJbnZlcnRlZCBuYXZiYXIgYnJhbmQgbGFiZWxcbiRuYXZiYXItaW52ZXJzZS1icmFuZC1jb2xvcjogICAgICAgICAgICAgICAgJG5hdmJhci1pbnZlcnNlLWxpbmstY29sb3IgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtYnJhbmQtaG92ZXItY29sb3I6ICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtYnJhbmQtaG92ZXItYmc6ICAgICAgICAgICAgIHRyYW5zcGFyZW50ICFkZWZhdWx0O1xuXG4vLyBJbnZlcnRlZCBuYXZiYXIgdG9nZ2xlXG4kbmF2YmFyLWludmVyc2UtdG9nZ2xlLWhvdmVyLWJnOiAgICAgICAgICAgICMzMzMgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtdG9nZ2xlLWljb24tYmFyLWJnOiAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kbmF2YmFyLWludmVyc2UtdG9nZ2xlLWJvcmRlci1jb2xvcjogICAgICAgICMzMzMgIWRlZmF1bHQ7XG5cblxuLy89PSBOYXZzXG4vL1xuLy8jI1xuXG4vLz09PSBTaGFyZWQgbmF2IHN0eWxlc1xuJG5hdi1saW5rLXBhZGRpbmc6ICAgICAgICAgICAgICAgICAgICAgICAgICAxMHB4IDE1cHggIWRlZmF1bHQ7XG4kbmF2LWxpbmstaG92ZXItYmc6ICAgICAgICAgICAgICAgICAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG5cbiRuYXYtZGlzYWJsZWQtbGluay1jb2xvcjogICAgICAgICAgICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4kbmF2LWRpc2FibGVkLWxpbmstaG92ZXItY29sb3I6ICAgICAgICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuXG4vLz09IFRhYnNcbiRuYXYtdGFicy1ib3JkZXItY29sb3I6ICAgICAgICAgICAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcblxuJG5hdi10YWJzLWxpbmstaG92ZXItYm9yZGVyLWNvbG9yOiAgICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuXG4kbmF2LXRhYnMtYWN0aXZlLWxpbmstaG92ZXItYmc6ICAgICAgICAgICAgICRib2R5LWJnICFkZWZhdWx0O1xuJG5hdi10YWJzLWFjdGl2ZS1saW5rLWhvdmVyLWNvbG9yOiAgICAgICAgICAkZ3JheSAhZGVmYXVsdDtcbiRuYXYtdGFicy1hY3RpdmUtbGluay1ob3Zlci1ib3JkZXItY29sb3I6ICAgI2RkZCAhZGVmYXVsdDtcblxuJG5hdi10YWJzLWp1c3RpZmllZC1saW5rLWJvcmRlci1jb2xvcjogICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuJG5hdi10YWJzLWp1c3RpZmllZC1hY3RpdmUtbGluay1ib3JkZXItY29sb3I6ICAgICAkYm9keS1iZyAhZGVmYXVsdDtcblxuLy89PSBQaWxsc1xuJG5hdi1waWxscy1ib3JkZXItcmFkaXVzOiAgICAgICAgICAgICAgICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuJG5hdi1waWxscy1hY3RpdmUtbGluay1ob3Zlci1iZzogICAgICAgICAgICAkY29tcG9uZW50LWFjdGl2ZS1iZyAhZGVmYXVsdDtcbiRuYXYtcGlsbHMtYWN0aXZlLWxpbmstaG92ZXItY29sb3I6ICAgICAgICAgJGNvbXBvbmVudC1hY3RpdmUtY29sb3IgIWRlZmF1bHQ7XG5cblxuLy89PSBQYWdpbmF0aW9uXG4vL1xuLy8jI1xuXG4kcGFnaW5hdGlvbi1jb2xvcjogICAgICAgICAgICAgICAgICAgICAkbGluay1jb2xvciAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWJnOiAgICAgICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1ib3JkZXI6ICAgICAgICAgICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuXG4kcGFnaW5hdGlvbi1ob3Zlci1jb2xvcjogICAgICAgICAgICAgICAkbGluay1ob3Zlci1jb2xvciAhZGVmYXVsdDtcbiRwYWdpbmF0aW9uLWhvdmVyLWJnOiAgICAgICAgICAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1ob3Zlci1ib3JkZXI6ICAgICAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuXG4kcGFnaW5hdGlvbi1hY3RpdmUtY29sb3I6ICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJHBhZ2luYXRpb24tYWN0aXZlLWJnOiAgICAgICAgICAgICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1hY3RpdmUtYm9yZGVyOiAgICAgICAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcblxuJHBhZ2luYXRpb24tZGlzYWJsZWQtY29sb3I6ICAgICAgICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4kcGFnaW5hdGlvbi1kaXNhYmxlZC1iZzogICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJHBhZ2luYXRpb24tZGlzYWJsZWQtYm9yZGVyOiAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcblxuXG4vLz09IFBhZ2VyXG4vL1xuLy8jI1xuXG4kcGFnZXItYmc6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkcGFnaW5hdGlvbi1iZyAhZGVmYXVsdDtcbiRwYWdlci1ib3JkZXI6ICAgICAgICAgICAgICAgICAgICAgICAgICRwYWdpbmF0aW9uLWJvcmRlciAhZGVmYXVsdDtcbiRwYWdlci1ib3JkZXItcmFkaXVzOiAgICAgICAgICAgICAgICAgIDE1cHggIWRlZmF1bHQ7XG5cbiRwYWdlci1ob3Zlci1iZzogICAgICAgICAgICAgICAgICAgICAgICRwYWdpbmF0aW9uLWhvdmVyLWJnICFkZWZhdWx0O1xuXG4kcGFnZXItYWN0aXZlLWJnOiAgICAgICAgICAgICAgICAgICAgICAkcGFnaW5hdGlvbi1hY3RpdmUtYmcgIWRlZmF1bHQ7XG4kcGFnZXItYWN0aXZlLWNvbG9yOiAgICAgICAgICAgICAgICAgICAkcGFnaW5hdGlvbi1hY3RpdmUtY29sb3IgIWRlZmF1bHQ7XG5cbiRwYWdlci1kaXNhYmxlZC1jb2xvcjogICAgICAgICAgICAgICAgICRwYWdpbmF0aW9uLWRpc2FibGVkLWNvbG9yICFkZWZhdWx0O1xuXG5cbi8vPT0gSnVtYm90cm9uXG4vL1xuLy8jI1xuXG4kanVtYm90cm9uLXBhZGRpbmc6ICAgICAgICAgICAgICAzMHB4ICFkZWZhdWx0O1xuJGp1bWJvdHJvbi1jb2xvcjogICAgICAgICAgICAgICAgaW5oZXJpdCAhZGVmYXVsdDtcbiRqdW1ib3Ryb24tYmc6ICAgICAgICAgICAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG4kanVtYm90cm9uLWhlYWRpbmctY29sb3I6ICAgICAgICBpbmhlcml0ICFkZWZhdWx0O1xuJGp1bWJvdHJvbi1mb250LXNpemU6ICAgICAgICAgICAgY2VpbCgoJGZvbnQtc2l6ZS1iYXNlICogMS41KSkgIWRlZmF1bHQ7XG4kanVtYm90cm9uLWhlYWRpbmctZm9udC1zaXplOiAgICBjZWlsKCgkZm9udC1zaXplLWJhc2UgKiA0LjUpKSAhZGVmYXVsdDtcblxuXG4vLz09IEZvcm0gc3RhdGVzIGFuZCBhbGVydHNcbi8vXG4vLyMjIERlZmluZSBjb2xvcnMgZm9yIGZvcm0gZmVlZGJhY2sgc3RhdGVzIGFuZCwgYnkgZGVmYXVsdCwgYWxlcnRzLlxuXG4kc3RhdGUtc3VjY2Vzcy10ZXh0OiAgICAgICAgICAgICAjM2M3NjNkICFkZWZhdWx0O1xuJHN0YXRlLXN1Y2Nlc3MtYmc6ICAgICAgICAgICAgICAgI2RmZjBkOCAhZGVmYXVsdDtcbiRzdGF0ZS1zdWNjZXNzLWJvcmRlcjogICAgICAgICAgIGRhcmtlbihhZGp1c3QtaHVlKCRzdGF0ZS1zdWNjZXNzLWJnLCAtMTApLCA1JSkgIWRlZmF1bHQ7XG5cbiRzdGF0ZS1pbmZvLXRleHQ6ICAgICAgICAgICAgICAgICMzMTcwOGYgIWRlZmF1bHQ7XG4kc3RhdGUtaW5mby1iZzogICAgICAgICAgICAgICAgICAjZDllZGY3ICFkZWZhdWx0O1xuJHN0YXRlLWluZm8tYm9yZGVyOiAgICAgICAgICAgICAgZGFya2VuKGFkanVzdC1odWUoJHN0YXRlLWluZm8tYmcsIC0xMCksIDclKSAhZGVmYXVsdDtcblxuJHN0YXRlLXdhcm5pbmctdGV4dDogICAgICAgICAgICAgIzhhNmQzYiAhZGVmYXVsdDtcbiRzdGF0ZS13YXJuaW5nLWJnOiAgICAgICAgICAgICAgICNmY2Y4ZTMgIWRlZmF1bHQ7XG4kc3RhdGUtd2FybmluZy1ib3JkZXI6ICAgICAgICAgICBkYXJrZW4oYWRqdXN0LWh1ZSgkc3RhdGUtd2FybmluZy1iZywgLTEwKSwgNSUpICFkZWZhdWx0O1xuXG4kc3RhdGUtZGFuZ2VyLXRleHQ6ICAgICAgICAgICAgICAjYTk0NDQyICFkZWZhdWx0O1xuJHN0YXRlLWRhbmdlci1iZzogICAgICAgICAgICAgICAgI2YyZGVkZSAhZGVmYXVsdDtcbiRzdGF0ZS1kYW5nZXItYm9yZGVyOiAgICAgICAgICAgIGRhcmtlbihhZGp1c3QtaHVlKCRzdGF0ZS1kYW5nZXItYmcsIC0xMCksIDUlKSAhZGVmYXVsdDtcblxuXG4vLz09IFRvb2x0aXBzXG4vL1xuLy8jI1xuXG4vLyoqIFRvb2x0aXAgbWF4IHdpZHRoXG4kdG9vbHRpcC1tYXgtd2lkdGg6ICAgICAgICAgICAyMDBweCAhZGVmYXVsdDtcbi8vKiogVG9vbHRpcCB0ZXh0IGNvbG9yXG4kdG9vbHRpcC1jb2xvcjogICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBUb29sdGlwIGJhY2tncm91bmQgY29sb3JcbiR0b29sdGlwLWJnOiAgICAgICAgICAgICAgICAgICMwMDAgIWRlZmF1bHQ7XG4kdG9vbHRpcC1vcGFjaXR5OiAgICAgICAgICAgICAuOSAhZGVmYXVsdDtcblxuLy8qKiBUb29sdGlwIGFycm93IHdpZHRoXG4kdG9vbHRpcC1hcnJvdy13aWR0aDogICAgICAgICA1cHggIWRlZmF1bHQ7XG4vLyoqIFRvb2x0aXAgYXJyb3cgY29sb3JcbiR0b29sdGlwLWFycm93LWNvbG9yOiAgICAgICAgICR0b29sdGlwLWJnICFkZWZhdWx0O1xuXG5cbi8vPT0gUG9wb3ZlcnNcbi8vXG4vLyMjXG5cbi8vKiogUG9wb3ZlciBib2R5IGJhY2tncm91bmQgY29sb3JcbiRwb3BvdmVyLWJnOiAgICAgICAgICAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogUG9wb3ZlciBtYXhpbXVtIHdpZHRoXG4kcG9wb3Zlci1tYXgtd2lkdGg6ICAgICAgICAgICAgICAgICAgIDI3NnB4ICFkZWZhdWx0O1xuLy8qKiBQb3BvdmVyIGJvcmRlciBjb2xvclxuJHBvcG92ZXItYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICAgICByZ2JhKDAsMCwwLC4yKSAhZGVmYXVsdDtcbi8vKiogUG9wb3ZlciBmYWxsYmFjayBib3JkZXIgY29sb3JcbiRwb3BvdmVyLWZhbGxiYWNrLWJvcmRlci1jb2xvcjogICAgICAgI2NjYyAhZGVmYXVsdDtcblxuLy8qKiBQb3BvdmVyIHRpdGxlIGJhY2tncm91bmQgY29sb3JcbiRwb3BvdmVyLXRpdGxlLWJnOiAgICAgICAgICAgICAgICAgICAgZGFya2VuKCRwb3BvdmVyLWJnLCAzJSkgIWRlZmF1bHQ7XG5cbi8vKiogUG9wb3ZlciBhcnJvdyB3aWR0aFxuJHBvcG92ZXItYXJyb3ctd2lkdGg6ICAgICAgICAgICAgICAgICAxMHB4ICFkZWZhdWx0O1xuLy8qKiBQb3BvdmVyIGFycm93IGNvbG9yXG4kcG9wb3Zlci1hcnJvdy1jb2xvcjogICAgICAgICAgICAgICAgICRwb3BvdmVyLWJnICFkZWZhdWx0O1xuXG4vLyoqIFBvcG92ZXIgb3V0ZXIgYXJyb3cgd2lkdGhcbiRwb3BvdmVyLWFycm93LW91dGVyLXdpZHRoOiAgICAgICAgICAgKCRwb3BvdmVyLWFycm93LXdpZHRoICsgMSkgIWRlZmF1bHQ7XG4vLyoqIFBvcG92ZXIgb3V0ZXIgYXJyb3cgY29sb3JcbiRwb3BvdmVyLWFycm93LW91dGVyLWNvbG9yOiAgICAgICAgICAgZmFkZV9pbigkcG9wb3Zlci1ib3JkZXItY29sb3IsIDAuMDUpICFkZWZhdWx0O1xuLy8qKiBQb3BvdmVyIG91dGVyIGFycm93IGZhbGxiYWNrIGNvbG9yXG4kcG9wb3Zlci1hcnJvdy1vdXRlci1mYWxsYmFjay1jb2xvcjogIGRhcmtlbigkcG9wb3Zlci1mYWxsYmFjay1ib3JkZXItY29sb3IsIDIwJSkgIWRlZmF1bHQ7XG5cblxuLy89PSBMYWJlbHNcbi8vXG4vLyMjXG5cbi8vKiogRGVmYXVsdCBsYWJlbCBiYWNrZ3JvdW5kIGNvbG9yXG4kbGFiZWwtZGVmYXVsdC1iZzogICAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbi8vKiogUHJpbWFyeSBsYWJlbCBiYWNrZ3JvdW5kIGNvbG9yXG4kbGFiZWwtcHJpbWFyeS1iZzogICAgICAgICAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcbi8vKiogU3VjY2VzcyBsYWJlbCBiYWNrZ3JvdW5kIGNvbG9yXG4kbGFiZWwtc3VjY2Vzcy1iZzogICAgICAgICAgICAkYnJhbmQtc3VjY2VzcyAhZGVmYXVsdDtcbi8vKiogSW5mbyBsYWJlbCBiYWNrZ3JvdW5kIGNvbG9yXG4kbGFiZWwtaW5mby1iZzogICAgICAgICAgICAgICAkYnJhbmQtaW5mbyAhZGVmYXVsdDtcbi8vKiogV2FybmluZyBsYWJlbCBiYWNrZ3JvdW5kIGNvbG9yXG4kbGFiZWwtd2FybmluZy1iZzogICAgICAgICAgICAkYnJhbmQtd2FybmluZyAhZGVmYXVsdDtcbi8vKiogRGFuZ2VyIGxhYmVsIGJhY2tncm91bmQgY29sb3JcbiRsYWJlbC1kYW5nZXItYmc6ICAgICAgICAgICAgICRicmFuZC1kYW5nZXIgIWRlZmF1bHQ7XG5cbi8vKiogRGVmYXVsdCBsYWJlbCB0ZXh0IGNvbG9yXG4kbGFiZWwtY29sb3I6ICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBEZWZhdWx0IHRleHQgY29sb3Igb2YgYSBsaW5rZWQgbGFiZWxcbiRsYWJlbC1saW5rLWhvdmVyLWNvbG9yOiAgICAgICNmZmYgIWRlZmF1bHQ7XG5cblxuLy89PSBNb2RhbHNcbi8vXG4vLyMjXG5cbi8vKiogUGFkZGluZyBhcHBsaWVkIHRvIHRoZSBtb2RhbCBib2R5XG4kbW9kYWwtaW5uZXItcGFkZGluZzogICAgICAgICAxNXB4ICFkZWZhdWx0O1xuXG4vLyoqIFBhZGRpbmcgYXBwbGllZCB0byB0aGUgbW9kYWwgdGl0bGVcbiRtb2RhbC10aXRsZS1wYWRkaW5nOiAgICAgICAgIDE1cHggIWRlZmF1bHQ7XG4vLyoqIE1vZGFsIHRpdGxlIGxpbmUtaGVpZ2h0XG4kbW9kYWwtdGl0bGUtbGluZS1oZWlnaHQ6ICAgICAkbGluZS1oZWlnaHQtYmFzZSAhZGVmYXVsdDtcblxuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9mIG1vZGFsIGNvbnRlbnQgYXJlYVxuJG1vZGFsLWNvbnRlbnQtYmc6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBNb2RhbCBjb250ZW50IGJvcmRlciBjb2xvclxuJG1vZGFsLWNvbnRlbnQtYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICAgICAgICByZ2JhKDAsMCwwLC4yKSAhZGVmYXVsdDtcbi8vKiogTW9kYWwgY29udGVudCBib3JkZXIgY29sb3IgKipmb3IgSUU4KipcbiRtb2RhbC1jb250ZW50LWZhbGxiYWNrLWJvcmRlci1jb2xvcjogICAgICAgICAgIzk5OSAhZGVmYXVsdDtcblxuLy8qKiBNb2RhbCBiYWNrZHJvcCBiYWNrZ3JvdW5kIGNvbG9yXG4kbW9kYWwtYmFja2Ryb3AtYmc6ICAgICAgICAgICAjMDAwICFkZWZhdWx0O1xuLy8qKiBNb2RhbCBiYWNrZHJvcCBvcGFjaXR5XG4kbW9kYWwtYmFja2Ryb3Atb3BhY2l0eTogICAgICAuNSAhZGVmYXVsdDtcbi8vKiogTW9kYWwgaGVhZGVyIGJvcmRlciBjb2xvclxuJG1vZGFsLWhlYWRlci1ib3JkZXItY29sb3I6ICAgI2U1ZTVlNSAhZGVmYXVsdDtcbi8vKiogTW9kYWwgZm9vdGVyIGJvcmRlciBjb2xvclxuJG1vZGFsLWZvb3Rlci1ib3JkZXItY29sb3I6ICAgJG1vZGFsLWhlYWRlci1ib3JkZXItY29sb3IgIWRlZmF1bHQ7XG5cbiRtb2RhbC1sZzogICAgICAgICAgICAgICAgICAgIDkwMHB4ICFkZWZhdWx0O1xuJG1vZGFsLW1kOiAgICAgICAgICAgICAgICAgICAgNjAwcHggIWRlZmF1bHQ7XG4kbW9kYWwtc206ICAgICAgICAgICAgICAgICAgICAzMDBweCAhZGVmYXVsdDtcblxuXG4vLz09IEFsZXJ0c1xuLy9cbi8vIyMgRGVmaW5lIGFsZXJ0IGNvbG9ycywgYm9yZGVyIHJhZGl1cywgYW5kIHBhZGRpbmcuXG5cbiRhbGVydC1wYWRkaW5nOiAgICAgICAgICAgICAgIDE1cHggIWRlZmF1bHQ7XG4kYWxlcnQtYm9yZGVyLXJhZGl1czogICAgICAgICAkYm9yZGVyLXJhZGl1cy1iYXNlICFkZWZhdWx0O1xuJGFsZXJ0LWxpbmstZm9udC13ZWlnaHQ6ICAgICAgYm9sZCAhZGVmYXVsdDtcblxuJGFsZXJ0LXN1Y2Nlc3MtYmc6ICAgICAgICAgICAgJHN0YXRlLXN1Y2Nlc3MtYmcgIWRlZmF1bHQ7XG4kYWxlcnQtc3VjY2Vzcy10ZXh0OiAgICAgICAgICAkc3RhdGUtc3VjY2Vzcy10ZXh0ICFkZWZhdWx0O1xuJGFsZXJ0LXN1Y2Nlc3MtYm9yZGVyOiAgICAgICAgJHN0YXRlLXN1Y2Nlc3MtYm9yZGVyICFkZWZhdWx0O1xuXG4kYWxlcnQtaW5mby1iZzogICAgICAgICAgICAgICAkc3RhdGUtaW5mby1iZyAhZGVmYXVsdDtcbiRhbGVydC1pbmZvLXRleHQ6ICAgICAgICAgICAgICRzdGF0ZS1pbmZvLXRleHQgIWRlZmF1bHQ7XG4kYWxlcnQtaW5mby1ib3JkZXI6ICAgICAgICAgICAkc3RhdGUtaW5mby1ib3JkZXIgIWRlZmF1bHQ7XG5cbiRhbGVydC13YXJuaW5nLWJnOiAgICAgICAgICAgICRzdGF0ZS13YXJuaW5nLWJnICFkZWZhdWx0O1xuJGFsZXJ0LXdhcm5pbmctdGV4dDogICAgICAgICAgJHN0YXRlLXdhcm5pbmctdGV4dCAhZGVmYXVsdDtcbiRhbGVydC13YXJuaW5nLWJvcmRlcjogICAgICAgICRzdGF0ZS13YXJuaW5nLWJvcmRlciAhZGVmYXVsdDtcblxuJGFsZXJ0LWRhbmdlci1iZzogICAgICAgICAgICAgJHN0YXRlLWRhbmdlci1iZyAhZGVmYXVsdDtcbiRhbGVydC1kYW5nZXItdGV4dDogICAgICAgICAgICRzdGF0ZS1kYW5nZXItdGV4dCAhZGVmYXVsdDtcbiRhbGVydC1kYW5nZXItYm9yZGVyOiAgICAgICAgICRzdGF0ZS1kYW5nZXItYm9yZGVyICFkZWZhdWx0O1xuXG5cbi8vPT0gUHJvZ3Jlc3MgYmFyc1xuLy9cbi8vIyNcblxuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9mIHRoZSB3aG9sZSBwcm9ncmVzcyBjb21wb25lbnRcbiRwcm9ncmVzcy1iZzogICAgICAgICAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG4vLyoqIFByb2dyZXNzIGJhciB0ZXh0IGNvbG9yXG4kcHJvZ3Jlc3MtYmFyLWNvbG9yOiAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuLy8qKiBWYXJpYWJsZSBmb3Igc2V0dGluZyByb3VuZGVkIGNvcm5lcnMgb24gcHJvZ3Jlc3MgYmFyLlxuJHByb2dyZXNzLWJvcmRlci1yYWRpdXM6ICAgICAgJGJvcmRlci1yYWRpdXMtYmFzZSAhZGVmYXVsdDtcblxuLy8qKiBEZWZhdWx0IHByb2dyZXNzIGJhciBjb2xvclxuJHByb2dyZXNzLWJhci1iZzogICAgICAgICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG4vLyoqIFN1Y2Nlc3MgcHJvZ3Jlc3MgYmFyIGNvbG9yXG4kcHJvZ3Jlc3MtYmFyLXN1Y2Nlc3MtYmc6ICAgICAkYnJhbmQtc3VjY2VzcyAhZGVmYXVsdDtcbi8vKiogV2FybmluZyBwcm9ncmVzcyBiYXIgY29sb3JcbiRwcm9ncmVzcy1iYXItd2FybmluZy1iZzogICAgICRicmFuZC13YXJuaW5nICFkZWZhdWx0O1xuLy8qKiBEYW5nZXIgcHJvZ3Jlc3MgYmFyIGNvbG9yXG4kcHJvZ3Jlc3MtYmFyLWRhbmdlci1iZzogICAgICAkYnJhbmQtZGFuZ2VyICFkZWZhdWx0O1xuLy8qKiBJbmZvIHByb2dyZXNzIGJhciBjb2xvclxuJHByb2dyZXNzLWJhci1pbmZvLWJnOiAgICAgICAgJGJyYW5kLWluZm8gIWRlZmF1bHQ7XG5cblxuLy89PSBMaXN0IGdyb3VwXG4vL1xuLy8jI1xuXG4vLyoqIEJhY2tncm91bmQgY29sb3Igb24gYC5saXN0LWdyb3VwLWl0ZW1gXG4kbGlzdC1ncm91cC1iZzogICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4vLyoqIGAubGlzdC1ncm91cC1pdGVtYCBib3JkZXIgY29sb3JcbiRsaXN0LWdyb3VwLWJvcmRlcjogICAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcbi8vKiogTGlzdCBncm91cCBib3JkZXIgcmFkaXVzXG4kbGlzdC1ncm91cC1ib3JkZXItcmFkaXVzOiAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG5cbi8vKiogQmFja2dyb3VuZCBjb2xvciBvZiBzaW5nbGUgbGlzdCBpdGVtcyBvbiBob3ZlclxuJGxpc3QtZ3JvdXAtaG92ZXItYmc6ICAgICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuLy8qKiBUZXh0IGNvbG9yIG9mIGFjdGl2ZSBsaXN0IGl0ZW1zXG4kbGlzdC1ncm91cC1hY3RpdmUtY29sb3I6ICAgICAgICRjb21wb25lbnQtYWN0aXZlLWNvbG9yICFkZWZhdWx0O1xuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9mIGFjdGl2ZSBsaXN0IGl0ZW1zXG4kbGlzdC1ncm91cC1hY3RpdmUtYmc6ICAgICAgICAgICRjb21wb25lbnQtYWN0aXZlLWJnICFkZWZhdWx0O1xuLy8qKiBCb3JkZXIgY29sb3Igb2YgYWN0aXZlIGxpc3QgZWxlbWVudHNcbiRsaXN0LWdyb3VwLWFjdGl2ZS1ib3JkZXI6ICAgICAgJGxpc3QtZ3JvdXAtYWN0aXZlLWJnICFkZWZhdWx0O1xuLy8qKiBUZXh0IGNvbG9yIGZvciBjb250ZW50IHdpdGhpbiBhY3RpdmUgbGlzdCBpdGVtc1xuJGxpc3QtZ3JvdXAtYWN0aXZlLXRleHQtY29sb3I6ICBsaWdodGVuKCRsaXN0LWdyb3VwLWFjdGl2ZS1iZywgNDAlKSAhZGVmYXVsdDtcblxuLy8qKiBUZXh0IGNvbG9yIG9mIGRpc2FibGVkIGxpc3QgaXRlbXNcbiRsaXN0LWdyb3VwLWRpc2FibGVkLWNvbG9yOiAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuLy8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9mIGRpc2FibGVkIGxpc3QgaXRlbXNcbiRsaXN0LWdyb3VwLWRpc2FibGVkLWJnOiAgICAgICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG4vLyoqIFRleHQgY29sb3IgZm9yIGNvbnRlbnQgd2l0aGluIGRpc2FibGVkIGxpc3QgaXRlbXNcbiRsaXN0LWdyb3VwLWRpc2FibGVkLXRleHQtY29sb3I6ICRsaXN0LWdyb3VwLWRpc2FibGVkLWNvbG9yICFkZWZhdWx0O1xuXG4kbGlzdC1ncm91cC1saW5rLWNvbG9yOiAgICAgICAgICM1NTUgIWRlZmF1bHQ7XG4kbGlzdC1ncm91cC1saW5rLWhvdmVyLWNvbG9yOiAgICRsaXN0LWdyb3VwLWxpbmstY29sb3IgIWRlZmF1bHQ7XG4kbGlzdC1ncm91cC1saW5rLWhlYWRpbmctY29sb3I6ICMzMzMgIWRlZmF1bHQ7XG5cblxuLy89PSBQYW5lbHNcbi8vXG4vLyMjXG5cbiRwYW5lbC1iZzogICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kcGFuZWwtYm9keS1wYWRkaW5nOiAgICAgICAgICAxNXB4ICFkZWZhdWx0O1xuJHBhbmVsLWhlYWRpbmctcGFkZGluZzogICAgICAgMTBweCAxNXB4ICFkZWZhdWx0O1xuJHBhbmVsLWZvb3Rlci1wYWRkaW5nOiAgICAgICAgJHBhbmVsLWhlYWRpbmctcGFkZGluZyAhZGVmYXVsdDtcbiRwYW5lbC1ib3JkZXItcmFkaXVzOiAgICAgICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG5cbi8vKiogQm9yZGVyIGNvbG9yIGZvciBlbGVtZW50cyB3aXRoaW4gcGFuZWxzXG4kcGFuZWwtaW5uZXItYm9yZGVyOiAgICAgICAgICAjZGRkICFkZWZhdWx0O1xuJHBhbmVsLWZvb3Rlci1iZzogICAgICAgICAgICAgI2Y1ZjVmNSAhZGVmYXVsdDtcblxuJHBhbmVsLWRlZmF1bHQtdGV4dDogICAgICAgICAgJGdyYXktZGFyayAhZGVmYXVsdDtcbiRwYW5lbC1kZWZhdWx0LWJvcmRlcjogICAgICAgICNkZGQgIWRlZmF1bHQ7XG4kcGFuZWwtZGVmYXVsdC1oZWFkaW5nLWJnOiAgICAjZjVmNWY1ICFkZWZhdWx0O1xuXG4kcGFuZWwtcHJpbWFyeS10ZXh0OiAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJHBhbmVsLXByaW1hcnktYm9yZGVyOiAgICAgICAgJGJyYW5kLXByaW1hcnkgIWRlZmF1bHQ7XG4kcGFuZWwtcHJpbWFyeS1oZWFkaW5nLWJnOiAgICAkYnJhbmQtcHJpbWFyeSAhZGVmYXVsdDtcblxuJHBhbmVsLXN1Y2Nlc3MtdGV4dDogICAgICAgICAgJHN0YXRlLXN1Y2Nlc3MtdGV4dCAhZGVmYXVsdDtcbiRwYW5lbC1zdWNjZXNzLWJvcmRlcjogICAgICAgICRzdGF0ZS1zdWNjZXNzLWJvcmRlciAhZGVmYXVsdDtcbiRwYW5lbC1zdWNjZXNzLWhlYWRpbmctYmc6ICAgICRzdGF0ZS1zdWNjZXNzLWJnICFkZWZhdWx0O1xuXG4kcGFuZWwtaW5mby10ZXh0OiAgICAgICAgICAgICAkc3RhdGUtaW5mby10ZXh0ICFkZWZhdWx0O1xuJHBhbmVsLWluZm8tYm9yZGVyOiAgICAgICAgICAgJHN0YXRlLWluZm8tYm9yZGVyICFkZWZhdWx0O1xuJHBhbmVsLWluZm8taGVhZGluZy1iZzogICAgICAgJHN0YXRlLWluZm8tYmcgIWRlZmF1bHQ7XG5cbiRwYW5lbC13YXJuaW5nLXRleHQ6ICAgICAgICAgICRzdGF0ZS13YXJuaW5nLXRleHQgIWRlZmF1bHQ7XG4kcGFuZWwtd2FybmluZy1ib3JkZXI6ICAgICAgICAkc3RhdGUtd2FybmluZy1ib3JkZXIgIWRlZmF1bHQ7XG4kcGFuZWwtd2FybmluZy1oZWFkaW5nLWJnOiAgICAkc3RhdGUtd2FybmluZy1iZyAhZGVmYXVsdDtcblxuJHBhbmVsLWRhbmdlci10ZXh0OiAgICAgICAgICAgJHN0YXRlLWRhbmdlci10ZXh0ICFkZWZhdWx0O1xuJHBhbmVsLWRhbmdlci1ib3JkZXI6ICAgICAgICAgJHN0YXRlLWRhbmdlci1ib3JkZXIgIWRlZmF1bHQ7XG4kcGFuZWwtZGFuZ2VyLWhlYWRpbmctYmc6ICAgICAkc3RhdGUtZGFuZ2VyLWJnICFkZWZhdWx0O1xuXG5cbi8vPT0gVGh1bWJuYWlsc1xuLy9cbi8vIyNcblxuLy8qKiBQYWRkaW5nIGFyb3VuZCB0aGUgdGh1bWJuYWlsIGltYWdlXG4kdGh1bWJuYWlsLXBhZGRpbmc6ICAgICAgICAgICA0cHggIWRlZmF1bHQ7XG4vLyoqIFRodW1ibmFpbCBiYWNrZ3JvdW5kIGNvbG9yXG4kdGh1bWJuYWlsLWJnOiAgICAgICAgICAgICAgICAkYm9keS1iZyAhZGVmYXVsdDtcbi8vKiogVGh1bWJuYWlsIGJvcmRlciBjb2xvclxuJHRodW1ibmFpbC1ib3JkZXI6ICAgICAgICAgICAgI2RkZCAhZGVmYXVsdDtcbi8vKiogVGh1bWJuYWlsIGJvcmRlciByYWRpdXNcbiR0aHVtYm5haWwtYm9yZGVyLXJhZGl1czogICAgICRib3JkZXItcmFkaXVzLWJhc2UgIWRlZmF1bHQ7XG5cbi8vKiogQ3VzdG9tIHRleHQgY29sb3IgZm9yIHRodW1ibmFpbCBjYXB0aW9uc1xuJHRodW1ibmFpbC1jYXB0aW9uLWNvbG9yOiAgICAgJHRleHQtY29sb3IgIWRlZmF1bHQ7XG4vLyoqIFBhZGRpbmcgYXJvdW5kIHRoZSB0aHVtYm5haWwgY2FwdGlvblxuJHRodW1ibmFpbC1jYXB0aW9uLXBhZGRpbmc6ICAgOXB4ICFkZWZhdWx0O1xuXG5cbi8vPT0gV2VsbHNcbi8vXG4vLyMjXG5cbiR3ZWxsLWJnOiAgICAgICAgICAgICAgICAgICAgICNmNWY1ZjUgIWRlZmF1bHQ7XG4kd2VsbC1ib3JkZXI6ICAgICAgICAgICAgICAgICBkYXJrZW4oJHdlbGwtYmcsIDclKSAhZGVmYXVsdDtcblxuXG4vLz09IEJhZGdlc1xuLy9cbi8vIyNcblxuJGJhZGdlLWNvbG9yOiAgICAgICAgICAgICAgICAgI2ZmZiAhZGVmYXVsdDtcbi8vKiogTGlua2VkIGJhZGdlIHRleHQgY29sb3Igb24gaG92ZXJcbiRiYWRnZS1saW5rLWhvdmVyLWNvbG9yOiAgICAgICNmZmYgIWRlZmF1bHQ7XG4kYmFkZ2UtYmc6ICAgICAgICAgICAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcblxuLy8qKiBCYWRnZSB0ZXh0IGNvbG9yIGluIGFjdGl2ZSBuYXYgbGlua1xuJGJhZGdlLWFjdGl2ZS1jb2xvcjogICAgICAgICAgJGxpbmstY29sb3IgIWRlZmF1bHQ7XG4vLyoqIEJhZGdlIGJhY2tncm91bmQgY29sb3IgaW4gYWN0aXZlIG5hdiBsaW5rXG4kYmFkZ2UtYWN0aXZlLWJnOiAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuXG4kYmFkZ2UtZm9udC13ZWlnaHQ6ICAgICAgICAgICBib2xkICFkZWZhdWx0O1xuJGJhZGdlLWxpbmUtaGVpZ2h0OiAgICAgICAgICAgMSAhZGVmYXVsdDtcbiRiYWRnZS1ib3JkZXItcmFkaXVzOiAgICAgICAgIDEwcHggIWRlZmF1bHQ7XG5cblxuLy89PSBCcmVhZGNydW1ic1xuLy9cbi8vIyNcblxuJGJyZWFkY3J1bWItcGFkZGluZy12ZXJ0aWNhbDogICA4cHggIWRlZmF1bHQ7XG4kYnJlYWRjcnVtYi1wYWRkaW5nLWhvcml6b250YWw6IDE1cHggIWRlZmF1bHQ7XG4vLyoqIEJyZWFkY3J1bWIgYmFja2dyb3VuZCBjb2xvclxuJGJyZWFkY3J1bWItYmc6ICAgICAgICAgICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuLy8qKiBCcmVhZGNydW1iIHRleHQgY29sb3JcbiRicmVhZGNydW1iLWNvbG9yOiAgICAgICAgICAgICAgI2NjYyAhZGVmYXVsdDtcbi8vKiogVGV4dCBjb2xvciBvZiBjdXJyZW50IHBhZ2UgaW4gdGhlIGJyZWFkY3J1bWJcbiRicmVhZGNydW1iLWFjdGl2ZS1jb2xvcjogICAgICAgJGdyYXktbGlnaHQgIWRlZmF1bHQ7XG4vLyoqIFRleHR1YWwgc2VwYXJhdG9yIGZvciBiZXR3ZWVuIGJyZWFkY3J1bWIgZWxlbWVudHNcbiRicmVhZGNydW1iLXNlcGFyYXRvcjogICAgICAgICAgXCIvXCIgIWRlZmF1bHQ7XG5cblxuLy89PSBDYXJvdXNlbFxuLy9cbi8vIyNcblxuJGNhcm91c2VsLXRleHQtc2hhZG93OiAgICAgICAgICAgICAgICAgICAgICAgIDAgMXB4IDJweCByZ2JhKDAsMCwwLC42KSAhZGVmYXVsdDtcblxuJGNhcm91c2VsLWNvbnRyb2wtY29sb3I6ICAgICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4kY2Fyb3VzZWwtY29udHJvbC13aWR0aDogICAgICAgICAgICAgICAgICAgICAgMTUlICFkZWZhdWx0O1xuJGNhcm91c2VsLWNvbnRyb2wtb3BhY2l0eTogICAgICAgICAgICAgICAgICAgIC41ICFkZWZhdWx0O1xuJGNhcm91c2VsLWNvbnRyb2wtZm9udC1zaXplOiAgICAgICAgICAgICAgICAgIDIwcHggIWRlZmF1bHQ7XG5cbiRjYXJvdXNlbC1pbmRpY2F0b3ItYWN0aXZlLWJnOiAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuJGNhcm91c2VsLWluZGljYXRvci1ib3JkZXItY29sb3I6ICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG5cbiRjYXJvdXNlbC1jYXB0aW9uLWNvbG9yOiAgICAgICAgICAgICAgICAgICAgICAjZmZmICFkZWZhdWx0O1xuXG5cbi8vPT0gQ2xvc2Vcbi8vXG4vLyMjXG5cbiRjbG9zZS1mb250LXdlaWdodDogICAgICAgICAgIGJvbGQgIWRlZmF1bHQ7XG4kY2xvc2UtY29sb3I6ICAgICAgICAgICAgICAgICAjMDAwICFkZWZhdWx0O1xuJGNsb3NlLXRleHQtc2hhZG93OiAgICAgICAgICAgMCAxcHggMCAjZmZmICFkZWZhdWx0O1xuXG5cbi8vPT0gQ29kZVxuLy9cbi8vIyNcblxuJGNvZGUtY29sb3I6ICAgICAgICAgICAgICAgICAgI2M3MjU0ZSAhZGVmYXVsdDtcbiRjb2RlLWJnOiAgICAgICAgICAgICAgICAgICAgICNmOWYyZjQgIWRlZmF1bHQ7XG5cbiRrYmQtY29sb3I6ICAgICAgICAgICAgICAgICAgICNmZmYgIWRlZmF1bHQ7XG4ka2JkLWJnOiAgICAgICAgICAgICAgICAgICAgICAjMzMzICFkZWZhdWx0O1xuXG4kcHJlLWJnOiAgICAgICAgICAgICAgICAgICAgICAjZjVmNWY1ICFkZWZhdWx0O1xuJHByZS1jb2xvcjogICAgICAgICAgICAgICAgICAgJGdyYXktZGFyayAhZGVmYXVsdDtcbiRwcmUtYm9yZGVyLWNvbG9yOiAgICAgICAgICAgICNjY2MgIWRlZmF1bHQ7XG4kcHJlLXNjcm9sbGFibGUtbWF4LWhlaWdodDogICAzNDBweCAhZGVmYXVsdDtcblxuXG4vLz09IFR5cGVcbi8vXG4vLyMjXG5cbi8vKiogSG9yaXpvbnRhbCBvZmZzZXQgZm9yIGZvcm1zIGFuZCBsaXN0cy5cbiRjb21wb25lbnQtb2Zmc2V0LWhvcml6b250YWw6IDE4MHB4ICFkZWZhdWx0O1xuLy8qKiBUZXh0IG11dGVkIGNvbG9yXG4kdGV4dC1tdXRlZDogICAgICAgICAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbi8vKiogQWJicmV2aWF0aW9ucyBhbmQgYWNyb255bXMgYm9yZGVyIGNvbG9yXG4kYWJici1ib3JkZXItY29sb3I6ICAgICAgICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbi8vKiogSGVhZGluZ3Mgc21hbGwgY29sb3JcbiRoZWFkaW5ncy1zbWFsbC1jb2xvcjogICAgICAgICRncmF5LWxpZ2h0ICFkZWZhdWx0O1xuLy8qKiBCbG9ja3F1b3RlIHNtYWxsIGNvbG9yXG4kYmxvY2txdW90ZS1zbWFsbC1jb2xvcjogICAgICAkZ3JheS1saWdodCAhZGVmYXVsdDtcbi8vKiogQmxvY2txdW90ZSBmb250IHNpemVcbiRibG9ja3F1b3RlLWZvbnQtc2l6ZTogICAgICAgICgkZm9udC1zaXplLWJhc2UgKiAxLjI1KSAhZGVmYXVsdDtcbi8vKiogQmxvY2txdW90ZSBib3JkZXIgY29sb3JcbiRibG9ja3F1b3RlLWJvcmRlci1jb2xvcjogICAgICRncmF5LWxpZ2h0ZXIgIWRlZmF1bHQ7XG4vLyoqIFBhZ2UgaGVhZGVyIGJvcmRlciBjb2xvclxuJHBhZ2UtaGVhZGVyLWJvcmRlci1jb2xvcjogICAgJGdyYXktbGlnaHRlciAhZGVmYXVsdDtcbi8vKiogV2lkdGggb2YgaG9yaXpvbnRhbCBkZXNjcmlwdGlvbiBsaXN0IHRpdGxlc1xuJGRsLWhvcml6b250YWwtb2Zmc2V0OiAgICAgICAgJGNvbXBvbmVudC1vZmZzZXQtaG9yaXpvbnRhbCAhZGVmYXVsdDtcbi8vKiogUG9pbnQgYXQgd2hpY2ggLmRsLWhvcml6b250YWwgYmVjb21lcyBob3Jpem9udGFsXG4kZGwtaG9yaXpvbnRhbC1icmVha3BvaW50OiAgICAkZ3JpZC1mbG9hdC1icmVha3BvaW50ICFkZWZhdWx0O1xuLy8qKiBIb3Jpem9udGFsIGxpbmUgY29sb3IuXG4kaHItYm9yZGVyOiAgICAgICAgICAgICAgICAgICAkZ3JheS1saWdodGVyICFkZWZhdWx0O1xuIiwiQGltcG9ydCAnLi4vLi4vLi4vc3R5bGVzL2FuaW1hdGlvbnMuc2Nzcyc7XG5cbnhvcy10YWJsZSB7XG5cbiAgZGlzcGxheTogYmxvY2s7XG5cbiAgdHIubmctbW92ZSxcbiAgdHIubmctZW50ZXIsXG4gIHRyLm5nLWxlYXZlIHtcbiAgICB0cmFuc2l0aW9uOmFsbCBsaW5lYXIgMC41cztcbiAgfVxuXG4gIHRyLm5nLWxlYXZlLm5nLWxlYXZlLWFjdGl2ZSxcbiAgdHIubmctbW92ZSxcbiAgdHIubmctZW50ZXIge1xuICAgIG9wYWNpdHk6MDtcbiAgICBhbmltYXRpb246IDAuNXMgc2xpZGVPdXRSaWdodCBlYXNlLWluLW91dDtcbiAgfVxuXG4gIHRyLm5nLWxlYXZlLFxuICB0ci5uZy1tb3ZlLm5nLW1vdmUtYWN0aXZlLFxuICB0ci5uZy1lbnRlci5uZy1lbnRlci1hY3RpdmUge1xuICAgIG9wYWNpdHk6MTtcbiAgICBhbmltYXRpb246IDAuNXMgc2xpZGVJblJpZ2h0IGVhc2UtaW4tb3V0O1xuICB9XG5cbiAgdGQgZGwge1xuICAgIG1hcmdpbi1ib3R0b206IDA7XG5cbiAgICBkdCB7XG4gICAgICB3aWR0aDogYXV0byAhaW1wb3J0YW50O1xuICAgICAgbWFyZ2luLXJpZ2h0OiAxMHB4O1xuICAgIH1cbiAgICBcbiAgICBkdDphZnRlciB7XG4gICAgICAvKmRpc3BsYXk6IGJsb2NrOyovXG4gICAgICBjb250ZW50OiAnOic7XG4gICAgfVxuXG4gICAgZGQge1xuICAgICAgbWFyZ2luLWxlZnQ6IDAgIWltcG9ydGFudDtcbiAgICB9XG4gIH1cbn0iLCJAaW1wb3J0ICcuLi8uLi8uLi9zdHlsZXMvYW5pbWF0aW9ucy5zY3NzJztcblxueG9zLWFsZXJ0IHtcblxuICAvKiB3aGVuIGhpZGluZyAqL1xuICAubmctaGlkZS1hZGQgICAgICAgICB7IGFuaW1hdGlvbjowLjVzIGZhZGVPdXREb3duIGVhc2UtaW4tb3V0OyB9XG5cbiAgLyogd2hlbiBzaG93aW5nICovXG4gIC5uZy1oaWRlLXJlbW92ZSAgICAgIHsgYW5pbWF0aW9uOjAuNXMgZmFkZUluVXAgZWFzZS1pbi1vdXQ7IH1cbn0iLCJAaW1wb3J0ICcuLi8uLi8uLi9zdHlsZXMvYW5pbWF0aW9ucy5zY3NzJztcbkBpbXBvcnQgJy4uLy4uLy4uLy4uLy4uLy4uL3N0eWxlL3Nhc3MvYm9vdHN0cmFwL2Jvb3RzdHJhcC9fdmFyaWFibGVzLnNjc3MnO1xuXG5pbnB1dCArIHhvcy12YWxpZGF0aW9uIHtcbiAgbWFyZ2luLXRvcDogJGZvcm0tZ3JvdXAtbWFyZ2luLWJvdHRvbTtcbiAgZGlzcGxheTogYmxvY2s7XG59IiwieG9zLWZpZWxkIHtcbiAgZGlzcGxheTogYmxvY2s7XG59IiwieG9zLXNtYXJ0LXRhYmxle1xuICBcbn0iXSwibWFwcGluZ3MiOiJBQ0FBLFVBQVUsQ0FBQyxBQUFBLFlBQVk7RUFDckIsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLHVCQUFXO0lBQ3RCLFVBQVUsRUFBRSxPQUFRO0VBR3RCLEFBQUEsRUFBRTtJQUNBLFNBQVMsRUFBRSxvQkFBVzs7QUFJMUIsVUFBVSxDQUFDLEFBQUEsYUFBYTtFQUN0QixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsb0JBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsVUFBVSxFQUFFLE1BQU87SUFDbkIsU0FBUyxFQUFFLHVCQUFXOztBQUkxQixVQUFVLENBQUMsQUFBQSxRQUFRO0VBQ2pCLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLElBQUs7O0FBSXBCLFVBQVUsQ0FBQyxBQUFBLFdBQVc7RUFDcEIsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7RUFHYixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVzs7QUF6QzFCLFVBQVUsQ0FBQyxBQUFBLFlBQVk7RUFDckIsQUFBQSxJQUFJO0lBQ0YsU0FBUyxFQUFFLHVCQUFXO0lBQ3RCLFVBQVUsRUFBRSxPQUFRO0VBR3RCLEFBQUEsRUFBRTtJQUNBLFNBQVMsRUFBRSxvQkFBVzs7QUFJMUIsVUFBVSxDQUFDLEFBQUEsYUFBYTtFQUN0QixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsb0JBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsVUFBVSxFQUFFLE1BQU87SUFDbkIsU0FBUyxFQUFFLHVCQUFXOztBQUkxQixVQUFVLENBQUMsQUFBQSxRQUFRO0VBQ2pCLEFBQUEsSUFBSTtJQUNGLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXO0VBR3hCLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLElBQUs7O0FBSXBCLFVBQVUsQ0FBQyxBQUFBLFdBQVc7RUFDcEIsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7RUFHYixBQUFBLEVBQUU7SUFDQSxPQUFPLEVBQUUsQ0FBRTtJQUNYLFNBQVMsRUFBRSx1QkFBVzs7QUV2QzFCLEFBQUEsU0FBUyxDQUFDO0VBRVIsT0FBTyxFQUFFLEtBQU0sR0F1Q2hCO0VBekNELEFBSUksU0FKSyxDQUlQLEVBQUUsQUFBQSxRQUFRO0VBSlosQUFLSSxTQUxLLENBS1AsRUFBRSxBQUFBLFNBQVM7RUFMYixBQU1JLFNBTkssQ0FNUCxFQUFFLEFBQUEsU0FBUyxDQUFDO0lBQ1YsVUFBVSxFQUFDLGVBQWdCLEdBQzVCO0VBUkgsQUFVYSxTQVZKLENBVVAsRUFBRSxBQUFBLFNBQVMsQUFBQSxnQkFBZ0I7RUFWN0IsQUFXSSxTQVhLLENBV1AsRUFBRSxBQUFBLFFBQVE7RUFYWixBQVlJLFNBWkssQ0FZUCxFQUFFLEFBQUEsU0FBUyxDQUFDO0lBQ1YsT0FBTyxFQUFDLENBQUU7SUFDVixTQUFTLEVBQUUsOEJBQStCLEdBQzNDO0VBZkgsQUFpQkksU0FqQkssQ0FpQlAsRUFBRSxBQUFBLFNBQVM7RUFqQmIsQUFrQlksU0FsQkgsQ0FrQlAsRUFBRSxBQUFBLFFBQVEsQUFBQSxlQUFlO0VBbEIzQixBQW1CYSxTQW5CSixDQW1CUCxFQUFFLEFBQUEsU0FBUyxBQUFBLGdCQUFnQixDQUFDO0lBQzFCLE9BQU8sRUFBQyxDQUFFO0lBQ1YsU0FBUyxFQUFFLDZCQUE4QixHQUMxQztFQXRCSCxBQXdCSyxTQXhCSSxDQXdCUCxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ0osYUFBYSxFQUFFLENBQUUsR0FlbEI7SUF4Q0gsQUEyQkksU0EzQkssQ0F3QlAsRUFBRSxDQUFDLEVBQUUsQ0FHSCxFQUFFLENBQUM7TUFDRCxLQUFLLEVBQUUsZUFBZ0I7TUFDdkIsWUFBWSxFQUFFLElBQUssR0FDcEI7SUE5QkwsQUFnQ00sU0FoQ0csQ0F3QlAsRUFBRSxDQUFDLEVBQUUsQ0FRSCxFQUFFLEFBQUEsTUFBTSxDQUFDO01BQ1AsbUJBQW1CO01BQ25CLE9BQU8sRUFBRSxHQUFJLEdBQ2Q7SUFuQ0wsQUFxQ0ksU0FyQ0ssQ0F3QlAsRUFBRSxDQUFDLEVBQUUsQ0FhSCxFQUFFLENBQUM7TUFDRCxXQUFXLEVBQUUsWUFBYSxHQUMzQjs7QUZ6Q0wsVUFBVSxDQUFDLEFBQUEsWUFBWTtFQUNyQixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsdUJBQVc7SUFDdEIsVUFBVSxFQUFFLE9BQVE7RUFHdEIsQUFBQSxFQUFFO0lBQ0EsU0FBUyxFQUFFLG9CQUFXOztBQUkxQixVQUFVLENBQUMsQUFBQSxhQUFhO0VBQ3RCLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSxvQkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxVQUFVLEVBQUUsTUFBTztJQUNuQixTQUFTLEVBQUUsdUJBQVc7O0FBSTFCLFVBQVUsQ0FBQyxBQUFBLFFBQVE7RUFDakIsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsSUFBSzs7QUFJcEIsVUFBVSxDQUFDLEFBQUEsV0FBVztFQUNwQixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtFQUdiLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXOztBR3ZDMUIsQUFBQSxTQUFTLENBQUM7RUFFUixpQkFBaUI7RUFHakIsa0JBQWtCLEVBRW5CO0VBUEQsQUFHRSxTQUhPLENBR1AsWUFBWSxDQUFTO0lBQUUsU0FBUyxFQUFDLDRCQUE2QixHQUFJO0VBSHBFLEFBTUUsU0FOTyxDQU1QLGVBQWUsQ0FBTTtJQUFFLFNBQVMsRUFBQyx5QkFBMEIsR0FBSTs7QUhSakUsVUFBVSxDQUFDLEFBQUEsWUFBWTtFQUNyQixBQUFBLElBQUk7SUFDRixTQUFTLEVBQUUsdUJBQVc7SUFDdEIsVUFBVSxFQUFFLE9BQVE7RUFHdEIsQUFBQSxFQUFFO0lBQ0EsU0FBUyxFQUFFLG9CQUFXOztBQUkxQixVQUFVLENBQUMsQUFBQSxhQUFhO0VBQ3RCLEFBQUEsSUFBSTtJQUNGLFNBQVMsRUFBRSxvQkFBVztFQUd4QixBQUFBLEVBQUU7SUFDQSxVQUFVLEVBQUUsTUFBTztJQUNuQixTQUFTLEVBQUUsdUJBQVc7O0FBSTFCLFVBQVUsQ0FBQyxBQUFBLFFBQVE7RUFDakIsQUFBQSxJQUFJO0lBQ0YsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsdUJBQVc7RUFHeEIsQUFBQSxFQUFFO0lBQ0EsT0FBTyxFQUFFLENBQUU7SUFDWCxTQUFTLEVBQUUsSUFBSzs7QUFJcEIsVUFBVSxDQUFDLEFBQUEsV0FBVztFQUNwQixBQUFBLElBQUk7SUFDRixPQUFPLEVBQUUsQ0FBRTtFQUdiLEFBQUEsRUFBRTtJQUNBLE9BQU8sRUFBRSxDQUFFO0lBQ1gsU0FBUyxFQUFFLHVCQUFXOztBSXRDMUIsQUFBUSxLQUFILEdBQUcsY0FBYyxDQUFDO0VBQ3JCLFVBQVUsRUh3TnFCLElBQUk7RUd2Tm5DLE9BQU8sRUFBRSxLQUFNLEdBQ2hCOztBQ05ELEFBQUEsU0FBUyxDQUFDO0VBQ1IsT0FBTyxFQUFFLEtBQU0sR0FDaEI7O0NOUUQsQUFBQSxBQUFVLFNBQVQsQUFBQSxJQUFZLEFBQUEsQUFBUyxRQUFSLEFBQUEsSUFBVyxBQUFBLEFBQWMsYUFBYixBQUFBLElBQWdCLEFBQUEsQUFBVyxVQUFWLEFBQUEsR0FBYSxBQUFBLFNBQVMsRUFBRSxBQUFBLFdBQVcsQ0FBQztFQUM3RSxPQUFPLEVBQUUsZUFBZ0IsR0FDMUI7O0FBRUQsQUFBTyxJQUFILEdBQUcsSUFBSSxDQUFDO0VBQ1YsMEJBQTBCO0VBQzFCLFVBQVUsRUU0TXFCLElBQUksR0YzTXBDIiwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiL3NvdXJjZS8ifQ== */
diff --git a/xos/core/templatetags/core_tags.py b/xos/core/templatetags/core_tags.py
index 6caf034..a17be08 100644
--- a/xos/core/templatetags/core_tags.py
+++ b/xos/core/templatetags/core_tags.py
@@ -2,9 +2,11 @@
 # import sys
 from core.models import DashboardView
 from itertools import chain
+from core.dashboard.views.home import DashboardDynamicView
 
 register = template.Library()
 
+
 @register.inclusion_tag('admin/tags/dashboard_list.html', takes_context=True)
 def dashboard_list(context):
     request = context['request']
@@ -14,4 +16,10 @@
         result_list = list(chain(dashboards, customize))
     else:
         result_list = []
-    return {'dashboards': result_list, 'path': request.path}
\ No newline at end of file
+    return {'dashboards': result_list, 'path': request.path}
+
+
+@register.inclusion_tag('admin/tags/notification.html', takes_context=True)
+def notification(context):
+    template = DashboardDynamicView.readTemplate(DashboardDynamicView(), "xosSynchronizerNotifier")
+    return {'template': template}
diff --git a/xos/core/views/observer.py b/xos/core/views/observer.py
index 77f1d1b..ff3ee28 100644
--- a/xos/core/views/observer.py
+++ b/xos/core/views/observer.py
@@ -9,15 +9,17 @@
     try:
         observer_name = Config().observer_name
     except AttributeError:
-        observer_name = ''
+        observer_name = 'openstack'
 
     diag = Diag.objects.filter(name=observer_name).first()
     if not diag:
         return HttpResponse(json.dumps({"health": ":-X", "time": time.time(), "comp": 0}))
 
     t = time.time()
+
     
     d = json.loads(diag.backend_register)
+
     comp = d['last_run'] + d['last_duration']*2 + 300
     if comp>t:
         d['health'] = ':-)'
diff --git a/xos/core/xoslib/dashboards/xosSynchronizerNotifier.html b/xos/core/xoslib/dashboards/xosSynchronizerNotifier.html
new file mode 100644
index 0000000..ef69861
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosSynchronizerNotifier.html
@@ -0,0 +1,16 @@
+<!-- browserSync -->
+
+<!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/static/css/xosSynchronizerNotifier.css">
+<!-- endinject -->
+
+<div id="xosSynchronizerNotifier">
+  <sync-status></sync-status>
+</div>
+
+
+<!-- endjs -->
+<!-- inject:js -->
+<script src="/static/js/xosSynchronizerNotifier.js"></script>
+<!-- endinject -->
\ No newline at end of file
diff --git a/xos/core/xoslib/methods/ceilometerview.py b/xos/core/xoslib/methods/ceilometerview.py
index 16b32d4..9c87e40 100644
--- a/xos/core/xoslib/methods/ceilometerview.py
+++ b/xos/core/xoslib/methods/ceilometerview.py
@@ -1151,8 +1151,8 @@
         if (not tenant_ceilometer_url):
             raise XOSMissingField("Tenant ceilometer URL is missing")
 
-        tenant_id = request.QUERY_PARAMS.get('tenant', None)
-        resource_id = request.QUERY_PARAMS.get('resource', None)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
 
         query = []
         if tenant_id:
@@ -1187,9 +1187,9 @@
             raise XOSMissingField("Tenant ceilometer URL is missing")
         tenant_map = getTenantControllerTenantMap(request.user)
         
-        date_options = request.QUERY_PARAMS.get('period', 1)
-        date_from = request.QUERY_PARAMS.get('date_from', '')
-        date_to = request.QUERY_PARAMS.get('date_to', '')
+        date_options = request.query_params.get('period', 1)
+        date_from = request.query_params.get('date_from', '')
+        date_to = request.query_params.get('date_to', '')
 
         try:
             date_from, date_to = calc_date_args(date_from,
@@ -1208,9 +1208,9 @@
                                      'op': 'le',
                                      'value': date_to})
 
-        meter_name = request.QUERY_PARAMS.get('meter', None)
-        tenant_id = request.QUERY_PARAMS.get('tenant', None)
-        resource_id = request.QUERY_PARAMS.get('resource', None)
+        meter_name = request.query_params.get('meter', None)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
 
         query = []
         if tenant_id:
@@ -1284,12 +1284,12 @@
         tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
         if (not tenant_ceilometer_url):
             raise XOSMissingField("Tenant ceilometer URL is missing")
-        meter_name = request.QUERY_PARAMS.get('meter', None)
+        meter_name = request.query_params.get('meter', None)
         if not meter_name:
             raise XOSMissingField("Meter name in query params is missing")
-        limit = request.QUERY_PARAMS.get('limit', 10)
-        tenant_id = request.QUERY_PARAMS.get('tenant', None)
-        resource_id = request.QUERY_PARAMS.get('resource', None)
+        limit = request.query_params.get('limit', 10)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
         query = []
         if tenant_id:
             query.extend(make_query(tenant_id=tenant_id))
@@ -1340,7 +1340,7 @@
         tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
         if (not tenant_ceilometer_url):
             raise XOSMissingField("Tenant ceilometer URL is missing")
-        instance_uuid = request.QUERY_PARAMS.get('instance-uuid', None)
+        instance_uuid = request.query_params.get('instance-uuid', None)
         if not instance_uuid:
             raise XOSMissingField("Instance UUID in query params is missing")
         if not Instance.objects.filter(instance_uuid=instance_uuid):
@@ -1354,9 +1354,9 @@
             #neutron port resource id is represented in ceilometer as "nova instance-name"+"-"+"nova instance-id"+"-"+"tap"+first 11 characters of port-id
             resource_ids.append(xos_instance.instance_id+"-"+instance_uuid+"-tap"+p.port_id[:11])
         
-        date_options = request.QUERY_PARAMS.get('period', 1)
-        date_from = request.QUERY_PARAMS.get('date_from', '')
-        date_to = request.QUERY_PARAMS.get('date_to', '')
+        date_options = request.query_params.get('period', 1)
+        date_from = request.query_params.get('date_from', '')
+        date_to = request.query_params.get('date_to', '')
 
         try:
             date_from, date_to = calc_date_args(date_from,
@@ -1437,9 +1437,9 @@
     def get(self, request, format=None):
         if (not request.user.is_authenticated()) or (not request.user.is_admin):
             raise PermissionDenied("You must be authenticated admin user in order to use this API")
-        service = request.QUERY_PARAMS.get('service', None)
-        slice_hint = request.QUERY_PARAMS.get('slice_hint', None)
-        scale = request.QUERY_PARAMS.get('scale', None)
+        service = request.query_params.get('service', None)
+        slice_hint = request.query_params.get('slice_hint', None)
+        scale = request.query_params.get('scale', None)
         if not service or not slice_hint or not scale:
             raise XOSMissingField("Mandatory fields missing")
         services = Service.select_by_user(request.user)
diff --git a/xos/core/xoslib/methods/cordsubscriber.py b/xos/core/xoslib/methods/cordsubscriber.py
index 0be9b33..b69b09d 100644
--- a/xos/core/xoslib/methods/cordsubscriber.py
+++ b/xos/core/xoslib/methods/cordsubscriber.py
@@ -28,7 +28,6 @@
 class CordSubscriberIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
         id = ReadOnlyField()
         service_specific_id = ReadOnlyField()
-        vlan_id = ReadOnlyField()      # XXX remove this
         c_tag = ReadOnlyField()
         s_tag = ReadOnlyField()
         vcpe_id = ReadOnlyField()
@@ -67,7 +66,7 @@
         class Meta:
             model = CordSubscriber
             fields = ('humanReadableName', 'id',
-                      'service_specific_id', 'vlan_id', 's_tag', 'c_tag',
+                      'service_specific_id', 's_tag', 'c_tag',
                       'vcpe_id', 'instance', 'instance_name', 'image', 'image_name',
                       'firewall_enable', 'firewall_rules',
                       'url_filter_enable', 'url_filter_rules', 'url_filter_level',
diff --git a/xos/core/xoslib/methods/volttenant.py b/xos/core/xoslib/methods/volttenant.py
index 229e105..25559a0 100644
--- a/xos/core/xoslib/methods/volttenant.py
+++ b/xos/core/xoslib/methods/volttenant.py
@@ -64,11 +64,6 @@
         if service_specific_id is not None:
             queryset = queryset.filter(service_specific_id=service_specific_id)
 
-#        vlan_id = self.request.query_params.get('vlan_id', None)
-#        if vlan_id is not None:
-#            ids = [x.id for x in queryset if x.get_attribute("vlan_id", None)==vlan_id]
-#            queryset = queryset.filter(id__in=ids)
-
         c_tag = self.request.query_params.get('c_tag', None)
         if c_tag is not None:
             ids = [x.id for x in queryset if x.get_attribute("c_tag", None)==c_tag]
diff --git a/xos/core/xoslib/objects/cordsubscriber.py b/xos/core/xoslib/objects/cordsubscriber.py
index 27596b7..681b769 100644
--- a/xos/core/xoslib/objects/cordsubscriber.py
+++ b/xos/core/xoslib/objects/cordsubscriber.py
@@ -39,7 +39,6 @@
                      # ("cdn_enable", "vcpe.cdn_enable"),
                      # uplink_speed, downlink_speed, status, enable_uverse
 
-                     ("vlan_id", "volt.vlan_id"),      # XXX remove this
                      ("c_tag", "volt.c_tag"),
                      ("s_tag", "volt.s_tag"),
 
diff --git a/xos/core/xoslib/static/css/xosSynchronizerNotifier.css b/xos/core/xoslib/static/css/xosSynchronizerNotifier.css
new file mode 100644
index 0000000..89374fb
--- /dev/null
+++ b/xos/core/xoslib/static/css/xosSynchronizerNotifier.css
@@ -0,0 +1 @@
+#xosSynchronizerNotifier{float:left}#xosSynchronizerNotifier .alert{margin-bottom:0!important}#xosSynchronizerNotifier .sync-status-container{position:relative;z-index:200}#xosSynchronizerNotifier .notification-panel{position:absolute;width:200px}#xosSynchronizerNotifier sync-status .badge.success{background-color:#5cb85c}#xosSynchronizerNotifier sync-status .badge.warning{background-color:#f0ad4e}
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
index 85670c2..90049b8 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -1,2278 +1 @@
-'use strict';
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 3/24/16.
- */
-
-(function () {
-  'use strict';
-
-  /**
-  * @ngdoc overview
-  * @name xos.uiComponents
-  * @description
-  * A collection of UI components useful for Dashboard development.
-  * Currently available components are:
-  * - [xosAlert](/#/module/xos.uiComponents.directive:xosAlert)
-  * - [xosForm](/#/module/xos.uiComponents.directive:xosForm)
-  * - [xosPagination](/#/module/xos.uiComponents.directive:xosPagination)
-  * - [xosSmartTable](/#/module/xos.uiComponents.directive:xosSmartTable)
-  * - [xosTable](/#/module/xos.uiComponents.directive:xosTable)
-  * - [xosValidation](/#/module/xos.uiComponents.directive:xosValidation)
-  **/
-
-  angular.module('xos.uiComponents', ['chart.js']);
-})();
-//# sourceMappingURL=../maps/ui_components/ui-components.module.js.map
-
-'use strict';
-
-var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 3/24/16.
- */
-
-(function () {
-  'use strict';
-
-  angular.module('xos.uiComponents')
-
-  /**
-  * @ngdoc directive
-  * @name xos.uiComponents.directive:xosSmartTable
-  * @link xos.uiComponents.directive:xosTable xosTable
-  * @link xos.uiComponents.directive:xosForm xosForm
-  * @restrict E
-  * @description The xos-table directive
-  * @param {Object} config The configuration for the component,
-  * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
-  * and an array of fields that shouldn't be printed.
-  * ```
-  * {
-      resource: 'Users',
-      hiddenFields: []
-    }
-  * ```
-  * @scope
-  * @example
-   <example module="sampleSmartTable">
-    <file name="index.html">
-      <div ng-controller="SampleCtrl as vm">
-        <xos-smart-table config="vm.config"></xos-smart-table>
-      </div>
-    </file>
-    <file name="script.js">
-      angular.module('sampleSmartTable', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
-      // This is only for documentation purpose
-      .run(function($httpBackend, _){
-        let datas = [{id: 1, name: 'Jhon', surname: 'Doe'}];
-        let count = 1;
-         let paramsUrl = new RegExp(/\/test\/(.+)/);
-         $httpBackend.whenDELETE(paramsUrl, undefined, ['id']).respond((method, url, data, headers, params) => {
-          data = angular.fromJson(data);
-          let id = url.match(paramsUrl)[1];
-          _.remove(datas, (d) => {
-            return d.id === parseInt(id);
-          })
-          return [204];
-        });
-         $httpBackend.whenGET('/test').respond(200, datas)
-        $httpBackend.whenPOST('/test').respond((method, url, data) => {
-          data = angular.fromJson(data);
-          data.id = ++count;
-          datas.push(data);
-          return [201, data, {}];
-        });
-      })
-      .factory('_', function($window){
-        return $window._;
-      })
-      .service('SampleResource', function($resource){
-        return $resource('/test/:id', {id: '@id'});
-      })
-      // End of documentation purpose, example start
-      .controller('SampleCtrl', function(){
-        this.config = {
-          resource: 'SampleResource'
-        };
-      });
-    </file>
-  </example>
-  */
-
-  .directive('xosSmartTable', function () {
-    return {
-      restrict: 'E',
-      scope: {
-        config: '='
-      },
-      template: '\n        <div class="row" ng-show="vm.data.length > 0">\n          <div class="col-xs-12 text-right">\n            <a href="" class="btn btn-success" ng-click="vm.createItem()">\n              Add\n            </a>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12 table-responsive">\n            <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n          </div>\n        </div>\n        <div class="panel panel-default" ng-show="vm.detailedItem">\n          <div class="panel-heading">\n            <div class="row">\n              <div class="col-xs-11">\n                <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n                <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n              </div>\n              <div class="col-xs-1">\n                <a href="" ng-click="vm.cleanForm()">\n                  <i class="glyphicon glyphicon-remove pull-right"></i>\n                </a>\n              </div>\n            </div>\n          </div>\n          <div class="panel-body">\n            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n          </div>\n        </div>\n        <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n        <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n      ',
-      bindToController: true,
-      controllerAs: 'vm',
-      controller: ["$injector", "LabelFormatter", "_", "XosFormHelpers", function controller($injector, LabelFormatter, _, XosFormHelpers) {
-        var _this = this;
-
-        // TODO
-        // - Validate the config (what if resource does not exist?)
-
-        // NOTE
-        // Corner case
-        // - if response is empty, how can we generate a form ?
-
-        this.responseMsg = false;
-        this.responseErr = false;
-
-        this.tableConfig = {
-          columns: [],
-          actions: [{
-            label: 'delete',
-            icon: 'remove',
-            cb: function cb(item) {
-              _this.Resource.delete({ id: item.id }).$promise.then(function () {
-                _.remove(_this.data, function (d) {
-                  return d.id === item.id;
-                });
-                _this.responseMsg = _this.config.resource + ' with id ' + item.id + ' successfully deleted';
-              }).catch(function (err) {
-                _this.responseErr = err.data.detail || 'Error while deleting ' + _this.config.resource + ' with id ' + item.id;
-              });
-            },
-            color: 'red'
-          }, {
-            label: 'details',
-            icon: 'search',
-            cb: function cb(item) {
-              _this.detailedItem = item;
-            }
-          }],
-          classes: 'table table-striped table-bordered table-responsive',
-          filter: 'field',
-          order: true,
-          pagination: {
-            pageSize: 10
-          }
-        };
-
-        this.formConfig = {
-          exclude: this.config.hiddenFields,
-          fields: {},
-          formName: this.config.resource + 'Form',
-          actions: [{
-            label: 'Save',
-            icon: 'ok',
-            cb: function cb(item) {
-              var p = void 0;
-              var isNew = true;
-
-              if (item.id) {
-                p = item.$update();
-                isNew = false;
-              } else {
-                p = item.$save();
-              }
-
-              p.then(function (res) {
-                if (isNew) {
-                  _this.data.push(angular.copy(res));
-                }
-                delete _this.detailedItem;
-                _this.responseMsg = _this.config.resource + ' with id ' + item.id + ' successfully saved';
-              }).catch(function (err) {
-                _this.responseErr = err.data.detail || 'Error while saving ' + _this.config.resource + ' with id ' + item.id;
-              });
-            },
-            class: 'success'
-          }]
-        };
-
-        this.cleanForm = function () {
-          delete _this.detailedItem;
-        };
-
-        this.createItem = function () {
-          _this.detailedItem = new _this.Resource();
-        };
-
-        this.Resource = $injector.get(this.config.resource);
-
-        var getData = function getData() {
-          _this.Resource.query().$promise.then(function (res) {
-
-            if (!res[0]) {
-              return;
-            }
-
-            var item = res[0];
-            var props = Object.keys(item);
-
-            _.remove(props, function (p) {
-              return p == 'id' || p == 'validators';
-            });
-
-            // TODO move out cb,  non sense triggering a lot of times
-            if (angular.isArray(_this.config.hiddenFields)) {
-              props = _.difference(props, _this.config.hiddenFields);
-            }
-
-            var labels = props.map(function (p) {
-              return LabelFormatter.format(p);
-            });
-
-            props.forEach(function (p, i) {
-              var fieldConfig = {
-                label: labels[i],
-                prop: p
-              };
-
-              if (typeof item[p] !== 'string' && typeof item[p] !== 'undefined') {
-                fieldConfig.type = _typeof(item[p]);
-              }
-
-              _this.tableConfig.columns.push(fieldConfig);
-            });
-
-            // build form structure
-            props.forEach(function (p, i) {
-              _this.formConfig.fields[p] = {
-                label: LabelFormatter.format(labels[i]).replace(':', ''),
-                type: XosFormHelpers._getFieldFormat(item[p])
-              };
-            });
-
-            _this.data = res;
-          });
-        };
-
-        getData();
-      }]
-    };
-  });
-})();
-//# sourceMappingURL=../../../maps/ui_components/smartComponents/smartTable/smartTable.component.js.map
-
-'use strict';
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 3/24/16.
- */
-
-(function () {
-  'use strict';
-
-  angular.module('xos.uiComponents')
-  /**
-    * @ngdoc directive
-    * @name xos.uiComponents.directive:xosSmartPie
-    * @restrict E
-    * @description The xos-table directive
-    * @param {Object} config The configuration for the component,
-    * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
-    * and a field name that is used to group the data.
-    * ```
-    * {
-        resource: 'Users',
-        groupBy: 'fieldName',
-        classes: 'my-custom-class',
-        labelFormatter: (labels) => {
-          // here you can format your label,
-          // you should return an array with the same order
-          return labels;
-        }
-      }
-    * ```
-    * @scope
-    * @example
-    
-    Displaying Local data
-     <example module="sampleSmartPieLocal">
-      <file name="index.html">
-        <div ng-controller="SampleCtrlLocal as vm">
-          <xos-smart-pie config="vm.configLocal"></xos-smart-pie>
-        </div>
-      </file>
-      <file name="script.js">
-        angular.module('sampleSmartPieLocal', ['xos.uiComponents'])
-        .factory('_', function($window){
-          return $window._;
-        })
-        .controller('SampleCtrlLocal', function($timeout){
-          
-          this.datas = [
-            {id: 1, first_name: 'Jon', last_name: 'aaa', category: 2},
-            {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 1},
-            {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2}
-          ];
-           this.configLocal = {
-            data: [],
-            groupBy: 'category',
-            classes: 'local',
-            labelFormatter: (labels) => {
-              return labels.map(l => l === '1' ? 'North' : 'Dragon');
-            }
-          };
-          
-          $timeout(() => {
-            // this need to be triggered in this way just because of ngDoc,
-            // otherwise you can assign data directly in the config
-            this.configLocal.data = this.datas;
-          }, 1)
-        });
-      </file>
-    </example>
-     Fetching data from API
-     <example module="sampleSmartPieResource">
-      <file name="index.html">
-        <div ng-controller="SampleCtrl as vm">
-          <xos-smart-pie config="vm.config"></xos-smart-pie>
-        </div>
-      </file>
-      <file name="script.js">
-        angular.module('sampleSmartPieResource', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
-        .controller('SampleCtrl', function(){
-          this.config = {
-            resource: 'SampleResource',
-            groupBy: 'category',
-            classes: 'resource',
-            labelFormatter: (labels) => {
-              return labels.map(l => l === '1' ? 'North' : 'Dragon');
-            }
-          };
-        });
-      </file>
-      <file name="backendPoll.js">
-        angular.module('sampleSmartPieResource')
-        .run(function($httpBackend, _){
-          let datas = [
-            {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
-            {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
-            {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1}
-          ];
-           $httpBackend.whenGET('/test').respond(200, datas)
-        })
-        .factory('_', function($window){
-          return $window._;
-        })
-        .service('SampleResource', function($resource){
-          return $resource('/test/:id', {id: '@id'});
-        })
-      </file>
-    </example>
-     Polling data from API
-     <example module="sampleSmartPiePoll">
-      <file name="index.html">
-        <div ng-controller="SampleCtrl as vm">
-          <xos-smart-pie config="vm.config"></xos-smart-pie>
-        </div>
-      </file>
-      <file name="script.js">
-        angular.module('sampleSmartPiePoll', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
-        .controller('SampleCtrl', function(){
-          this.config = {
-            resource: 'SampleResource',
-            groupBy: 'category',
-            poll: 2,
-            labelFormatter: (labels) => {
-              return labels.map(l => l === '1' ? 'Active' : 'Banned');
-            }
-          };
-        });
-      </file>
-      <file name="backend.js">
-        angular.module('sampleSmartPiePoll')
-        .run(function($httpBackend, _){
-          let mock = [
-            [
-              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
-              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
-              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
-              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 1}
-            ],
-             [
-              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
-              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
-              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2},
-              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
-            ],
-             [
-              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
-              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
-              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
-              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
-            ]
-          ];
-          $httpBackend.whenGET('/test').respond(function(method, url, data, headers, params) {
-            return [200, mock[Math.round(Math.random() * 3)]];
-          });
-        })
-        .factory('_', function($window){
-          return $window._;
-        })
-        .service('SampleResource', function($resource){
-          return $resource('/test/:id', {id: '@id'});
-        })
-      </file>
-    </example>
-    */
-  .directive('xosSmartPie', function () {
-    return {
-      restrict: 'E',
-      scope: {
-        config: '='
-      },
-      template: '\n        <canvas\n          class="chart chart-pie {{vm.config.classes}}"\n          chart-data="vm.data" chart-labels="vm.labels"\n          chart-legend="{{vm.config.legend}}">\n        </canvas>\n      ',
-      bindToController: true,
-      controllerAs: 'vm',
-      controller: ["$injector", "$interval", "$scope", "$timeout", "_", function controller($injector, $interval, $scope, $timeout, _) {
-        var _this = this;
-
-        if (!this.config.resource && !this.config.data) {
-          throw new Error('[xosSmartPie] Please provide a resource or an array of data in the configuration');
-        }
-
-        var groupData = function groupData(data) {
-          return _.groupBy(data, _this.config.groupBy);
-        };
-        var formatData = function formatData(data) {
-          return _.reduce(Object.keys(data), function (list, group) {
-            return list.concat(data[group].length);
-          }, []);
-        };
-        var formatLabels = function formatLabels(data) {
-          return angular.isFunction(_this.config.labelFormatter) ? _this.config.labelFormatter(Object.keys(data)) : Object.keys(data);
-        };
-
-        var prepareData = function prepareData(data) {
-          // $timeout(() => {
-          // group data
-          var grouped = groupData(data);
-          _this.data = formatData(grouped);
-          // create labels
-          _this.labels = formatLabels(grouped);
-          // }, 10);
-        };
-
-        if (this.config.resource) {
-          (function () {
-
-            _this.Resource = $injector.get(_this.config.resource);
-            var getData = function getData() {
-              _this.Resource.query().$promise.then(function (res) {
-
-                if (!res[0]) {
-                  return;
-                }
-
-                prepareData(res);
-              });
-            };
-
-            getData();
-
-            if (_this.config.poll) {
-              $interval(function () {
-                getData();
-              }, _this.config.poll * 1000);
-            }
-          })();
-        } else {
-          $scope.$watch(function () {
-            return _this.config.data;
-          }, function (data) {
-            if (data) {
-              prepareData(_this.config.data);
-            }
-          }, true);
-        }
-
-        $scope.$on('create', function (event, chart) {
-          console.log('create: ' + chart.id);
-        });
-
-        $scope.$on('destroy', function (event, chart) {
-          console.log('destroy: ' + chart.id);
-        });
-      }]
-    };
-  });
-})();
-//# sourceMappingURL=../../../maps/ui_components/smartComponents/smartPie/smartPie.component.js.map
-
-'use strict';
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 4/15/16.
- */
-
-(function () {
-  'use strict';
-
-  angular.module('xos.uiComponents')
-
-  /**
-    * @ngdoc directive
-    * @name xos.uiComponents.directive:xosValidation
-    * @restrict E
-    * @description The xos-validation directive
-    * @param {Object} errors The error object
-    * @element ANY
-    * @scope
-  * @example
-  <example module="sampleValidation">
-    <file name="index.html">
-      <div ng-controller="SampleCtrl as vm">
-        <div class="row">
-          <div class="col-xs-12">
-            <label>Set an error type:</label>
-          </div>
-          <div class="col-xs-2">
-            <a class="btn"
-              ng-click="vm.errors.required = !vm.errors.required"
-              ng-class="{'btn-default': !vm.errors.required, 'btn-success': vm.errors.required}">
-              Required
-            </a>
-          </div>
-          <div class="col-xs-2">
-            <a class="btn"
-              ng-click="vm.errors.email = !vm.errors.email"
-              ng-class="{'btn-default': !vm.errors.email, 'btn-success': vm.errors.email}">
-              Email
-            </a>
-          </div>
-          <div class="col-xs-2">
-            <a class="btn"
-              ng-click="vm.errors.minlength = !vm.errors.minlength"
-              ng-class="{'btn-default': !vm.errors.minlength, 'btn-success': vm.errors.minlength}">
-              Min Length
-            </a>
-          </div>
-          <div class="col-xs-2">
-            <a class="btn"
-              ng-click="vm.errors.maxlength = !vm.errors.maxlength"
-              ng-class="{'btn-default': !vm.errors.maxlength, 'btn-success': vm.errors.maxlength}">
-              Max Length
-            </a>
-          </div>
-        </div>
-        <xos-validation errors="vm.errors"></xos-validation>
-      </div>
-    </file>
-    <file name="script.js">
-      angular.module('sampleValidation', ['xos.uiComponents'])
-      .controller('SampleCtrl', function(){
-        this.errors = {
-          email: false
-        }
-      });
-    </file>
-  </example>
-    */
-
-  .directive('xosValidation', function () {
-    return {
-      restrict: 'E',
-      scope: {
-        errors: '='
-      },
-      template: '\n        <div ng-cloak>\n          <!-- <pre>{{vm.errors.email | json}}</pre> -->\n          <xos-alert config="vm.config" show="vm.errors.required !== undefined && vm.errors.required !== false">\n            Field required\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.errors.email !== undefined && vm.errors.email !== false">\n            This is not a valid email\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.errors.minlength !== undefined && vm.errors.minlength !== false">\n            Too short\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.errors.maxlength !== undefined && vm.errors.maxlength !== false">\n            Too long\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.errors.custom !== undefined && vm.errors.custom !== false">\n            Field invalid\n          </xos-alert>\n        </div>\n      ',
-      transclude: true,
-      bindToController: true,
-      controllerAs: 'vm',
-      controller: function controller() {
-        this.config = {
-          type: 'danger'
-        };
-      }
-    };
-  });
-})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/validation/validation.component.js.map
-
-'use strict';
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 3/24/16.
- */
-
-(function () {
-  'use strict';
-
-  angular.module('xos.uiComponents')
-
-  /**
-  * @ngdoc directive
-  * @name xos.uiComponents.directive:xosTable
-  * @restrict E
-  * @description The xos-table directive
-  * @param {Object} config The configuration for the component.
-  * ```
-  * {
-  *   columns: [
-  *     {
-  *       label: 'Human readable name',
-  *       prop: 'Property to read in the model object',
-  *       type: 'boolean'| 'array'| 'object'| 'custom'| 'date' | 'icon' // see examples for more details
-          formatter: fn(), // receive the whole item if tipe is custom and return a string
-          link: fn() // receive the whole item and return an url
-  *     }
-  *   ],
-  *   classes: 'table table-striped table-bordered',
-  *   actions: [ // if defined add an action column
-        {
-          label: 'delete',
-          icon: 'remove', // refers to bootstraps glyphicon
-          cb: (user) => { // receive the model
-            console.log(user);
-          },
-          color: 'red'
-        }
-      ],
-      filter: 'field', // can be by `field` or `fulltext`
-      order: true | {field: 'property name', reverse: true | false} // whether to show ordering arrows, or a configuration for a default ordering
-  * }
-  * ```
-  * @param {Array} data The data that should be rendered
-  * @element ANY
-  * @scope
-  * @example
-   # Basic usage
-  <example module="sampleTable1">
-  <file name="index.html">
-    <div ng-controller="SampleCtrl1 as vm">
-      <xos-table data="vm.data" config="vm.config"></xos-table>
-    </div>
-  </file>
-  <file name="script.js">
-    angular.module('sampleTable1', ['xos.uiComponents'])
-    .factory('_', function($window){
-      return $window._;
-    })
-    .controller('SampleCtrl1', function(){
-      this.config = {
-        columns: [
-          {
-            label: 'First Name', // column title
-            prop: 'name' // property to read in the data array
-          },
-          {
-            label: 'Last Name',
-            prop: 'lastname'
-          }
-        ]
-      };
-       this.data = [
-        {
-          name: 'John',
-          lastname: 'Doe'
-        },
-        {
-          name: 'Gili',
-          lastname: 'Fereydoun'
-        }
-      ]
-    });
-  </file>
-  </example>
-   # Filtering
-  <example module="sampleTable2" animations="true">
-  <file name="index.html">
-    <div ng-controller="SampleCtrl2 as vm">
-      <xos-table data="vm.data" config="vm.config"></xos-table>
-    </div>
-  </file>
-  <file name="script.js">
-    angular.module('sampleTable2', ['xos.uiComponents', 'ngAnimate'])
-    .factory('_', function($window){
-      return $window._;
-    })
-    .controller('SampleCtrl2', function(){
-      this.config = {
-        columns: [
-          {
-            label: 'First Name', // column title
-            prop: 'name' // property to read in the data array
-          },
-          {
-            label: 'Last Name',
-            prop: 'lastname'
-          }
-        ],
-        classes: 'table table-striped table-condensed', // table classes, default to `table table-striped table-bordered`
-        actions: [ // if defined add an action column
-          {
-            label: 'delete', // label
-            icon: 'remove', // icons, refers to bootstraps glyphicon
-            cb: (user) => { // callback, get feeded with the full object
-              console.log(user);
-            },
-            color: 'red' // icon color
-          }
-        ],
-        filter: 'field', // can be by `field` or `fulltext`
-        order: true
-      };
-       this.data = [
-        {
-          name: 'John',
-          lastname: 'Doe'
-        },
-        {
-          name: 'Gili',
-          lastname: 'Fereydoun'
-        }
-      ]
-    });
-  </file>
-  </example>
-   # Pagination
-  <example module="sampleTable3">
-  <file name="index.html">
-    <div ng-controller="SampleCtrl3 as vm">
-      <xos-table data="vm.data" config="vm.config"></xos-table>
-    </div>
-  </file>
-  <file name="script.js">
-    angular.module('sampleTable3', ['xos.uiComponents'])
-    .factory('_', function($window){
-      return $window._;
-    })
-    .controller('SampleCtrl3', function(){
-      this.config = {
-        columns: [
-          {
-            label: 'First Name', // column title
-            prop: 'name' // property to read in the data array
-          },
-          {
-            label: 'Last Name',
-            prop: 'lastname'
-          }
-        ],
-        pagination: {
-          pageSize: 2
-        }
-      };
-       this.data = [
-        {
-          name: 'John',
-          lastname: 'Doe'
-        },
-        {
-          name: 'Gili',
-          lastname: 'Fereydoun'
-        },
-        {
-          name: 'Lucky',
-          lastname: 'Clarkson'
-        },
-        {
-          name: 'Tate',
-          lastname: 'Spalding'
-        }
-      ]
-    });
-  </file>
-  </example>
-   # Field formatter
-  <example module="sampleTable4">
-  <file name="index.html">
-    <div ng-controller="SampleCtrl as vm">
-      <xos-table data="vm.data" config="vm.config"></xos-table>
-    </div>
-  </file>
-  <file name="script.js">
-    angular.module('sampleTable4', ['xos.uiComponents'])
-    .factory('_', function($window){
-      return $window._;
-    })
-    .controller('SampleCtrl', function(){
-      this.config = {
-        columns: [
-          {
-            label: 'First Name',
-            prop: 'name',
-            link: item => `https://www.google.it/#q=${item.name}`
-          },
-          {
-            label: 'Enabled',
-            prop: 'enabled',
-            type: 'boolean'
-          },
-          {
-            label: 'Services',
-            prop: 'services',
-            type: 'array'
-          },
-          {
-            label: 'Details',
-            prop: 'details',
-            type: 'object'
-          },
-          {
-            label: 'Created',
-            prop: 'created',
-            type: 'date'
-          },
-          {
-            label: 'Icon',
-            type: 'icon',
-            formatter: item => item.icon //note that this refer to [Bootstrap Glyphicon](http://getbootstrap.com/components/#glyphicons)
-          }
-        ]
-      };
-       this.data = [
-        {
-          name: 'John',
-          enabled: true,
-          services: ['Cdn', 'IpTv'],
-          details: {
-            c_tag: '243',
-            s_tag: '444'
-          },
-          created: new Date('December 17, 1995 03:24:00'),
-          icon: 'music'
-        },
-        {
-          name: 'Gili',
-          enabled: false,
-          services: ['Cdn', 'IpTv', 'Cache'],
-          details: {
-            c_tag: '675',
-            s_tag: '893'
-          },
-          created: new Date(),
-          icon: 'camera'
-        }
-      ]
-    });
-  </file>
-  </example>
-  # Custom formatter
-  <example module="sampleTable5">
-  <file name="index.html">
-    <div ng-controller="SampleCtrl as vm">
-      <xos-table data="vm.data" config="vm.config"></xos-table>
-    </div>
-  </file>
-  <file name="script.js">
-    angular.module('sampleTable5', ['xos.uiComponents'])
-    .factory('_', function($window){
-      return $window._;
-    })
-    .controller('SampleCtrl', function(){
-      this.config = {
-        columns: [
-          {
-            label: 'Username',
-            prop: 'username'
-          },
-          {
-            label: 'Features',
-            type: 'custom',
-            formatter: (val) => {
-              
-              let cdnEnabled = val.features.cdn ? 'enabled' : 'disabled';
-              return `
-                Cdn is ${cdnEnabled},
-                uplink speed is ${val.features.uplink_speed}
-                and downlink speed is ${val.features.downlink_speed}
-              `;
-            }
-          }
-        ]
-      };
-       this.data = [
-        {
-          username: 'John',
-          features: {
-            "cdn": false,
-            "uplink_speed": 1000000000,
-            "downlink_speed": 1000000000,
-            "uverse": true,
-            "status": "enabled"
-          }
-        },
-        {
-          username: 'Gili',
-          features: {
-            "cdn": true,
-            "uplink_speed": 3000000000,
-            "downlink_speed": 2000000000,
-            "uverse": true,
-            "status": "enabled"
-          }
-        }
-      ]
-    });
-  </file>
-  </example>
-  **/
-
-  .directive('xosTable', function () {
-    return {
-      restrict: 'E',
-      scope: {
-        data: '=',
-        config: '='
-      },
-      template: '\n          <div ng-show="vm.data.length > 0">\n            <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n              <div class="col-xs-12">\n                <input\n                  class="form-control"\n                  placeholder="Type to search.."\n                  type="text"\n                  ng-model="vm.query"/>\n              </div>\n            </div>\n            <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n              <thead>\n                <tr>\n                  <th ng-repeat="col in vm.columns">\n                    {{col.label}}\n                    <span ng-if="vm.config.order">\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n                        <i class="glyphicon glyphicon-chevron-up"></i>\n                      </a>\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n                        <i class="glyphicon glyphicon-chevron-down"></i>\n                      </a>\n                    </span>\n                  </th>\n                  <th ng-if="vm.config.actions">Actions:</th>\n                </tr>\n              </thead>\n              <tbody ng-if="vm.config.filter == \'field\'">\n                <tr>\n                  <td ng-repeat="col in vm.columns">\n                    <input\n                      ng-if="col.type !== \'boolean\'"\n                      class="form-control"\n                      placeholder="Type to search by {{col.label}}"\n                      type="text"\n                      ng-model="vm.query[col.prop]"/>\n                    <select\n                      ng-if="col.type === \'boolean\'"\n                      class="form-control"\n                      ng-model="vm.query[col.prop]">\n                      <option value="">-</option>\n                      <option value="true">True</option>\n                      <option value="false">False</option>\n                    </select>\n                  </td>\n                  <td ng-if="vm.config.actions"></td>\n                </tr>\n              </tbody>\n              <tbody>\n                <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n                  <td ng-repeat="col in vm.columns" link-wrapper>\n                    <span ng-if="!col.type">{{item[col.prop]}}</span>\n                    <span ng-if="col.type === \'boolean\'">\n                      <i class="glyphicon"\n                        ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n                      </i>\n                    </span>\n                    <span ng-if="col.type === \'date\'">\n                      {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n                    </span>\n                    <span ng-if="col.type === \'array\'">\n                      {{item[col.prop] | arrayToList}}\n                    </span>\n                    <span ng-if="col.type === \'object\'">\n                      <dl class="dl-horizontal">\n                        <span ng-repeat="(k,v) in item[col.prop]">\n                          <dt>{{k}}</dt>\n                          <dd>{{v}}</dd>\n                        </span>\n                      </dl>\n                    </span>\n                    <span ng-if="col.type === \'custom\'">\n                      {{col.formatter(item)}}\n                    </span>\n                    <span ng-if="col.type === \'icon\'">\n                      <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n                      </i>\n                    </span>\n                  </td>\n                  <td ng-if="vm.config.actions">\n                    <a href=""\n                      ng-repeat="action in vm.config.actions"\n                      ng-click="action.cb(item)"\n                      title="{{action.label}}">\n                      <i\n                        class="glyphicon glyphicon-{{action.icon}}"\n                        style="color: {{action.color}};"></i>\n                    </a>\n                  </td>\n                </tr>\n              </tbody>\n            </table>\n            <xos-pagination\n              ng-if="vm.config.pagination"\n              page-size="vm.config.pagination.pageSize"\n              total-elements="vm.data.length"\n              change="vm.goToPage">\n              </xos-pagination>\n          </div>\n          <div ng-show="vm.data.length == 0 || !vm.data">\n             <xos-alert config="{type: \'info\'}">\n              No data to show.\n            </xos-alert>\n          </div>\n        ',
-      bindToController: true,
-      controllerAs: 'vm',
-      controller: ["_", function controller(_) {
-        var _this = this;
-
-        if (!this.config) {
-          throw new Error('[xosTable] Please provide a configuration via the "config" attribute');
-        }
-
-        if (!this.config.columns) {
-          throw new Error('[xosTable] Please provide a columns list in the configuration');
-        }
-
-        // handle default ordering
-        if (this.config.order && angular.isObject(this.config.order)) {
-          this.reverse = this.config.order.reverse || false;
-          this.orderBy = this.config.order.field || 'id';
-        }
-
-        // if columns with type 'custom' are provided
-        // check that a custom formatte3 is provided too
-        var customCols = _.filter(this.config.columns, { type: 'custom' });
-        if (angular.isArray(customCols) && customCols.length > 0) {
-          _.forEach(customCols, function (col) {
-            if (!col.formatter || !angular.isFunction(col.formatter)) {
-              throw new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.');
-            }
-          });
-        }
-
-        // if columns with type 'icon' are provided
-        // check that a custom formatte3 is provided too
-        var iconCols = _.filter(this.config.columns, { type: 'icon' });
-        if (angular.isArray(iconCols) && iconCols.length > 0) {
-          _.forEach(iconCols, function (col) {
-            if (!col.formatter || !angular.isFunction(col.formatter)) {
-              throw new Error('[xosTable] You have provided an icon field type, a formatter function should provided too.');
-            }
-          });
-        }
-
-        // if a link property is passed,
-        // it should be a function
-        var linkedColumns = _.filter(this.config.columns, function (col) {
-          return angular.isDefined(col.link);
-        });
-        if (angular.isArray(linkedColumns) && linkedColumns.length > 0) {
-          _.forEach(linkedColumns, function (col) {
-            if (!angular.isFunction(col.link)) {
-              throw new Error('[xosTable] The link property should be a function.');
-            }
-          });
-        }
-
-        this.columns = this.config.columns;
-        this.classes = this.config.classes || 'table table-striped table-bordered';
-
-        if (this.config.actions) {
-          // TODO validate action format
-        }
-        if (this.config.pagination) {
-          this.currentPage = 0;
-          this.goToPage = function (n) {
-            _this.currentPage = n;
-          };
-        }
-      }]
-    };
-  })
-  // TODO move in separate files
-  // TODO test
-  .filter('arrayToList', function () {
-    return function (input) {
-      if (!angular.isArray(input)) {
-        return input;
-      }
-      return input.join(', ');
-    };
-  })
-  // TODO test
-  .directive('linkWrapper', function () {
-    return {
-      restrict: 'A',
-      transclude: true,
-      template: '\n          <a ng-if="col.link" href="{{col.link(item)}}">\n            <div ng-transclude></div>\n          </a>\n          <div ng-transclude ng-if="!col.link"></div>\n        '
-    };
-  });
-})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/table/table.component.js.map
-
-'use strict';
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 4/15/16.
- */
-
-(function () {
-  'use strict';
-
-  angular.module('xos.uiComponents')
-
-  /**
-    * @ngdoc directive
-    * @name xos.uiComponents.directive:xosPagination
-    * @restrict E
-    * @description The xos-table directive
-    * @param {Number} pageSize Number of elements per page
-    * @param {Number} totalElements Number of total elements in the collection
-    * @param {Function} change The callback to be triggered on page change.
-    * * @element ANY
-    * @scope
-    * @example
-  <example module="samplePagination">
-    <file name="index.html">
-      <div ng-controller="SampleCtrl1 as vm">
-        <xos-pagination
-          page-size="vm.pageSize"
-          total-elements="vm.totalElements"
-          change="vm.change">
-        </xos-pagination>
-      </div>
-    </file>
-    <file name="script.js">
-      angular.module('samplePagination', ['xos.uiComponents'])
-      .controller('SampleCtrl1', function(){
-        this.pageSize = 10;
-        this.totalElements = 35;
-        this.change = (pageNumber) => {
-          console.log(pageNumber);
-        }
-      });
-    </file>
-  </example>
-  **/
-
-  .directive('xosPagination', function () {
-    return {
-      restrict: 'E',
-      scope: {
-        pageSize: '=',
-        totalElements: '=',
-        change: '='
-      },
-      template: '\n        <div class="row" ng-if="vm.pageList.length > 1">\n          <div class="col-xs-12 text-center">\n            <ul class="pagination">\n              <li\n                ng-click="vm.goToPage(vm.currentPage - 1)"\n                ng-class="{disabled: vm.currentPage == 0}">\n                <a href="" aria-label="Previous">\n                    <span aria-hidden="true">&laquo;</span>\n                </a>\n              </li>\n              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n              </li>\n              <li\n                ng-click="vm.goToPage(vm.currentPage + 1)"\n                ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n                <a href="" aria-label="Next">\n                    <span aria-hidden="true">&raquo;</span>\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n      ',
-      bindToController: true,
-      controllerAs: 'vm',
-      controller: ["$scope", function controller($scope) {
-        var _this = this;
-
-        this.currentPage = 0;
-
-        this.goToPage = function (n) {
-          if (n < 0 || n === _this.pages) {
-            return;
-          }
-          _this.currentPage = n;
-          _this.change(n);
-        };
-
-        this.createPages = function (pages) {
-          var arr = [];
-          for (var i = 0; i < pages; i++) {
-            arr.push(i);
-          }
-          return arr;
-        };
-
-        // watch for data changes
-        $scope.$watch(function () {
-          return _this.totalElements;
-        }, function () {
-          if (_this.totalElements) {
-            _this.pages = Math.ceil(_this.totalElements / _this.pageSize);
-            _this.pageList = _this.createPages(_this.pages);
-          }
-        });
-      }]
-    };
-  }).filter('pagination', function () {
-    return function (input, start) {
-      if (!input || !angular.isArray(input)) {
-        return input;
-      }
-      start = parseInt(start, 10);
-      return input.slice(start);
-    };
-  });
-})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/pagination/pagination.component.js.map
-
-'use strict';
-
-var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 4/18/16.
- */
-
-(function () {
-  'use strict';
-
-  angular.module('xos.uiComponents')
-
-  /**
-    * @ngdoc directive
-    * @name xos.uiComponents.directive:xosForm
-    * @restrict E
-    * @description The xos-form directive.
-    * This components have two usage, given a model it is able to autogenerate a form or it can be configured to create a custom form.
-    * @param {Object} config The configuration object
-    * ```
-    * {
-    *   exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
-    *   actions: [ // define the form buttons with related callback
-    *     {
-            label: 'save',
-            icon: 'ok', // refers to bootstraps glyphicon
-            cb: (user) => { // receive the model
-              console.log(user);
-            },
-            class: 'success'
-          }
-    *   ],
-    *   fields: {
-    *     field_name: {
-    *       label: 'Field Label',
-    *       type: 'string' // options are: [date, boolean, number, email, string],
-    *       validators: {
-    *         minlength: number,
-              maxlength: number,
-              required: boolean,
-              min: number,
-              max: number
-    *       }
-    *     }
-    *   }
-    * }
-    * ```
-    * @element ANY
-    * @scope
-    * @example
-    
-    Autogenerated form
-   <example module="sampleForm">
-    <file name="script.js">
-      angular.module('sampleForm', ['xos.uiComponents'])
-      .factory('_', function($window){
-        return $window._;
-      })
-      .controller('SampleCtrl', function(){
-        this.model = {
-          first_name: 'Jhon',
-          last_name: 'Doe',
-          email: 'jhon.doe@sample.com',
-          active: true,
-          birthDate: '2015-02-17T22:06:38.059000Z'
-        }
-        this.config = {
-          exclude: ['password', 'last_login'],
-          formName: 'sampleForm',
-          actions: [
-            {
-              label: 'Save',
-              icon: 'ok', // refers to bootstraps glyphicon
-              cb: (user) => { // receive the model
-                console.log(user);
-              },
-              class: 'success'
-            }
-          ]
-        };
-      });
-    </file>
-    <file name="index.html">
-      <div ng-controller="SampleCtrl as vm">
-        <xos-form ng-model="vm.model" config="vm.config"></xos-form>
-      </div>
-    </file>
-  </example>
-   Configuration defined form
-   <example module="sampleForm1">
-    <file name="script.js">
-      angular.module('sampleForm1', ['xos.uiComponents'])
-      .factory('_', function($window){
-        return $window._;
-      })
-      .controller('SampleCtrl1', function(){
-        this.model = {
-        };
-         this.config = {
-          exclude: ['password', 'last_login'],
-          formName: 'sampleForm1',
-          actions: [
-            {
-              label: 'Save',
-              icon: 'ok', // refers to bootstraps glyphicon
-              cb: (user) => { // receive the model
-                console.log(user);
-              },
-              class: 'success'
-            }
-          ],
-          fields: {
-            first_name: {
-              type: 'string',
-              validators: {
-                required: true
-              }
-            },
-            last_name: {
-              label: 'Surname',
-              type: 'string',
-              validators: {
-                required: true,
-                minlength: 10
-              }
-            },
-            age: {
-              type: 'number',
-              validators: {
-                required: true,
-                min: 21
-              }
-            },
-          }
-        };
-      });
-    </file>
-    <file name="index.html">
-      <div ng-controller="SampleCtrl1 as vm">
-        <xos-form ng-model="vm.model" config="vm.config"></xos-form>
-      </div>
-    </file>
-  </example>
-   **/
-
-  .directive('xosForm', function () {
-    return {
-      restrict: 'E',
-      scope: {
-        config: '=',
-        ngModel: '='
-      },
-      template: '\n        <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n          <div class="form-group" ng-repeat="(name, field) in vm.formField">\n            <label>{{field.label}}</label>\n            <input\n              ng-if="field.type !== \'boolean\'"\n              type="{{field.type}}"\n              name="{{name}}"\n              class="form-control"\n              ng-model="vm.ngModel[name]"\n              ng-minlength="field.validators.minlength || 0"\n              ng-maxlength="field.validators.maxlength || 2000"\n              ng-required="field.validators.required || false" />\n            <span class="boolean-field" ng-if="field.type === \'boolean\'">\n              <button\n                class="btn btn-success"\n                ng-show="vm.ngModel[name]"\n                ng-click="vm.ngModel[name] = false">\n                <i class="glyphicon glyphicon-ok"></i>\n              </button>\n              <button\n                class="btn btn-danger"\n                ng-show="!vm.ngModel[name]"\n                ng-click="vm.ngModel[name] = true">\n                <i class="glyphicon glyphicon-remove"></i>\n              </button>\n            </span>\n            <!-- <pre>{{vm[vm.config.formName][name].$error | json}}</pre> -->\n            <xos-validation errors="vm[vm.config.formName || \'form\'][name].$error"></xos-validation>\n          </div>\n          <div class="form-group" ng-if="vm.config.actions">\n            <button role="button" href=""\n              ng-repeat="action in vm.config.actions"\n              ng-click="action.cb(vm.ngModel)"\n              class="btn btn-{{action.class}}"\n              title="{{action.label}}">\n              <i class="glyphicon glyphicon-{{action.icon}}"></i>\n              {{action.label}}\n            </button>\n          </div>\n        </ng-form>\n      ',
-      bindToController: true,
-      controllerAs: 'vm',
-      controller: ["$scope", "$log", "_", "XosFormHelpers", function controller($scope, $log, _, XosFormHelpers) {
-        var _this = this;
-
-        if (!this.config) {
-          throw new Error('[xosForm] Please provide a configuration via the "config" attribute');
-        }
-
-        if (!this.config.actions) {
-          throw new Error('[xosForm] Please provide an action list in the configuration');
-        }
-
-        this.excludedField = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status'];
-        if (this.config && this.config.exclude) {
-          this.excludedField = this.excludedField.concat(this.config.exclude);
-        }
-
-        this.formField = [];
-        $scope.$watch(function () {
-          return _this.ngModel;
-        }, function (model) {
-
-          // empty from old stuff
-          _this.formField = {};
-
-          if (!model) {
-            return;
-          }
-
-          var diff = _.difference(Object.keys(model), _this.excludedField);
-          var modelField = XosFormHelpers.parseModelField(diff);
-          _this.formField = XosFormHelpers.buildFormStructure(modelField, _this.config.fields, model);
-        });
-      }]
-    };
-  }).service('XosFormHelpers', ["_", "LabelFormatter", function (_, LabelFormatter) {
-    var _this2 = this;
-
-    this._isEmail = function (text) {
-      var re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
-      return re.test(text);
-    };
-
-    this._getFieldFormat = function (value) {
-
-      // check if is date
-      if (_.isDate(value) || !Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000) {
-        return 'date';
-      }
-
-      // check if is boolean
-      // isNaN(false) = false, false is a number (0), true is a number (1)
-      if (typeof value === 'boolean') {
-        return 'boolean';
-      }
-
-      // check if a string is a number
-      if (!isNaN(value) && value !== null) {
-        return 'number';
-      }
-
-      // check if a string is an email
-      if (_this2._isEmail(value)) {
-        return 'email';
-      }
-
-      // if null return string
-      if (value === null) {
-        return 'string';
-      }
-
-      return typeof value === 'undefined' ? 'undefined' : _typeof(value);
-    };
-
-    this.buildFormStructure = function (modelField, customField, model) {
-
-      modelField = Object.keys(modelField).length > 0 ? modelField : customField; //if no model field are provided, check custom
-      customField = customField || {};
-
-      return _.reduce(Object.keys(modelField), function (form, f) {
-
-        form[f] = {
-          label: customField[f] && customField[f].label ? customField[f].label + ':' : LabelFormatter.format(f),
-          type: customField[f] && customField[f].type ? customField[f].type : _this2._getFieldFormat(model[f]),
-          validators: customField[f] && customField[f].validators ? customField[f].validators : {}
-        };
-
-        if (form[f].type === 'date') {
-          model[f] = new Date(model[f]);
-        }
-
-        if (form[f].type === 'number') {
-          model[f] = parseInt(model[f], 10);
-        }
-
-        return form;
-      }, {});
-    };
-
-    this.parseModelField = function (fields) {
-      return _.reduce(fields, function (form, f) {
-        form[f] = {};
-        return form;
-      }, {});
-    };
-  }]);
-})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/form/form.component.js.map
-
-'use strict';
-
-/**
- * © OpenCORD
- *
- * Visit http://guide.xosproject.org/devguide/addview/ for more information
- *
- * Created by teone on 4/15/16.
- */
-
-(function () {
-  'use strict';
-
-  angular.module('xos.uiComponents')
-
-  /**
-    * @ngdoc directive
-    * @name xos.uiComponents.directive:xosAlert
-    * @restrict E
-    * @description The xos-alert directive
-    * @param {Object} config The configuration object
-    * ```
-    * {
-    *   type: 'danger', //info, success, warning
-    *   closeBtn: true, //default false
-    *   autoHide: 3000 //delay to automatically hide the alert
-    * }
-    * ```
-    * @param {Boolean=} show Binding to show and hide the alert, default to true
-    * @element ANY
-    * @scope
-    * @example
-  <example module="sampleAlert1">
-    <file name="index.html">
-      <div ng-controller="SampleCtrl1 as vm">
-        <xos-alert config="vm.config1">
-          A sample alert message
-        </xos-alert>
-        <xos-alert config="vm.config2">
-          A sample alert message (with close button)
-        </xos-alert>
-        <xos-alert config="vm.config3">
-          A sample info message
-        </xos-alert>
-        <xos-alert config="vm.config4">
-          A sample success message
-        </xos-alert>
-        <xos-alert config="vm.config5">
-          A sample warning message
-        </xos-alert>
-      </div>
-    </file>
-    <file name="script.js">
-      angular.module('sampleAlert1', ['xos.uiComponents'])
-      .controller('SampleCtrl1', function(){
-        this.config1 = {
-          type: 'danger'
-        };
-         this.config2 = {
-          type: 'danger',
-          closeBtn: true
-        };
-         this.config3 = {
-          type: 'info'
-        };
-         this.config4 = {
-          type: 'success'
-        };
-         this.config5 = {
-          type: 'warning'
-        };
-      });
-    </file>
-  </example>
-   <example module="sampleAlert2" animations="true">
-    <file name="index.html">
-      <div ng-controller="SampleCtrl as vm" class="row">
-        <div class="col-sm-4">
-          <a class="btn btn-default btn-block" ng-show="!vm.show" ng-click="vm.show = true">Show Alert</a>
-          <a class="btn btn-default btn-block" ng-show="vm.show" ng-click="vm.show = false">Hide Alert</a>
-        </div>
-        <div class="col-sm-8">
-          <xos-alert config="vm.config1" show="vm.show">
-            A sample alert message, not displayed by default.
-          </xos-alert>
-        </div>
-      </div>
-    </file>
-    <file name="script.js">
-      angular.module('sampleAlert2', ['xos.uiComponents', 'ngAnimate'])
-      .controller('SampleCtrl', function(){
-        this.config1 = {
-          type: 'success'
-        };
-         this.show = false;
-      });
-    </file>
-  </example>
-  **/
-
-  .directive('xosAlert', function () {
-    return {
-      restrict: 'E',
-      scope: {
-        config: '=',
-        show: '=?'
-      },
-      template: '\n        <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n            <span aria-hidden="true">&times;</span>\n          </button>\n          <p ng-transclude></p>\n        </div>\n      ',
-      transclude: true,
-      bindToController: true,
-      controllerAs: 'vm',
-      controller: ["$timeout", function controller($timeout) {
-        var _this = this;
-
-        if (!this.config) {
-          throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');
-        }
-
-        // default the value to true
-        this.show = this.show !== false;
-
-        this.dismiss = function () {
-          _this.show = false;
-        };
-
-        if (this.config.autoHide) {
-          (function () {
-            var to = $timeout(function () {
-              _this.dismiss();
-              $timeout.cancel(to);
-            }, _this.config.autoHide);
-          })();
-        }
-      }]
-    };
-  });
-})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/alert/alert.component.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  config.$inject = ["$httpProvider", "$interpolateProvider", "$resourceProvider"];
-  angular.module('bugSnag', []).factory('$exceptionHandler', function () {
-    return function (exception, cause) {
-      if (window.Bugsnag) {
-        Bugsnag.notifyException(exception, { diagnostics: { cause: cause } });
-      } else {
-        console.error(exception, cause, exception.stack);
-      }
-    };
-  });
-
-  /**
-  * @ngdoc overview
-  * @name xos.helpers
-  * @description this is the module that group all the helpers service and components for XOS
-  **/
-
-  angular.module('xos.helpers', ['ngCookies', 'ngResource', 'ngAnimate', 'bugSnag', 'xos.uiComponents']).config(config).factory('_', ["$window", function ($window) {
-    return $window._;
-  }]);
-
-  function config($httpProvider, $interpolateProvider, $resourceProvider) {
-    $httpProvider.interceptors.push('SetCSRFToken');
-
-    $interpolateProvider.startSymbol('{$');
-    $interpolateProvider.endSymbol('$}');
-
-    // NOTE http://www.masnun.com/2013/09/18/django-rest-framework-angularjs-resource-trailing-slash-problem.html
-    $resourceProvider.defaults.stripTrailingSlashes = false;
-  }
-})();
-//# sourceMappingURL=maps/xosHelpers.module.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.vSG-Collection
-  * @description Angular resource to fetch /api/service/vsg/
-  **/
-  .service('vSG-Collection', ["$resource", function ($resource) {
-    return $resource('/api/service/vsg/');
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/vSG.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.vOLT-Collection
-  * @description Angular resource to fetch /api/tenant/cord/volt/:volt_id/
-  **/
-  .service('vOLT-Collection', ["$resource", function ($resource) {
-    return $resource('/api/tenant/cord/volt/:volt_id/', { volt_id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/vOLT.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Login
-  * @description Angular resource to fetch /api/utility/login/
-  **/
-  .service('Login', ["$resource", function ($resource) {
-    return $resource('/api/utility/login/');
-  }])
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Logout
-  * @description Angular resource to fetch /api/utility/logout/
-  **/
-  .service('Logout', ["$resource", function ($resource) {
-    return $resource('/api/utility/logout/');
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Utility.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Users
-  * @description Angular resource to fetch /api/core/users/:id/
-  **/
-  .service('Users', ["$resource", function ($resource) {
-    return $resource('/api/core/users/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Users.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Truckroll
-  * @description Angular resource to fetch /api/tenant/truckroll/:id/
-  **/
-  .service('Truckroll', ["$resource", function ($resource) {
-    return $resource('/api/tenant/truckroll/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Truckroll.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Tenant
-  * @description Angular resource to fetch /api/core/tenant/:id/
-  **/
-  .service('Tenants', ["$resource", function ($resource) {
-    return $resource('/api/core/tenants/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Tenant.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Subscribers
-  * @description Angular resource to fetch Subscribers
-  **/
-  .service('Subscribers', ["$resource", function ($resource) {
-    return $resource('/api/tenant/cord/subscriber/:id/', { id: '@id' }, {
-      update: { method: 'PUT' },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#View-a-Subscriber-Features-Detail
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * View-a-Subscriber-Features-Detail
-      **/
-      'View-a-Subscriber-Features-Detail': {
-        method: 'GET',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Read-Subscriber-uplink_speed
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Read-Subscriber-uplink_speed
-      **/
-      'Read-Subscriber-uplink_speed': {
-        method: 'GET',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/uplink_speed/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Update-Subscriber-uplink_speed
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Update-Subscriber-uplink_speed
-      **/
-      'Update-Subscriber-uplink_speed': {
-        method: 'PUT',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/uplink_speed/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Read-Subscriber-downlink_speed
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Read-Subscriber-downlink_speed
-      **/
-      'Read-Subscriber-downlink_speed': {
-        method: 'GET',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/downlink_speed/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Update-Subscriber-downlink_speed
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Update-Subscriber-downlink_speed
-      **/
-      'Update-Subscriber-downlink_speed': {
-        method: 'PUT',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/downlink_speed/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Read-Subscriber-cdn
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Read-Subscriber-cdn
-      **/
-      'Read-Subscriber-cdn': {
-        method: 'GET',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/cdn/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Update-Subscriber-cdn
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Update-Subscriber-cdn
-      **/
-      'Update-Subscriber-cdn': {
-        method: 'PUT',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/cdn/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Read-Subscriber-uverse
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Read-Subscriber-uverse
-      **/
-      'Read-Subscriber-uverse': {
-        method: 'GET',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/uverse/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Update-Subscriber-uverse
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Update-Subscriber-uverse
-      **/
-      'Update-Subscriber-uverse': {
-        method: 'PUT',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/uverse/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Read-Subscriber-status
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Read-Subscriber-status
-      **/
-      'Read-Subscriber-status': {
-        method: 'GET',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/status/'
-      },
-      /**
-      * @ngdoc method
-      * @name xos.helpers.Subscribers#Update-Subscriber-status
-      * @methodOf xos.helpers.Subscribers
-      * @description
-      * Update-Subscriber-status
-      **/
-      'Update-Subscriber-status': {
-        method: 'PUT',
-        isArray: false,
-        url: '/api/tenant/cord/subscriber/:id/features/status/'
-      }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Subscribers.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.SlicesPlus
-  * @description Angular resource to fetch /api/utility/slicesplus/
-  * This is a read-only API and only the `query` method is currently supported.
-  **/
-  .service('SlicesPlus', ["$http", "$q", function ($http, $q) {
-    this.query = function (params) {
-      var deferred = $q.defer();
-
-      $http.get('/api/utility/slicesplus/', { params: params }).then(function (res) {
-        deferred.resolve(res.data);
-      }).catch(function (res) {
-        deferred.reject(res.data);
-      });
-
-      return { $promise: deferred.promise };
-    };
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Slices_plus.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Slices
-  * @description Angular resource to fetch /api/core/slices/:id/
-  **/
-  .service('Slices', ["$resource", function ($resource) {
-    return $resource('/api/core/slices/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Slices.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Sites
-  * @description Angular resource to fetch /api/core/sites/:id/
-  **/
-  .service('Sites', ["$resource", function ($resource) {
-    return $resource('/api/core/sites/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Sites.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Services
-  * @description Angular resource to fetch /api/core/services/:id/
-  **/
-  .service('Services', ["$resource", function ($resource) {
-    return $resource('/api/core/services/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Services.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.ONOS-Services-Collection
-  * @description Angular resource to fetch /api/service/onos/
-  **/
-  .service('ONOS-Services-Collection', ["$resource", function ($resource) {
-    return $resource('/api/service/onos/');
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/ONOS-Services.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.ONOS-App-Collection
-  * @description Angular resource to fetch /api/tenant/onos/app/
-  **/
-  .service('ONOS-App-Collection', ["$resource", function ($resource) {
-    return $resource('/api/tenant/onos/app/');
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/ONOS-Apps.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Nodes
-  * @description Angular resource to fetch /api/core/nodes/:id/
-  **/
-  .service('Nodes', ["$resource", function ($resource) {
-    return $resource('/api/core/nodes/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Nodes.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Networks
-  * @description Angular resource to fetch /api/core/networks/:id/
-  **/
-  .service('Networks', ["$resource", function ($resource) {
-    return $resource('/api/core/networks/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Networks.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Instances
-  * @description Angular resource to fetch /api/core/instances/:id/
-  **/
-  .service('Instances', ["$resource", function ($resource) {
-    return $resource('/api/core/instances/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Instances.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Flavors
-  * @description Angular resource to fetch /api/core/flavors/:id/
-  **/
-  .service('Flavors', ["$resource", function ($resource) {
-    return $resource('/api/core/flavors/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Flavors.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Example-Services-Collection
-  * @description Angular resource to fetch /api/service/exampleservice/
-  **/
-  .service('Example-Services-Collection', ["$resource", function ($resource) {
-    return $resource('/api/service/exampleservice/');
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Example.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  angular.module('xos.helpers')
-  /**
-  * @ngdoc service
-  * @name xos.helpers.Deployments
-  * @description Angular resource to fetch /api/core/deployments/:id/
-  **/
-  .service('Deployments', ["$resource", function ($resource) {
-    return $resource('/api/core/deployments/:id/', { id: '@id' }, {
-      update: { method: 'PUT' }
-    });
-  }]);
-})();
-//# sourceMappingURL=../../maps/services/rest/Deployments.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  /**
-  * @ngdoc service
-  * @name xos.helpers.ServiceGraph
-  * @description This factory define a set of helper function to query the service tenancy graph
-  **/
-
-  angular.module('xos.helpers').service('GraphService', ["$q", "Tenants", "Services", function ($q, Tenants, Services) {
-    var _this = this;
-
-    this.loadCoarseData = function () {
-
-      var services = void 0;
-
-      var deferred = $q.defer();
-
-      Services.query().$promise.then(function (res) {
-        services = res;
-        return Tenants.query({ kind: 'coarse' }).$promise;
-      }).then(function (tenants) {
-        deferred.resolve({
-          tenants: tenants,
-          services: services
-        });
-      });
-
-      return deferred.promise;
-    };
-
-    this.getCoarseGraph = function () {
-      _this.loadCoarseData().then(function (res) {
-        console.log(res);
-      });
-      return 'ciao';
-    };
-  }]);
-})();
-//# sourceMappingURL=../maps/services/service_graph.service.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  /**
-  * @ngdoc service
-  * @name xos.helpers.NoHyperlinks
-  * @description This factory is automatically loaded trough xos.helpers and will add an $http interceptor that will add ?no_hyperlinks=1 to your api request, that is required by django
-  **/
-
-  angular.module('xos.helpers').factory('NoHyperlinks', noHyperlinks);
-
-  function noHyperlinks() {
-    return {
-      request: function request(_request) {
-        if (_request.url.indexOf('.html') === -1) {
-          _request.url += '?no_hyperlinks=1';
-        }
-        return _request;
-      }
-    };
-  }
-})();
-//# sourceMappingURL=../maps/services/noHyperlinks.interceptor.js.map
-
-'use strict';
-
-// TODO write tests for log
-
-angular.module('xos.helpers').config(['$provide', function ($provide) {
-  // Use the `decorator` solution to substitute or attach behaviors to
-  // original service instance; @see angular-mocks for more examples....
-
-  $provide.decorator('$log', ['$delegate', function ($delegate) {
-
-    var isLogEnabled = function isLogEnabled() {
-      return window.location.href.indexOf('debug=true') >= 0;
-    };
-    // Save the original $log.debug()
-    var logFn = $delegate.log;
-    var infoFn = $delegate.info;
-    var warnFn = $delegate.warn;
-    var errorFn = $delegate.error;
-    var debugFn = $delegate.debug;
-
-    // create the replacement function
-    var replacement = function replacement(fn) {
-      return function () {
-        // console.log(`Is Log Enabled: ${isLogEnabled()}`)
-        if (!isLogEnabled()) {
-          // console.log('logging is disabled');
-          return;
-        }
-        var args = [].slice.call(arguments);
-        var now = new Date();
-
-        // Prepend timestamp
-        args[0] = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] ' + args[0];
-
-        // HACK awfull fix for angular mock implementation whithin jasmine test failing issue
-        if (typeof $delegate.reset === 'function' && !($delegate.debug.logs instanceof Array)) {
-          // if we are within the mock and did not reset yet, we call it to avoid issue
-          // console.log('mock log impl fix to avoid logs array not existing...');
-          $delegate.reset();
-        }
-
-        // Call the original with the output prepended with formatted timestamp
-        fn.apply(null, args);
-      };
-    };
-
-    $delegate.info = replacement(infoFn);
-    $delegate.log = replacement(logFn);
-    $delegate.warn = replacement(warnFn);
-    $delegate.error = replacement(errorFn);
-    $delegate.debug = replacement(debugFn);
-
-    return $delegate;
-  }]);
-}]);
-//# sourceMappingURL=../maps/services/log.decorator.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  /**
-  * @ngdoc service
-  * @name xos.helpers.LabelFormatter
-  * @description This factory define a set of helper function to format label started from an object property
-  **/
-
-  angular.module('xos.uiComponents').factory('LabelFormatter', labelFormatter);
-
-  function labelFormatter() {
-
-    var _formatByUnderscore = function _formatByUnderscore(string) {
-      return string.split('_').join(' ').trim();
-    };
-
-    var _formatByUppercase = function _formatByUppercase(string) {
-      return string.split(/(?=[A-Z])/).map(function (w) {
-        return w.toLowerCase();
-      }).join(' ');
-    };
-
-    var _capitalize = function _capitalize(string) {
-      return string.slice(0, 1).toUpperCase() + string.slice(1);
-    };
-
-    var format = function format(string) {
-      string = _formatByUnderscore(string);
-      string = _formatByUppercase(string);
-
-      string = _capitalize(string).replace(/\s\s+/g, ' ') + ':';
-      return string.replace('::', ':');
-    };
-
-    return {
-      // test export
-      _formatByUnderscore: _formatByUnderscore,
-      _formatByUppercase: _formatByUppercase,
-      _capitalize: _capitalize,
-      // export to use
-      format: format
-    };
-  }
-})();
-//# sourceMappingURL=../maps/services/label_formatter.service.js.map
-
-'use strict';
-
-(function () {
-  'use strict';
-
-  /**
-  * @ngdoc service
-  * @name xos.helpers.SetCSRFToken
-  * @description This factory is automatically loaded trough xos.helpers and will add an $http interceptor that will the CSRF-Token to your request headers
-  **/
-
-  setCSRFToken.$inject = ["$cookies"];
-  angular.module('xos.helpers').factory('SetCSRFToken', setCSRFToken);
-
-  function setCSRFToken($cookies) {
-    return {
-      request: function request(_request) {
-        if (_request.method !== 'GET') {
-          _request.headers['X-CSRFToken'] = $cookies.get('xoscsrftoken');
-        }
-        return _request;
-      }
-    };
-  }
-})();
-//# sourceMappingURL=../maps/services/csrfToken.interceptor.js.map
+"use strict";!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper"])}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").directive("xosSmartTable",function(){return{restrict:"E",scope:{config:"="},template:'\n        <div class="row" ng-show="vm.data.length > 0">\n          <div class="col-xs-12 text-right">\n            <a href="" class="btn btn-success" ng-click="vm.createItem()">\n              Add\n            </a>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12 table-responsive">\n            <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n          </div>\n        </div>\n        <div class="panel panel-default" ng-show="vm.detailedItem">\n          <div class="panel-heading">\n            <div class="row">\n              <div class="col-xs-11">\n                <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n                <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n              </div>\n              <div class="col-xs-1">\n                <a href="" ng-click="vm.cleanForm()">\n                  <i class="glyphicon glyphicon-remove pull-right"></i>\n                </a>\n              </div>\n            </div>\n          </div>\n          <div class="panel-body">\n            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n          </div>\n        </div>\n        <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n        <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,o,t){var i=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){i.Resource["delete"]({id:e.id}).$promise.then(function(){o.remove(i.data,function(n){return n.id===e.id}),i.responseMsg=i.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){i.responseErr=n.data.detail||"Error while deleting "+i.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){i.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,o=!0;e.id?(n=e.$update(),o=!1):n=e.$save(),n.then(function(n){o&&i.data.push(angular.copy(n)),delete i.detailedItem,i.responseMsg=i.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){i.responseErr=n.data.detail||"Error while saving "+i.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete i.detailedItem},this.createItem=function(){i.detailedItem=new i.Resource},this.Resource=e.get(this.config.resource);var r=function(){i.Resource.query().$promise.then(function(e){if(e[0]){var r=e[0],s=Object.keys(r);o.remove(s,function(e){return"id"===e||"validators"===e}),angular.isArray(i.config.hiddenFields)&&(s=o.difference(s,i.config.hiddenFields));var a=s.map(function(e){return n.format(e)});s.forEach(function(e,n){var o={label:a[n],prop:e};"string"!=typeof r[e]&&"undefined"!=typeof r[e]&&(o.type=_typeof(r[e])),i.tableConfig.columns.push(o)}),s.forEach(function(e,o){i.formConfig.fields[e]={label:n.format(a[o]).replace(":",""),type:t._getFieldFormat(r[e])}}),i.data=e}})};r()}]}})}(),function(){angular.module("xos.uiComponents").directive("xosValidation",function(){return{restrict:"E",scope:{field:"=",form:"="},template:'\n        <div ng-cloak>\n          <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">\n            Field required\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">\n            This is not a valid email\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">\n            Too short\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">\n            Too long\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">\n            Field invalid\n          </xos-alert>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}}})}(),function(){angular.module("xos.uiComponents").directive("xosSmartPie",function(){return{restrict:"E",scope:{config:"="},template:'\n        <canvas\n          class="chart chart-pie {{vm.config.classes}}"\n          chart-data="vm.data" chart-labels="vm.labels"\n          chart-legend="{{vm.config.legend}}">\n        </canvas>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,o,t,i){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var s=function(e){return i.groupBy(e,r.config.groupBy)},a=function(e){return i.reduce(Object.keys(e),function(n,o){return n.concat(e[o].length)},[])},l=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},c=function(e){var n=s(e);r.data=a(n),r.labels=l(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var o=function(){r.Resource.query().$promise.then(function(e){e[0]&&c(e)})};o(),r.config.poll&&n(function(){o()},1e3*r.config.poll)}():o.$watch(function(){return r.config.data},function(e){e&&c(r.config.data)},!0),o.$on("create",function(e,n){console.log("create: "+n.id)}),o.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosTable",function(){return{restrict:"E",scope:{data:"=",config:"="},template:'\n          <div ng-show="vm.data.length > 0">\n            <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n              <div class="col-xs-12">\n                <input\n                  class="form-control"\n                  placeholder="Type to search.."\n                  type="text"\n                  ng-model="vm.query"/>\n              </div>\n            </div>\n            <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n              <thead>\n                <tr>\n                  <th ng-repeat="col in vm.columns">\n                    {{col.label}}\n                    <span ng-if="vm.config.order">\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n                        <i class="glyphicon glyphicon-chevron-up"></i>\n                      </a>\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n                        <i class="glyphicon glyphicon-chevron-down"></i>\n                      </a>\n                    </span>\n                  </th>\n                  <th ng-if="vm.config.actions">Actions:</th>\n                </tr>\n              </thead>\n              <tbody ng-if="vm.config.filter == \'field\'">\n                <tr>\n                  <td ng-repeat="col in vm.columns">\n                    <input\n                      ng-if="col.type !== \'boolean\'"\n                      class="form-control"\n                      placeholder="Type to search by {{col.label}}"\n                      type="text"\n                      ng-model="vm.query[col.prop]"/>\n                    <select\n                      ng-if="col.type === \'boolean\'"\n                      class="form-control"\n                      ng-model="vm.query[col.prop]">\n                      <option value="">-</option>\n                      <option value="true">True</option>\n                      <option value="false">False</option>\n                    </select>\n                  </td>\n                  <td ng-if="vm.config.actions"></td>\n                </tr>\n              </tbody>\n              <tbody>\n                <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n                  <td ng-repeat="col in vm.columns" link-wrapper>\n                    <span ng-if="!col.type">{{item[col.prop]}}</span>\n                    <span ng-if="col.type === \'boolean\'">\n                      <i class="glyphicon"\n                        ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n                      </i>\n                    </span>\n                    <span ng-if="col.type === \'date\'">\n                      {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n                    </span>\n                    <span ng-if="col.type === \'array\'">\n                      {{item[col.prop] | arrayToList}}\n                    </span>\n                    <span ng-if="col.type === \'object\'">\n                      <dl class="dl-horizontal">\n                        <span ng-repeat="(k,v) in item[col.prop]">\n                          <dt>{{k}}</dt>\n                          <dd>{{v}}</dd>\n                        </span>\n                      </dl>\n                    </span>\n                    <span ng-if="col.type === \'custom\'">\n                      {{col.formatter(item)}}\n                    </span>\n                    <span ng-if="col.type === \'icon\'">\n                      <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n                      </i>\n                    </span>\n                  </td>\n                  <td ng-if="vm.config.actions">\n                    <a href=""\n                      ng-repeat="action in vm.config.actions"\n                      ng-click="action.cb(item)"\n                      title="{{action.label}}">\n                      <i\n                        class="glyphicon glyphicon-{{action.icon}}"\n                        style="color: {{action.color}};"></i>\n                    </a>\n                  </td>\n                </tr>\n              </tbody>\n            </table>\n            <xos-pagination\n              ng-if="vm.config.pagination"\n              page-size="vm.config.pagination.pageSize"\n              total-elements="vm.data.length"\n              change="vm.goToPage">\n              </xos-pagination>\n          </div>\n          <div ng-show="vm.data.length == 0 || !vm.data">\n             <xos-alert config="{type: \'info\'}">\n              No data to show.\n            </xos-alert>\n          </div>\n        ',bindToController:!0,controllerAs:"vm",controller:["_",function(e){var n=this;if(!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var o=e.filter(this.config.columns,{type:"custom"});angular.isArray(o)&&o.length>0&&e.forEach(o,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var t=e.filter(this.config.columns,{type:"icon"});angular.isArray(t)&&t.length>0&&e.forEach(t,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var i=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(i)&&i.length>0&&e.forEach(i,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){n.currentPage=e})}]}}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("linkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n          <a ng-if="col.link" href="{{col.link(item)}}">\n            <div ng-transclude></div>\n          </a>\n          <div ng-transclude ng-if="!col.link"></div>\n        '}})}(),function(){angular.module("xos.uiComponents").directive("xosPagination",function(){return{restrict:"E",scope:{pageSize:"=",totalElements:"=",change:"="},template:'\n        <div class="row" ng-if="vm.pageList.length > 1">\n          <div class="col-xs-12 text-center">\n            <ul class="pagination">\n              <li\n                ng-click="vm.goToPage(vm.currentPage - 1)"\n                ng-class="{disabled: vm.currentPage == 0}">\n                <a href="" aria-label="Previous">\n                    <span aria-hidden="true">&laquo;</span>\n                </a>\n              </li>\n              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n              </li>\n              <li\n                ng-click="vm.goToPage(vm.currentPage + 1)"\n                ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n                <a href="" aria-label="Next">\n                    <span aria-hidden="true">&raquo;</span>\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){0>e||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],o=0;e>o;o++)n.push(o);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").directive("xosForm",function(){return{restrict:"E",scope:{config:"=",ngModel:"="},template:'\n        <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n          <div class="form-group" ng-repeat="(name, field) in vm.formField">\n            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n            <xos-validation field="vm[vm.config.formName || \'form\'][name]" form="vm[vm.config.formName || \'form\']"></xos-validation>\n          </div>\n          <div class="form-group" ng-if="vm.config.actions">\n            <button role="button" href=""\n              ng-repeat="action in vm.config.actions"\n              ng-click="action.cb(vm.ngModel)"\n              class="btn btn-{{action.class}}"\n              title="{{action.label}}">\n              <i class="glyphicon glyphicon-{{action.icon}}"></i>\n              {{action.label}}\n            </button>\n          </div>\n        </ng-form>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,o,t){var i=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return i.ngModel},function(e){if(i.formField={},e){var n=o.difference(Object.keys(e),i.excludedField),r=t.parseModelField(n);i.formField=t.buildFormStructure(r,i.config.fields,e)}})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosField",["RecursionHelper",function(e){return{restrict:"E",scope:{name:"=",field:"=",ngModel:"="},template:'\n        <label ng-if="vm.field.type !== \'object\'">{{vm.field.label}}</label>\n            <input\n              ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\' && vm.field.type !== \'select\'"\n              type="{{vm.field.type}}"\n              name="{{vm.name}}"\n              class="form-control"\n              ng-model="vm.ngModel"\n              ng-minlength="vm.field.validators.minlength || 0"\n              ng-maxlength="vm.field.validators.maxlength || 2000"\n              ng-required="vm.field.validators.required || false" />\n              <select class="form-control" ng-if ="vm.field.type === \'select\'"\n                name = "{{vm.name}}"\n                ng-options="item.id as item.label for item in vm.field.options track by item.id"\n                ng-model="vm.ngModel"\n                ng-required="vm.field.validators.required || false">\n                </select>\n            <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n              <button\n                class="btn btn-success"\n                ng-show="vm.ngModel"\n                ng-click="vm.ngModel = false">\n                <i class="glyphicon glyphicon-ok"></i>\n              </button>\n              <button\n                class="btn btn-danger"\n                ng-show="!vm.ngModel"\n                ng-click="vm.ngModel = true">\n                <i class="glyphicon glyphicon-remove"></i>\n              </button>\n            </span>\n            <div\n              class="panel panel-default object-field"\n              ng-if="vm.field.type == \'object\' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"\n              >\n              <div class="panel-heading">{{vm.field.label}}</div>\n              <div class="panel-body">\n                <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">\n                  <xos-field\n                    name="k"\n                    field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n                    ng-model="v">\n                  </xos-field>\n                </div>\n                <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">\n                  <xos-field\n                    name="k"\n                    field="{\n                      label: v.label || vm.formatLabel(k),\n                      type: v.type,\n                      validators: v.validators\n                    }"\n                    ng-model="vm.ngModel[k]">\n                  </xos-field>\n                </div>\n              </div>\n            </div>\n      ',bindToController:!0,controllerAs:"vm",compile:function(n){return e.compile(n)},controller:["$attrs","XosFormHelpers","LabelFormatter",function(e,n,o){if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!this.field.type)throw new Error("[xosField] Please provide a type in the field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=n._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return e?0===Object.keys(e).length:!0}}]}}])}(),function(){angular.module("xos.uiComponents").directive("xosAlert",function(){return{restrict:"E",scope:{config:"=",show:"=?"},template:'\n        <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n            <span aria-hidden="true">&times;</span>\n          </button>\n          <p ng-transclude></p>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var o=e(function(){n.dismiss(),e.cancel(o)},n.config.autoHide)}()}]}})}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var o=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(n){return angular.isArray(n)?"array":e.isDate(n)||!Number.isNaN(Date.parse(n))&&new Date(n).getTime()>6311808e5?"date":"boolean"==typeof n?"boolean":o._isEmail(n)?"email":"string"==typeof n||null===n?"text":"undefined"==typeof n?"undefined":_typeof(n)},this.buildFormStructure=function(t,i,r){return t=angular.extend(t,i),i=i||{},e.reduce(Object.keys(t),function(e,t){return e[t]={label:i[t]&&i[t].label?i[t].label+":":n.format(t),type:i[t]&&i[t].type?i[t].type:o._getFieldFormat(r[t]),validators:i[t]&&i[t].validators?i[t].validators:{},hint:i[t]&&i[t].hint?i[t].hint:""},i[t]&&i[t].options&&(e[t].options=i[t].options),i[t]&&i[t].properties&&(e[t].properties=i[t].properties),"date"===e[t].type&&(r[t]=new Date(r[t])),"number"===e[t].type&&(r[t]=parseInt(r[t],10)),e},{})},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){function e(e,n,o){e.interceptors.push("SetCSRFToken"),n.startSymbol("{$"),n.endSymbol("$}"),o.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("bugSnag",[]).factory("$exceptionHandler",function(){return function(e,n){window.Bugsnag?Bugsnag.notifyException(e,{diagnostics:{cause:n}}):console.error(e,n,e.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","bugSnag","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(o){var t=n.defer();return e.get("/api/utility/slicesplus/",{params:o}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}},this.get=function(o,t){var i=n.defer();return e.get("/api/utility/slicesplus/"+o,{params:t}).then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e.data)}),{$promise:i.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies",function(e){var n=this,o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{};this.getAll=function(){return o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",JSON.stringify(n))},this.getSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return e?n.getAll().synchronizers.notification[e]:n.getAll().synchronizers.notification},this.setSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],o=arguments[1];if(!e)throw new Error("[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.");var t=n.getAll();t.synchronizers||(t.synchronizers={notification:{}}),t.synchronizers.notification[e]=o,n.setAll(t)}}])}(),function(){angular.module("xos.helpers").service("GraphService",["$q","Tenants","Services",function(e,n,o){var t=this;this.loadCoarseData=function(){var t=void 0,i=e.defer();return o.query().$promise.then(function(e){return t=e,n.query({kind:"coarse"}).$promise}).then(function(e){i.resolve({tenants:e,services:t})}),i.promise},this.getCoarseGraph=function(){return t.loadCoarseData().then(function(e){console.log(e)}),"ciao"}}])}(),function(){angular.module("xos.helpers").factory("Notification",function(){return window.Notification}).service("xosNotification",["$q","$log","Notification",function(e,n,o){var t=this;this.checkPermission=function(){var n=e.defer();return o.requestPermission().then(function(e){"granted"===e?n.resolve(e):n.reject(e)}),n.promise},this.sendNotification=function(e,t){var i=new o(e,t);i.onerror=function(e){n.error(e)}},this.notify=function(e,i){"Notification"in window?"granted"!==o.permission?t.checkPermission().then(function(){return t.sendNotification(e,i)}):"granted"===o.permission&&t.sendNotification(e,i):n.info("This browser does not support desktop notification")}}])}(),function(){function e(){return{request:function(e){return-1===e.url.indexOf(".html")&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),angular.module("xos.helpers").config(["$provide",function(e){e.decorator("$log",["$delegate",function(e){var n=function(){return window.location.href.indexOf("debug=true")>=0},o=e.log,t=e.info,i=e.warn,r=e.error,s=e.debug,a=function(o){return function(){if(n()){var t=[].slice.call(arguments),i=new Date;t[0]="["+i.getHours()+":"+i.getMinutes()+":"+i.getSeconds()+"] "+t[0],"function"!=typeof e.reset||e.debug.logs instanceof Array||e.reset(),o.apply(null,t)}}};return e.info=a(t),e.log=a(o),e.warn=a(i),e.error=a(r),e.debug=a(s),e}])}]),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}(),function(){function e(e){return{request:function(n){return"GET"!==n.method&&(n.headers["X-CSRFToken"]=e.get("xoscsrftoken")),n}}}e.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",e)}();
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/vendor/ngXosVendor.js b/xos/core/xoslib/static/js/vendor/ngXosVendor.js
index ab8f370..78eee30 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosVendor.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosVendor.js
@@ -13,4 +13,4 @@
 }function Pe(t){return t[1]}function Oe(t){for(var n=t.length,e=[0,1],r=2,i=2;n>i;i++){for(;r>1&&Q(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function Te(t,n){return t[0]-n[0]||t[1]-n[1]}function Le(t,n,e){return(e[0]-n[0])*(t[1]-n[1])<(e[1]-n[1])*(t[0]-n[0])}function je(t,n,e,r){var i=t[0],o=e[0],a=n[0]-i,u=r[0]-o,s=t[1],l=e[1],c=n[1]-s,f=r[1]-l,h=(u*(s-l)-f*(i-o))/(f*a-u*c);return[i+h*a,s+h*c]}function Ne(t){var n=t[0],e=t[t.length-1];return!(n[0]-e[0]||n[1]-e[1])}function Re(){rr(this),this.edge=this.site=this.circle=null}function De(t){var n=ls.pop()||new Re;return n.site=t,n}function Fe(t){Ge(t),as.remove(t),ls.push(t),rr(t)}function Ie(t){var n=t.circle,e=n.x,r=n.cy,i={x:e,y:r},o=t.P,a=t.N,u=[t];Fe(t);for(var s=o;s.circle&&xa(e-s.circle.x)<Da&&xa(r-s.circle.cy)<Da;)o=s.P,u.unshift(s),Fe(s),s=o;u.unshift(s),Ge(s);for(var l=a;l.circle&&xa(e-l.circle.x)<Da&&xa(r-l.circle.cy)<Da;)a=l.N,u.push(l),Fe(l),l=a;u.push(l),Ge(l);var c,f=u.length;for(c=1;f>c;++c)l=u[c],s=u[c-1],tr(l.edge,s.site,l.site,i);s=u[0],l=u[f-1],l.edge=Ke(s.site,l.site,null,i),Ye(s),Ye(l)}function ze(t){for(var n,e,r,i,o=t.x,a=t.y,u=as._;u;)if(r=qe(u,a)-o,r>Da)u=u.L;else{if(i=o-Ve(u,a),!(i>Da)){r>-Da?(n=u.P,e=u):i>-Da?(n=u,e=u.N):n=e=u;break}if(!u.R){n=u;break}u=u.R}var s=De(t);if(as.insert(n,s),n||e){if(n===e)return Ge(n),e=De(n.site),as.insert(s,e),s.edge=e.edge=Ke(n.site,s.site),Ye(n),void Ye(e);if(!e)return void(s.edge=Ke(n.site,s.site));Ge(n),Ge(e);var l=n.site,c=l.x,f=l.y,h=t.x-c,p=t.y-f,d=e.site,v=d.x-c,g=d.y-f,m=2*(h*g-p*v),y=h*h+p*p,$=v*v+g*g,x={x:(g*y-p*$)/m+c,y:(h*$-v*y)/m+f};tr(e.edge,l,d,x),s.edge=Ke(l,t,null,x),e.edge=Ke(t,d,null,x),Ye(n),Ye(e)}}function qe(t,n){var e=t.site,r=e.x,i=e.y,o=i-n;if(!o)return r;var a=t.P;if(!a)return-(1/0);e=a.site;var u=e.x,s=e.y,l=s-n;if(!l)return u;var c=u-r,f=1/o-1/l,h=c/l;return f?(-h+Math.sqrt(h*h-2*f*(c*c/(-2*l)-s+l/2+i-o/2)))/f+r:(r+u)/2}function Ve(t,n){var e=t.N;if(e)return qe(e,n);var r=t.site;return r.y===n?r.x:1/0}function Be(t){this.site=t,this.edges=[]}function We(t){for(var n,e,r,i,o,a,u,s,l,c,f=t[0][0],h=t[1][0],p=t[0][1],d=t[1][1],v=os,g=v.length;g--;)if(o=v[g],o&&o.prepare())for(u=o.edges,s=u.length,a=0;s>a;)c=u[a].end(),r=c.x,i=c.y,l=u[++a%s].start(),n=l.x,e=l.y,(xa(r-n)>Da||xa(i-e)>Da)&&(u.splice(a,0,new nr(Qe(o.site,c,xa(r-f)<Da&&d-i>Da?{x:f,y:xa(n-f)<Da?e:d}:xa(i-d)<Da&&h-r>Da?{x:xa(e-d)<Da?n:h,y:d}:xa(r-h)<Da&&i-p>Da?{x:h,y:xa(n-h)<Da?e:p}:xa(i-p)<Da&&r-f>Da?{x:xa(e-p)<Da?n:f,y:p}:null),o.site,null)),++s)}function Ue(t,n){return n.angle-t.angle}function He(){rr(this),this.x=this.y=this.arc=this.site=this.cy=null}function Ye(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var a=i.x,u=i.y,s=r.x-a,l=r.y-u,c=o.x-a,f=o.y-u,h=2*(s*f-l*c);if(!(h>=-Fa)){var p=s*s+l*l,d=c*c+f*f,v=(f*p-l*d)/h,g=(s*d-c*p)/h,f=g+u,m=cs.pop()||new He;m.arc=t,m.site=i,m.x=v+a,m.y=f+Math.sqrt(v*v+g*g),m.cy=f,t.circle=m;for(var y=null,$=ss._;$;)if(m.y<$.y||m.y===$.y&&m.x<=$.x){if(!$.L){y=$.P;break}$=$.L}else{if(!$.R){y=$;break}$=$.R}ss.insert(y,m),y||(us=m)}}}}function Ge(t){var n=t.circle;n&&(n.P||(us=n.N),ss.remove(n),cs.push(n),rr(n),t.circle=null)}function Xe(t){for(var n,e=is,r=Bn(t[0][0],t[0][1],t[1][0],t[1][1]),i=e.length;i--;)n=e[i],(!Ze(n,t)||!r(n)||xa(n.a.x-n.b.x)<Da&&xa(n.a.y-n.b.y)<Da)&&(n.a=n.b=null,e.splice(i,1))}function Ze(t,n){var e=t.b;if(e)return!0;var r,i,o=t.a,a=n[0][0],u=n[1][0],s=n[0][1],l=n[1][1],c=t.l,f=t.r,h=c.x,p=c.y,d=f.x,v=f.y,g=(h+d)/2,m=(p+v)/2;if(v===p){if(a>g||g>=u)return;if(h>d){if(o){if(o.y>=l)return}else o={x:g,y:s};e={x:g,y:l}}else{if(o){if(o.y<s)return}else o={x:g,y:l};e={x:g,y:s}}}else if(r=(h-d)/(v-p),i=m-r*g,-1>r||r>1)if(h>d){if(o){if(o.y>=l)return}else o={x:(s-i)/r,y:s};e={x:(l-i)/r,y:l}}else{if(o){if(o.y<s)return}else o={x:(l-i)/r,y:l};e={x:(s-i)/r,y:s}}else if(v>p){if(o){if(o.x>=u)return}else o={x:a,y:r*a+i};e={x:u,y:r*u+i}}else{if(o){if(o.x<a)return}else o={x:u,y:r*u+i};e={x:a,y:r*a+i}}return t.a=o,t.b=e,!0}function Je(t,n){this.l=t,this.r=n,this.a=this.b=null}function Ke(t,n,e,r){var i=new Je(t,n);return is.push(i),e&&tr(i,t,n,e),r&&tr(i,n,t,r),os[t.i].edges.push(new nr(i,t,n)),os[n.i].edges.push(new nr(i,n,t)),i}function Qe(t,n,e){var r=new Je(t,null);return r.a=n,r.b=e,is.push(r),r}function tr(t,n,e,r){t.a||t.b?t.l===e?t.b=r:t.a=r:(t.a=r,t.l=n,t.r=e)}function nr(t,n,e){var r=t.a,i=t.b;this.edge=t,this.site=n,this.angle=e?Math.atan2(e.y-n.y,e.x-n.x):t.l===n?Math.atan2(i.x-r.x,r.y-i.y):Math.atan2(r.x-i.x,i.y-r.y)}function er(){this._=null}function rr(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function ir(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function or(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function ar(t){for(;t.L;)t=t.L;return t}function ur(t,n){var e,r,i,o=t.sort(sr).pop();for(is=[],os=new Array(t.length),as=new er,ss=new er;;)if(i=us,o&&(!i||o.y<i.y||o.y===i.y&&o.x<i.x))o.x===e&&o.y===r||(os[o.i]=new Be(o),ze(o),e=o.x,r=o.y),o=t.pop();else{if(!i)break;Ie(i.arc)}n&&(Xe(n),We(n));var a={cells:os,edges:is};return as=ss=is=os=null,a}function sr(t,n){return n.y-t.y||n.x-t.x}function lr(t,n,e){return(t.x-e.x)*(n.y-t.y)-(t.x-n.x)*(e.y-t.y)}function cr(t){return t.x}function fr(t){return t.y}function hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pr(t,n,e,r,i,o){if(!t(n,e,r,i,o)){var a=.5*(e+i),u=.5*(r+o),s=n.nodes;s[0]&&pr(t,s[0],e,r,a,u),s[1]&&pr(t,s[1],a,r,i,u),s[2]&&pr(t,s[2],e,u,a,o),s[3]&&pr(t,s[3],a,u,i,o)}}function dr(t,n,e,r,i,o,a){var u,s=1/0;return function l(t,c,f,h,p){if(!(c>o||f>a||r>h||i>p)){if(d=t.point){var d,v=n-t.x,g=e-t.y,m=v*v+g*g;if(s>m){var y=Math.sqrt(s=m);r=n-y,i=e-y,o=n+y,a=e+y,u=d}}for(var $=t.nodes,x=.5*(c+h),b=.5*(f+p),w=n>=x,C=e>=b,S=C<<1|w,_=S+4;_>S;++S)if(t=$[3&S])switch(3&S){case 0:l(t,c,f,x,b);break;case 1:l(t,x,f,h,b);break;case 2:l(t,c,b,x,p);break;case 3:l(t,x,b,h,p)}}}(t,r,i,o,a),u}function vr(t,n){t=sa.rgb(t),n=sa.rgb(n);var e=t.r,r=t.g,i=t.b,o=n.r-e,a=n.g-r,u=n.b-i;return function(t){return"#"+xt(Math.round(e+o*t))+xt(Math.round(r+a*t))+xt(Math.round(i+u*t))}}function gr(t,n){var e,r={},i={};for(e in t)e in n?r[e]=$r(t[e],n[e]):i[e]=t[e];for(e in n)e in t||(i[e]=n[e]);return function(t){for(e in r)i[e]=r[e](t);return i}}function mr(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function yr(t,n){var e,r,i,o=hs.lastIndex=ps.lastIndex=0,a=-1,u=[],s=[];for(t+="",n+="";(e=hs.exec(t))&&(r=ps.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,s.push({i:a,x:mr(e,r)})),o=ps.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?s[0]?(n=s[0].x,function(t){return n(t)+""}):function(){return n}:(n=s.length,function(t){for(var e,r=0;n>r;++r)u[(e=s[r]).i]=e.x(t);return u.join("")})}function $r(t,n){for(var e,r=sa.interpolators.length;--r>=0&&!(e=sa.interpolators[r](t,n)););return e}function xr(t,n){var e,r=[],i=[],o=t.length,a=n.length,u=Math.min(t.length,n.length);for(e=0;u>e;++e)r.push($r(t[e],n[e]));for(;o>e;++e)i[e]=t[e];for(;a>e;++e)i[e]=n[e];return function(t){for(e=0;u>e;++e)i[e]=r[e](t);return i}}function br(t){return function(n){return 0>=n?0:n>=1?1:t(n)}}function wr(t){return function(n){return 1-t(1-n)}}function Cr(t){return function(n){return.5*(.5>n?t(2*n):2-t(2-2*n))}}function Sr(t){return t*t}function _r(t){return t*t*t}function Mr(t){if(0>=t)return 0;if(t>=1)return 1;var n=t*t,e=n*t;return 4*(.5>t?e:3*(t-n)+e-.75)}function kr(t){return function(n){return Math.pow(n,t)}}function Ar(t){return 1-Math.cos(t*Va)}function Er(t){return Math.pow(2,10*(t-1))}function Pr(t){return 1-Math.sqrt(1-t*t)}function Or(t,n){var e;return arguments.length<2&&(n=.45),arguments.length?e=n/za*Math.asin(1/t):(t=1,e=n/4),function(r){return 1+t*Math.pow(2,-10*r)*Math.sin((r-e)*za/n)}}function Tr(t){return t||(t=1.70158),function(n){return n*n*((t+1)*n-t)}}function Lr(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}function jr(t,n){t=sa.hcl(t),n=sa.hcl(n);var e=t.h,r=t.c,i=t.l,o=n.h-e,a=n.c-r,u=n.l-i;return isNaN(a)&&(a=0,r=isNaN(r)?n.c:r),isNaN(o)?(o=0,e=isNaN(e)?n.h:e):o>180?o-=360:-180>o&&(o+=360),function(t){return ct(e+o*t,r+a*t,i+u*t)+""}}function Nr(t,n){t=sa.hsl(t),n=sa.hsl(n);var e=t.h,r=t.s,i=t.l,o=n.h-e,a=n.s-r,u=n.l-i;return isNaN(a)&&(a=0,r=isNaN(r)?n.s:r),isNaN(o)?(o=0,e=isNaN(e)?n.h:e):o>180?o-=360:-180>o&&(o+=360),function(t){return st(e+o*t,r+a*t,i+u*t)+""}}function Rr(t,n){t=sa.lab(t),n=sa.lab(n);var e=t.l,r=t.a,i=t.b,o=n.l-e,a=n.a-r,u=n.b-i;return function(t){return ht(e+o*t,r+a*t,i+u*t)+""}}function Dr(t,n){return n-=t,function(e){return Math.round(t+n*e)}}function Fr(t){var n=[t.a,t.b],e=[t.c,t.d],r=zr(n),i=Ir(n,e),o=zr(qr(e,n,-i))||0;n[0]*e[1]<e[0]*n[1]&&(n[0]*=-1,n[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(n[1],n[0]):Math.atan2(-e[0],e[1]))*Wa,this.translate=[t.e,t.f],this.scale=[r,o],this.skew=o?Math.atan2(i,o)*Wa:0}function Ir(t,n){return t[0]*n[0]+t[1]*n[1]}function zr(t){var n=Math.sqrt(Ir(t,t));return n&&(t[0]/=n,t[1]/=n),n}function qr(t,n,e){return t[0]+=e*n[0],t[1]+=e*n[1],t}function Vr(t){return t.length?t.pop()+",":""}function Br(t,n,e,r){if(t[0]!==n[0]||t[1]!==n[1]){var i=e.push("translate(",null,",",null,")");r.push({i:i-4,x:mr(t[0],n[0])},{i:i-2,x:mr(t[1],n[1])})}else(n[0]||n[1])&&e.push("translate("+n+")")}function Wr(t,n,e,r){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),r.push({i:e.push(Vr(e)+"rotate(",null,")")-2,x:mr(t,n)})):n&&e.push(Vr(e)+"rotate("+n+")")}function Ur(t,n,e,r){t!==n?r.push({i:e.push(Vr(e)+"skewX(",null,")")-2,x:mr(t,n)}):n&&e.push(Vr(e)+"skewX("+n+")")}function Hr(t,n,e,r){if(t[0]!==n[0]||t[1]!==n[1]){var i=e.push(Vr(e)+"scale(",null,",",null,")");r.push({i:i-4,x:mr(t[0],n[0])},{i:i-2,x:mr(t[1],n[1])})}else 1===n[0]&&1===n[1]||e.push(Vr(e)+"scale("+n+")")}function Yr(t,n){var e=[],r=[];return t=sa.transform(t),n=sa.transform(n),Br(t.translate,n.translate,e,r),Wr(t.rotate,n.rotate,e,r),Ur(t.skew,n.skew,e,r),Hr(t.scale,n.scale,e,r),t=n=null,function(t){for(var n,i=-1,o=r.length;++i<o;)e[(n=r[i]).i]=n.x(t);return e.join("")}}function Gr(t,n){return n=(n-=t=+t)||1/n,function(e){return(e-t)/n}}function Xr(t,n){return n=(n-=t=+t)||1/n,function(e){return Math.max(0,Math.min(1,(e-t)/n))}}function Zr(t){for(var n=t.source,e=t.target,r=Kr(n,e),i=[n];n!==r;)n=n.parent,i.push(n);for(var o=i.length;e!==r;)i.splice(o,0,e),e=e.parent;return i}function Jr(t){for(var n=[],e=t.parent;null!=e;)n.push(t),t=e,e=e.parent;return n.push(t),n}function Kr(t,n){if(t===n)return t;for(var e=Jr(t),r=Jr(n),i=e.pop(),o=r.pop(),a=null;i===o;)a=i,i=e.pop(),o=r.pop();return a}function Qr(t){t.fixed|=2}function ti(t){t.fixed&=-7}function ni(t){t.fixed|=4,t.px=t.x,t.py=t.y}function ei(t){t.fixed&=-5}function ri(t,n,e){var r=0,i=0;if(t.charge=0,!t.leaf)for(var o,a=t.nodes,u=a.length,s=-1;++s<u;)o=a[s],null!=o&&(ri(o,n,e),t.charge+=o.charge,r+=o.charge*o.cx,i+=o.charge*o.cy);if(t.point){t.leaf||(t.point.x+=Math.random()-.5,t.point.y+=Math.random()-.5);var l=n*e[t.point.index];t.charge+=t.pointCharge=l,r+=l*t.point.x,i+=l*t.point.y}t.cx=r/t.charge,t.cy=i/t.charge}function ii(t,n){return sa.rebind(t,n,"sort","children","value"),t.nodes=t,t.links=ci,t}function oi(t,n){for(var e=[t];null!=(t=e.pop());)if(n(t),(i=t.children)&&(r=i.length))for(var r,i;--r>=0;)e.push(i[r])}function ai(t,n){for(var e=[t],r=[];null!=(t=e.pop());)if(r.push(t),(o=t.children)&&(i=o.length))for(var i,o,a=-1;++a<i;)e.push(o[a]);for(;null!=(t=r.pop());)n(t)}function ui(t){return t.children}function si(t){return t.value}function li(t,n){return n.value-t.value}function ci(t){return sa.merge(t.map(function(t){return(t.children||[]).map(function(n){return{source:t,target:n}})}))}function fi(t){return t.x}function hi(t){return t.y}function pi(t,n,e){t.y0=n,t.y=e}function di(t){return sa.range(t.length)}function vi(t){for(var n=-1,e=t[0].length,r=[];++n<e;)r[n]=0;return r}function gi(t){for(var n,e=1,r=0,i=t[0][1],o=t.length;o>e;++e)(n=t[e][1])>i&&(r=e,i=n);return r}function mi(t){return t.reduce(yi,0)}function yi(t,n){return t+n[1]}function $i(t,n){return xi(t,Math.ceil(Math.log(n.length)/Math.LN2+1))}function xi(t,n){for(var e=-1,r=+t[0],i=(t[1]-r)/n,o=[];++e<=n;)o[e]=i*e+r;return o}function bi(t){return[sa.min(t),sa.max(t)]}function wi(t,n){return t.value-n.value}function Ci(t,n){var e=t._pack_next;t._pack_next=n,n._pack_prev=t,n._pack_next=e,e._pack_prev=n}function Si(t,n){t._pack_next=n,n._pack_prev=t}function _i(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return.999*i*i>e*e+r*r}function Mi(t){function n(t){c=Math.min(t.x-t.r,c),f=Math.max(t.x+t.r,f),h=Math.min(t.y-t.r,h),p=Math.max(t.y+t.r,p)}if((e=t.children)&&(l=e.length)){var e,r,i,o,a,u,s,l,c=1/0,f=-(1/0),h=1/0,p=-(1/0);if(e.forEach(ki),r=e[0],r.x=-r.r,r.y=0,n(r),l>1&&(i=e[1],i.x=i.r,i.y=0,n(i),l>2))for(o=e[2],Pi(r,i,o),n(o),Ci(r,o),r._pack_prev=o,Ci(o,i),i=r._pack_next,a=3;l>a;a++){Pi(r,i,o=e[a]);var d=0,v=1,g=1;for(u=i._pack_next;u!==i;u=u._pack_next,v++)if(_i(u,o)){d=1;break}if(1==d)for(s=r._pack_prev;s!==u._pack_prev&&!_i(s,o);s=s._pack_prev,g++);d?(g>v||v==g&&i.r<r.r?Si(r,i=u):Si(r=s,i),a--):(Ci(r,o),i=o,n(o))}var m=(c+f)/2,y=(h+p)/2,$=0;for(a=0;l>a;a++)o=e[a],o.x-=m,o.y-=y,$=Math.max($,o.r+Math.sqrt(o.x*o.x+o.y*o.y));t.r=$,e.forEach(Ai)}}function ki(t){t._pack_next=t._pack_prev=t}function Ai(t){delete t._pack_next,delete t._pack_prev}function Ei(t,n,e,r){var i=t.children;if(t.x=n+=r*t.x,t.y=e+=r*t.y,t.r*=r,i)for(var o=-1,a=i.length;++o<a;)Ei(i[o],n,e,r)}function Pi(t,n,e){var r=t.r+e.r,i=n.x-t.x,o=n.y-t.y;if(r&&(i||o)){var a=n.r+e.r,u=i*i+o*o;a*=a,r*=r;var s=.5+(r-a)/(2*u),l=Math.sqrt(Math.max(0,2*a*(r+u)-(r-=u)*r-a*a))/(2*u);e.x=t.x+s*i+l*o,e.y=t.y+s*o-l*i}else e.x=t.x+r,e.y=t.y}function Oi(t,n){return t.parent==n.parent?1:2}function Ti(t){var n=t.children;return n.length?n[0]:t.t}function Li(t){var n,e=t.children;return(n=e.length)?e[n-1]:t.t}function ji(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function Ni(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)n=i[o],n.z+=e,n.m+=e,e+=n.s+(r+=n.c)}function Ri(t,n,e){return t.a.parent===n.parent?t.a:e}function Di(t){return 1+sa.max(t,function(t){return t.y})}function Fi(t){return t.reduce(function(t,n){return t+n.x},0)/t.length}function Ii(t){var n=t.children;return n&&n.length?Ii(n[0]):t}function zi(t){var n,e=t.children;return e&&(n=e.length)?zi(e[n-1]):t}function qi(t){return{x:t.x,y:t.y,dx:t.dx,dy:t.dy}}function Vi(t,n){var e=t.x+n[3],r=t.y+n[0],i=t.dx-n[1]-n[3],o=t.dy-n[0]-n[2];return 0>i&&(e+=i/2,i=0),0>o&&(r+=o/2,o=0),{x:e,y:r,dx:i,dy:o}}function Bi(t){var n=t[0],e=t[t.length-1];return e>n?[n,e]:[e,n]}function Wi(t){return t.rangeExtent?t.rangeExtent():Bi(t.range())}function Ui(t,n,e,r){var i=e(t[0],t[1]),o=r(n[0],n[1]);return function(t){return o(i(t))}}function Hi(t,n){var e,r=0,i=t.length-1,o=t[r],a=t[i];return o>a&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Yi(t){return t?{floor:function(n){return Math.floor(n/t)*t},ceil:function(n){return Math.ceil(n/t)*t}}:Ss}function Gi(t,n,e,r){var i=[],o=[],a=0,u=Math.min(t.length,n.length)-1;for(t[u]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<=u;)i.push(e(t[a-1],t[a])),o.push(r(n[a-1],n[a]));return function(n){var e=sa.bisect(t,n,1,u)-1;return o[e](i[e](n))}}function Xi(t,n,e,r){function i(){var i=Math.min(t.length,n.length)>2?Gi:Ui,s=r?Xr:Gr;return a=i(t,n,s,e),u=i(n,t,s,$r),o}function o(t){return a(t)}var a,u;return o.invert=function(t){return u(t)},o.domain=function(n){return arguments.length?(t=n.map(Number),i()):t},o.range=function(t){return arguments.length?(n=t,i()):n},o.rangeRound=function(t){return o.range(t).interpolate(Dr)},o.clamp=function(t){return arguments.length?(r=t,i()):r},o.interpolate=function(t){return arguments.length?(e=t,i()):e},o.ticks=function(n){return Qi(t,n)},o.tickFormat=function(n,e){return to(t,n,e)},o.nice=function(n){return Ji(t,n),i()},o.copy=function(){return Xi(t,n,e,r)},i()}function Zi(t,n){return sa.rebind(t,n,"range","rangeRound","interpolate","clamp")}function Ji(t,n){return Hi(t,Yi(Ki(t,n)[2])),Hi(t,Yi(Ki(t,n)[2])),t}function Ki(t,n){null==n&&(n=10);var e=Bi(t),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/n)/Math.LN10)),o=n/r*i;return.15>=o?i*=10:.35>=o?i*=5:.75>=o&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Qi(t,n){return sa.range.apply(sa,Ki(t,n))}function to(t,n,e){var r=Ki(t,n);if(e){var i=hu.exec(e);if(i.shift(),"s"===i[8]){var o=sa.formatPrefix(Math.max(xa(r[0]),xa(r[1])));return i[7]||(i[7]="."+no(o.scale(r[2]))),i[8]="f",e=sa.format(i.join("")),function(t){return e(o.scale(t))+o.symbol}}i[7]||(i[7]="."+eo(i[8],r)),e=i.join("")}else e=",."+no(r[2])+"f";return sa.format(e)}function no(t){return-Math.floor(Math.log(t)/Math.LN10+.01)}function eo(t,n){var e=no(n[2]);return t in _s?Math.abs(e-no(Math.max(xa(n[0]),xa(n[1]))))+ +("e"!==t):e-2*("%"===t)}function ro(t,n,e,r){function i(t){return(e?Math.log(0>t?0:t):-Math.log(t>0?0:-t))/Math.log(n)}function o(t){return e?Math.pow(n,t):-Math.pow(n,-t)}function a(n){return t(i(n))}return a.invert=function(n){return o(t.invert(n))},a.domain=function(n){return arguments.length?(e=n[0]>=0,t.domain((r=n.map(Number)).map(i)),a):r},a.base=function(e){return arguments.length?(n=+e,t.domain(r.map(i)),a):n},a.nice=function(){var n=Hi(r.map(i),e?Math:ks);return t.domain(n),r=n.map(o),a},a.ticks=function(){var t=Bi(r),a=[],u=t[0],s=t[1],l=Math.floor(i(u)),c=Math.ceil(i(s)),f=n%1?2:n;if(isFinite(c-l)){if(e){for(;c>l;l++)for(var h=1;f>h;h++)a.push(o(l)*h);a.push(o(l))}else for(a.push(o(l));l++<c;)for(var h=f-1;h>0;h--)a.push(o(l)*h);for(l=0;a[l]<u;l++);for(c=a.length;a[c-1]>s;c--);a=a.slice(l,c)}return a},a.tickFormat=function(t,e){if(!arguments.length)return Ms;arguments.length<2?e=Ms:"function"!=typeof e&&(e=sa.format(e));var r=Math.max(1,n*t/a.ticks().length);return function(t){var a=t/o(Math.round(i(t)));return n-.5>a*n&&(a*=n),r>=a?e(t):""}},a.copy=function(){return ro(t.copy(),n,e,r)},Zi(a,t)}function io(t,n,e){function r(n){return t(i(n))}var i=oo(n),o=oo(1/n);return r.invert=function(n){return o(t.invert(n))},r.domain=function(n){return arguments.length?(t.domain((e=n.map(Number)).map(i)),r):e},r.ticks=function(t){return Qi(e,t)},r.tickFormat=function(t,n){return to(e,t,n)},r.nice=function(t){return r.domain(Ji(e,t))},r.exponent=function(a){return arguments.length?(i=oo(n=a),o=oo(1/n),t.domain(e.map(i)),r):n},r.copy=function(){return io(t.copy(),n,e)},Zi(r,t)}function oo(t){return function(n){return 0>n?-Math.pow(-n,t):Math.pow(n,t)}}function ao(t,n){function e(e){return o[((i.get(e)||("range"===n.t?i.set(e,t.push(e)):NaN))-1)%o.length]}function r(n,e){return sa.range(t.length).map(function(t){return n+e*t})}var i,o,a;return e.domain=function(r){if(!arguments.length)return t;t=[],i=new l;for(var o,a=-1,u=r.length;++a<u;)i.has(o=r[a])||i.set(o,t.push(o));return e[n.t].apply(e,n.a)},e.range=function(t){return arguments.length?(o=t,a=0,n={t:"range",a:arguments},e):o},e.rangePoints=function(i,u){arguments.length<2&&(u=0);var s=i[0],l=i[1],c=t.length<2?(s=(s+l)/2,0):(l-s)/(t.length-1+u);return o=r(s+c*u/2,c),a=0,n={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(i,u){arguments.length<2&&(u=0);var s=i[0],l=i[1],c=t.length<2?(s=l=Math.round((s+l)/2),0):(l-s)/(t.length-1+u)|0;return o=r(s+Math.round(c*u/2+(l-s-(t.length-1+u)*c)/2),c),a=0,n={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(i,u,s){arguments.length<2&&(u=0),arguments.length<3&&(s=u);var l=i[1]<i[0],c=i[l-0],f=i[1-l],h=(f-c)/(t.length-u+2*s);return o=r(c+h*s,h),l&&o.reverse(),a=h*(1-u),n={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,u,s){arguments.length<2&&(u=0),arguments.length<3&&(s=u);var l=i[1]<i[0],c=i[l-0],f=i[1-l],h=Math.floor((f-c)/(t.length-u+2*s));return o=r(c+Math.round((f-c-(t.length-u)*h)/2),h),l&&o.reverse(),a=Math.round(h*(1-u)),n={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return a},e.rangeExtent=function(){return Bi(n.a[0])},e.copy=function(){return ao(t,n)},e.domain(t)}function uo(t,n){function o(){var e=0,r=n.length;for(u=[];++e<r;)u[e-1]=sa.quantile(t,e/r);return a}function a(t){return isNaN(t=+t)?void 0:n[sa.bisect(u,t)]}var u;return a.domain=function(n){return arguments.length?(t=n.map(r).filter(i).sort(e),o()):t},a.range=function(t){return arguments.length?(n=t,o()):n},a.quantiles=function(){return u},a.invertExtent=function(e){return e=n.indexOf(e),0>e?[NaN,NaN]:[e>0?u[e-1]:t[0],e<u.length?u[e]:t[t.length-1]]},a.copy=function(){return uo(t,n)},o()}function so(t,n,e){function r(n){return e[Math.max(0,Math.min(a,Math.floor(o*(n-t))))]}function i(){return o=e.length/(n-t),a=e.length-1,r}var o,a;return r.domain=function(e){return arguments.length?(t=+e[0],n=+e[e.length-1],i()):[t,n]},r.range=function(t){return arguments.length?(e=t,i()):e},r.invertExtent=function(n){return n=e.indexOf(n),n=0>n?NaN:n/o+t,[n,n+1/o]},r.copy=function(){return so(t,n,e)},i()}function lo(t,n){function e(e){return e>=e?n[sa.bisect(t,e)]:void 0}return e.domain=function(n){return arguments.length?(t=n,e):t},e.range=function(t){return arguments.length?(n=t,e):n},e.invertExtent=function(e){return e=n.indexOf(e),[t[e-1],t[e]]},e.copy=function(){return lo(t,n)},e}function co(t){function n(t){return+t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=e.map(n),n):t},n.ticks=function(n){return Qi(t,n)},n.tickFormat=function(n,e){return to(t,n,e)},n.copy=function(){return co(t)},n}function fo(){return 0}function ho(t){return t.innerRadius}function po(t){return t.outerRadius}function vo(t){return t.startAngle}function go(t){return t.endAngle}function mo(t){return t&&t.padAngle}function yo(t,n,e,r){return(t-e)*n-(n-r)*t>0?0:1}function $o(t,n,e,r,i){var o=t[0]-n[0],a=t[1]-n[1],u=(i?r:-r)/Math.sqrt(o*o+a*a),s=u*a,l=-u*o,c=t[0]+s,f=t[1]+l,h=n[0]+s,p=n[1]+l,d=(c+h)/2,v=(f+p)/2,g=h-c,m=p-f,y=g*g+m*m,$=e-r,x=c*p-h*f,b=(0>m?-1:1)*Math.sqrt(Math.max(0,$*$*y-x*x)),w=(x*m-g*b)/y,C=(-x*g-m*b)/y,S=(x*m+g*b)/y,_=(-x*g+m*b)/y,M=w-d,k=C-v,A=S-d,E=_-v;return M*M+k*k>A*A+E*E&&(w=S,C=_),[[w-s,C-l],[w*e/$,C*e/$]]}function xo(t){function n(n){function a(){l.push("M",o(t(c),u))}for(var s,l=[],c=[],f=-1,h=n.length,p=Mt(e),d=Mt(r);++f<h;)i.call(this,s=n[f],f)?c.push([+p.call(this,s,f),+d.call(this,s,f)]):c.length&&(a(),c=[]);return c.length&&a(),l.length?l.join(""):null}var e=Ee,r=Pe,i=Pn,o=bo,a=o.key,u=.7;return n.x=function(t){return arguments.length?(e=t,n):e},n.y=function(t){return arguments.length?(r=t,n):r},n.defined=function(t){return arguments.length?(i=t,n):i},n.interpolate=function(t){return arguments.length?(a="function"==typeof t?o=t:(o=Ls.get(t)||bo).key,n):a},n.tension=function(t){return arguments.length?(u=t,n):u},n}function bo(t){return t.length>1?t.join("L"):t+"Z"}function wo(t){return t.join("L")+"Z"}function Co(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];++n<e;)i.push("H",(r[0]+(r=t[n])[0])/2,"V",r[1]);return e>1&&i.push("H",r[0]),i.join("")}function So(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];++n<e;)i.push("V",(r=t[n])[1],"H",r[0]);return i.join("")}function _o(t){for(var n=0,e=t.length,r=t[0],i=[r[0],",",r[1]];++n<e;)i.push("H",(r=t[n])[0],"V",r[1]);return i.join("")}function Mo(t,n){return t.length<4?bo(t):t[1]+Eo(t.slice(1,-1),Po(t,n))}function ko(t,n){return t.length<3?wo(t):t[0]+Eo((t.push(t[0]),t),Po([t[t.length-2]].concat(t,[t[1]]),n))}function Ao(t,n){return t.length<3?bo(t):t[0]+Eo(t,Po(t,n))}function Eo(t,n){if(n.length<1||t.length!=n.length&&t.length!=n.length+2)return bo(t);var e=t.length!=n.length,r="",i=t[0],o=t[1],a=n[0],u=a,s=1;if(e&&(r+="Q"+(o[0]-2*a[0]/3)+","+(o[1]-2*a[1]/3)+","+o[0]+","+o[1],i=t[1],s=2),n.length>1){u=n[1],o=t[s],s++,r+="C"+(i[0]+a[0])+","+(i[1]+a[1])+","+(o[0]-u[0])+","+(o[1]-u[1])+","+o[0]+","+o[1];for(var l=2;l<n.length;l++,s++)o=t[s],u=n[l],r+="S"+(o[0]-u[0])+","+(o[1]-u[1])+","+o[0]+","+o[1]}if(e){var c=t[s];r+="Q"+(o[0]+2*u[0]/3)+","+(o[1]+2*u[1]/3)+","+c[0]+","+c[1]}return r}function Po(t,n){for(var e,r=[],i=(1-n)/2,o=t[0],a=t[1],u=1,s=t.length;++u<s;)e=o,o=a,a=t[u],r.push([i*(a[0]-e[0]),i*(a[1]-e[1])]);return r}function Oo(t){if(t.length<3)return bo(t);var n=1,e=t.length,r=t[0],i=r[0],o=r[1],a=[i,i,i,(r=t[1])[0]],u=[o,o,o,r[1]],s=[i,",",o,"L",No(Rs,a),",",No(Rs,u)];for(t.push(t[e-1]);++n<=e;)r=t[n],a.shift(),a.push(r[0]),u.shift(),u.push(r[1]),Ro(s,a,u);return t.pop(),s.push("L",r),s.join("")}function To(t){if(t.length<4)return bo(t);for(var n,e=[],r=-1,i=t.length,o=[0],a=[0];++r<3;)n=t[r],o.push(n[0]),a.push(n[1]);for(e.push(No(Rs,o)+","+No(Rs,a)),--r;++r<i;)n=t[r],o.shift(),o.push(n[0]),a.shift(),a.push(n[1]),Ro(e,o,a);return e.join("")}function Lo(t){for(var n,e,r=-1,i=t.length,o=i+4,a=[],u=[];++r<4;)e=t[r%i],a.push(e[0]),u.push(e[1]);for(n=[No(Rs,a),",",No(Rs,u)],--r;++r<o;)e=t[r%i],a.shift(),a.push(e[0]),u.shift(),u.push(e[1]),Ro(n,a,u);return n.join("")}function jo(t,n){var e=t.length-1;if(e)for(var r,i,o=t[0][0],a=t[0][1],u=t[e][0]-o,s=t[e][1]-a,l=-1;++l<=e;)r=t[l],i=l/e,r[0]=n*r[0]+(1-n)*(o+i*u),r[1]=n*r[1]+(1-n)*(a+i*s);return Oo(t)}function No(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function Ro(t,n,e){t.push("C",No(js,n),",",No(js,e),",",No(Ns,n),",",No(Ns,e),",",No(Rs,n),",",No(Rs,e))}function Do(t,n){return(n[1]-t[1])/(n[0]-t[0])}function Fo(t){for(var n=0,e=t.length-1,r=[],i=t[0],o=t[1],a=r[0]=Do(i,o);++n<e;)r[n]=(a+(a=Do(i=o,o=t[n+1])))/2;return r[n]=a,r}function Io(t){for(var n,e,r,i,o=[],a=Fo(t),u=-1,s=t.length-1;++u<s;)n=Do(t[u],t[u+1]),xa(n)<Da?a[u]=a[u+1]=0:(e=a[u]/n,r=a[u+1]/n,i=e*e+r*r,i>9&&(i=3*n/Math.sqrt(i),a[u]=i*e,a[u+1]=i*r));for(u=-1;++u<=s;)i=(t[Math.min(s,u+1)][0]-t[Math.max(0,u-1)][0])/(6*(1+a[u]*a[u])),o.push([i||0,a[u]*i||0]);return o}function zo(t){return t.length<3?bo(t):t[0]+Eo(t,Io(t))}function qo(t){for(var n,e,r,i=-1,o=t.length;++i<o;)n=t[i],e=n[0],r=n[1]-Va,n[0]=e*Math.cos(r),n[1]=e*Math.sin(r);return t}function Vo(t){function n(n){function s(){v.push("M",u(t(m),f),c,l(t(g.reverse()),f),"Z")}for(var h,p,d,v=[],g=[],m=[],y=-1,$=n.length,x=Mt(e),b=Mt(i),w=e===r?function(){return p}:Mt(r),C=i===o?function(){return d}:Mt(o);++y<$;)a.call(this,h=n[y],y)?(g.push([p=+x.call(this,h,y),d=+b.call(this,h,y)]),m.push([+w.call(this,h,y),+C.call(this,h,y)])):g.length&&(s(),g=[],m=[]);return g.length&&s(),v.length?v.join(""):null}var e=Ee,r=Ee,i=0,o=Pe,a=Pn,u=bo,s=u.key,l=u,c="L",f=.7;return n.x=function(t){return arguments.length?(e=r=t,n):r},n.x0=function(t){return arguments.length?(e=t,n):e},n.x1=function(t){return arguments.length?(r=t,n):r},n.y=function(t){return arguments.length?(i=o=t,n):o},n.y0=function(t){return arguments.length?(i=t,n):i},n.y1=function(t){return arguments.length?(o=t,n):o},n.defined=function(t){return arguments.length?(a=t,n):a},n.interpolate=function(t){return arguments.length?(s="function"==typeof t?u=t:(u=Ls.get(t)||bo).key,l=u.reverse||u,c=u.closed?"M":"L",n):s},n.tension=function(t){return arguments.length?(f=t,n):f},n}function Bo(t){return t.radius}function Wo(t){return[t.x,t.y]}function Uo(t){return function(){var n=t.apply(this,arguments),e=n[0],r=n[1]-Va;return[e*Math.cos(r),e*Math.sin(r)]}}function Ho(){return 64}function Yo(){return"circle"}function Go(t){var n=Math.sqrt(t/Ia);return"M0,"+n+"A"+n+","+n+" 0 1,1 0,"+-n+"A"+n+","+n+" 0 1,1 0,"+n+"Z"}function Xo(t){return function(){var n,e,r;(n=this[t])&&(r=n[e=n.active])&&(r.timer.c=null,r.timer.t=NaN,--n.count?delete n[e]:delete this[t],n.active+=.5,r.event&&r.event.interrupt.call(this,this.__data__,r.index))}}function Zo(t,n,e){return _a(t,Bs),t.namespace=n,t.id=e,t}function Jo(t,n,e,r){var i=t.id,o=t.namespace;return B(t,"function"==typeof e?function(t,a,u){t[o][i].tween.set(n,r(e.call(t,t.__data__,a,u)))}:(e=r(e),function(t){t[o][i].tween.set(n,e)}))}function Ko(t){return null==t&&(t=""),function(){this.textContent=t}}function Qo(t){return null==t?"__transition__":"__transition_"+t+"__"}function ta(t,n,e,r,i){function o(t){var n=v.delay;return c.t=n+s,t>=n?a(t-n):void(c.c=a)}function a(e){var i=d.active,o=d[i];o&&(o.timer.c=null,o.timer.t=NaN,--d.count,delete d[i],o.event&&o.event.interrupt.call(t,t.__data__,o.index));for(var a in d)if(r>+a){var l=d[a];l.timer.c=null,l.timer.t=NaN,--d.count,delete d[a]}c.c=u,Ot(function(){return c.c&&u(e||1)&&(c.c=null,c.t=NaN),1},0,s),d.active=r,v.event&&v.event.start.call(t,t.__data__,n),p=[],v.tween.forEach(function(e,r){(r=r.call(t,t.__data__,n))&&p.push(r)}),h=v.ease,f=v.duration}function u(i){for(var o=i/f,a=h(o),u=p.length;u>0;)p[--u].call(t,a);return o>=1?(v.event&&v.event.end.call(t,t.__data__,n),--d.count?delete d[r]:delete t[e],1):void 0}var s,c,f,h,p,d=t[e]||(t[e]={active:0,count:0}),v=d[r];v||(s=i.time,c=Ot(o,0,s),v=d[r]={tween:new l,time:s,timer:c,delay:i.delay,duration:i.duration,ease:i.ease,index:n},i=null,++d.count)}function na(t,n,e){t.attr("transform",function(t){var r=n(t);return"translate("+(isFinite(r)?r:e(t))+",0)"})}function ea(t,n,e){t.attr("transform",function(t){var r=n(t);return"translate(0,"+(isFinite(r)?r:e(t))+")"})}function ra(t){return t.toISOString()}function ia(t,n,e){function r(n){return t(n)}function i(t,e){var r=t[1]-t[0],i=r/e,o=sa.bisect(Ks,i);return o==Ks.length?[n.year,Ki(t.map(function(t){return t/31536e6}),e)[2]]:o?n[i/Ks[o-1]<Ks[o]/i?o-1:o]:[nl,Ki(t,e)[2]]}return r.invert=function(n){return oa(t.invert(n))},r.domain=function(n){return arguments.length?(t.domain(n),r):t.domain().map(oa)},r.nice=function(t,n){function e(e){return!isNaN(e)&&!t.range(e,oa(+e+1),n).length}var o=r.domain(),a=Bi(o),u=null==t?i(a,10):"number"==typeof t&&i(a,t);return u&&(t=u[0],n=u[1]),r.domain(Hi(o,n>1?{floor:function(n){for(;e(n=t.floor(n));)n=oa(n-1);return n},ceil:function(n){for(;e(n=t.ceil(n));)n=oa(+n+1);return n}}:t))},r.ticks=function(t,n){var e=Bi(r.domain()),o=null==t?i(e,10):"number"==typeof t?i(e,t):!t.range&&[{range:t},n];return o&&(t=o[0],n=o[1]),t.range(e[0],oa(+e[1]+1),1>n?1:n)},r.tickFormat=function(){return e},r.copy=function(){return ia(t.copy(),n,e)},Zi(r,t)}function oa(t){return new Date(t)}function aa(t){return JSON.parse(t.responseText)}function ua(t){var n=fa.createRange();return n.selectNode(fa.body),n.createContextualFragment(t.responseText)}var sa={version:"3.5.17"},la=[].slice,ca=function(t){return la.call(t)},fa=this.document;if(fa)try{ca(fa.documentElement.childNodes)[0].nodeType}catch(ha){ca=function(t){for(var n=t.length,e=new Array(n);n--;)e[n]=t[n];return e}}if(Date.now||(Date.now=function(){return+new Date}),fa)try{fa.createElement("DIV").style.setProperty("opacity",0,"")}catch(pa){var da=this.Element.prototype,va=da.setAttribute,ga=da.setAttributeNS,ma=this.CSSStyleDeclaration.prototype,ya=ma.setProperty;da.setAttribute=function(t,n){va.call(this,t,n+"")},da.setAttributeNS=function(t,n,e){ga.call(this,t,n,e+"")},ma.setProperty=function(t,n,e){ya.call(this,t,n+"",e)}}sa.ascending=e,sa.descending=function(t,n){return t>n?-1:n>t?1:n>=t?0:NaN},sa.min=function(t,n){var e,r,i=-1,o=t.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&e>r&&(e=r)}else{for(;++i<o;)if(null!=(r=n.call(t,t[i],i))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n.call(t,t[i],i))&&e>r&&(e=r)}return e},sa.max=function(t,n){var e,r,i=-1,o=t.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=t[i])&&r>=r){e=r;break}for(;++i<o;)null!=(r=t[i])&&r>e&&(e=r)}else{for(;++i<o;)if(null!=(r=n.call(t,t[i],i))&&r>=r){e=r;break}for(;++i<o;)null!=(r=n.call(t,t[i],i))&&r>e&&(e=r)}return e},sa.extent=function(t,n){var e,r,i,o=-1,a=t.length;if(1===arguments.length){for(;++o<a;)if(null!=(r=t[o])&&r>=r){e=i=r;break}for(;++o<a;)null!=(r=t[o])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++o<a;)if(null!=(r=n.call(t,t[o],o))&&r>=r){e=i=r;break}for(;++o<a;)null!=(r=n.call(t,t[o],o))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},sa.sum=function(t,n){var e,r=0,o=t.length,a=-1;if(1===arguments.length)for(;++a<o;)i(e=+t[a])&&(r+=e);else for(;++a<o;)i(e=+n.call(t,t[a],a))&&(r+=e);return r},sa.mean=function(t,n){
 var e,o=0,a=t.length,u=-1,s=a;if(1===arguments.length)for(;++u<a;)i(e=r(t[u]))?o+=e:--s;else for(;++u<a;)i(e=r(n.call(t,t[u],u)))?o+=e:--s;return s?o/s:void 0},sa.quantile=function(t,n){var e=(t.length-1)*n+1,r=Math.floor(e),i=+t[r-1],o=e-r;return o?i+o*(t[r]-i):i},sa.median=function(t,n){var o,a=[],u=t.length,s=-1;if(1===arguments.length)for(;++s<u;)i(o=r(t[s]))&&a.push(o);else for(;++s<u;)i(o=r(n.call(t,t[s],s)))&&a.push(o);return a.length?sa.quantile(a.sort(e),.5):void 0},sa.variance=function(t,n){var e,o,a=t.length,u=0,s=0,l=-1,c=0;if(1===arguments.length)for(;++l<a;)i(e=r(t[l]))&&(o=e-u,u+=o/++c,s+=o*(e-u));else for(;++l<a;)i(e=r(n.call(t,t[l],l)))&&(o=e-u,u+=o/++c,s+=o*(e-u));return c>1?s/(c-1):void 0},sa.deviation=function(){var t=sa.variance.apply(this,arguments);return t?Math.sqrt(t):t};var $a=o(e);sa.bisectLeft=$a.left,sa.bisect=sa.bisectRight=$a.right,sa.bisector=function(t){return o(1===t.length?function(n,r){return e(t(n),r)}:t)},sa.shuffle=function(t,n,e){(o=arguments.length)<3&&(e=t.length,2>o&&(n=0));for(var r,i,o=e-n;o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},sa.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},sa.pairs=function(t){for(var n,e=0,r=t.length-1,i=t[0],o=new Array(0>r?0:r);r>e;)o[e]=[n=i,i=t[++e]];return o},sa.transpose=function(t){if(!(i=t.length))return[];for(var n=-1,e=sa.min(t,a),r=new Array(e);++n<e;)for(var i,o=-1,u=r[n]=new Array(i);++o<i;)u[o]=t[o][n];return r},sa.zip=function(){return sa.transpose(arguments)},sa.keys=function(t){var n=[];for(var e in t)n.push(e);return n},sa.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},sa.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},sa.merge=function(t){for(var n,e,r,i=t.length,o=-1,a=0;++o<i;)a+=t[o].length;for(e=new Array(a);--i>=0;)for(r=t[i],n=r.length;--n>=0;)e[--a]=r[n];return e};var xa=Math.abs;sa.range=function(t,n,e){if(arguments.length<3&&(e=1,arguments.length<2&&(n=t,t=0)),(n-t)/e===1/0)throw new Error("infinite range");var r,i=[],o=u(xa(e)),a=-1;if(t*=o,n*=o,e*=o,0>e)for(;(r=t+e*++a)>n;)i.push(r/o);else for(;(r=t+e*++a)<n;)i.push(r/o);return i},sa.map=function(t,n){var e=new l;if(t instanceof l)t.forEach(function(t,n){e.set(t,n)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(1===arguments.length)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n.call(t,r=t[i],i),r)}else for(var a in t)e.set(a,t[a]);return e};var ba="__proto__",wa="\x00";s(l,{has:h,get:function(t){return this._[c(t)]},set:function(t,n){return this._[c(t)]=n},remove:p,keys:d,values:function(){var t=[];for(var n in this._)t.push(this._[n]);return t},entries:function(){var t=[];for(var n in this._)t.push({key:f(n),value:this._[n]});return t},size:v,empty:g,forEach:function(t){for(var n in this._)t.call(this,f(n),this._[n])}}),sa.nest=function(){function t(n,a,u){if(u>=o.length)return r?r.call(i,a):e?a.sort(e):a;for(var s,c,f,h,p=-1,d=a.length,v=o[u++],g=new l;++p<d;)(h=g.get(s=v(c=a[p])))?h.push(c):g.set(s,[c]);return n?(c=n(),f=function(e,r){c.set(e,t(n,r,u))}):(c={},f=function(e,r){c[e]=t(n,r,u)}),g.forEach(f),c}function n(t,e){if(e>=o.length)return t;var r=[],i=a[e++];return t.forEach(function(t,i){r.push({key:t,values:n(i,e)})}),i?r.sort(function(t,n){return i(t.key,n.key)}):r}var e,r,i={},o=[],a=[];return i.map=function(n,e){return t(e,n,0)},i.entries=function(e){return n(t(sa.map,e,0),0)},i.key=function(t){return o.push(t),i},i.sortKeys=function(t){return a[o.length-1]=t,i},i.sortValues=function(t){return e=t,i},i.rollup=function(t){return r=t,i},i},sa.set=function(t){var n=new m;if(t)for(var e=0,r=t.length;r>e;++e)n.add(t[e]);return n},s(m,{has:h,add:function(t){return this._[c(t+="")]=!0,t},remove:p,values:d,size:v,empty:g,forEach:function(t){for(var n in this._)t.call(this,f(n))}}),sa.behavior={},sa.rebind=function(t,n){for(var e,r=1,i=arguments.length;++r<i;)t[e=arguments[r]]=$(t,n,n[e]);return t};var Ca=["webkit","ms","moz","Moz","o","O"];sa.dispatch=function(){for(var t=new w,n=-1,e=arguments.length;++n<e;)t[arguments[n]]=C(t);return t},w.prototype.on=function(t,n){var e=t.indexOf("."),r="";if(e>=0&&(r=t.slice(e+1),t=t.slice(0,e)),t)return arguments.length<2?this[t].on(r):this[t].on(r,n);if(2===arguments.length){if(null==n)for(t in this)this.hasOwnProperty(t)&&this[t].on(r,null);return this}},sa.event=null,sa.requote=function(t){return t.replace(Sa,"\\$&")};var Sa=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,_a={}.__proto__?function(t,n){t.__proto__=n}:function(t,n){for(var e in n)t[e]=n[e]},Ma=function(t,n){return n.querySelector(t)},ka=function(t,n){return n.querySelectorAll(t)},Aa=function(t,n){var e=t.matches||t[x(t,"matchesSelector")];return(Aa=function(t,n){return e.call(t,n)})(t,n)};"function"==typeof Sizzle&&(Ma=function(t,n){return Sizzle(t,n)[0]||null},ka=Sizzle,Aa=Sizzle.matchesSelector),sa.selection=function(){return sa.select(fa.documentElement)};var Ea=sa.selection.prototype=[];Ea.select=function(t){var n,e,r,i,o=[];t=A(t);for(var a=-1,u=this.length;++a<u;){o.push(n=[]),n.parentNode=(r=this[a]).parentNode;for(var s=-1,l=r.length;++s<l;)(i=r[s])?(n.push(e=t.call(i,i.__data__,s,a)),e&&"__data__"in i&&(e.__data__=i.__data__)):n.push(null)}return k(o)},Ea.selectAll=function(t){var n,e,r=[];t=E(t);for(var i=-1,o=this.length;++i<o;)for(var a=this[i],u=-1,s=a.length;++u<s;)(e=a[u])&&(r.push(n=ca(t.call(e,e.__data__,u,i))),n.parentNode=e);return k(r)};var Pa="http://www.w3.org/1999/xhtml",Oa={svg:"http://www.w3.org/2000/svg",xhtml:Pa,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};sa.ns={prefix:Oa,qualify:function(t){var n=t.indexOf(":"),e=t;return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),Oa.hasOwnProperty(e)?{space:Oa[e],local:t}:t}},Ea.attr=function(t,n){if(arguments.length<2){if("string"==typeof t){var e=this.node();return t=sa.ns.qualify(t),t.local?e.getAttributeNS(t.space,t.local):e.getAttribute(t)}for(n in t)this.each(P(n,t[n]));return this}return this.each(P(t,n))},Ea.classed=function(t,n){if(arguments.length<2){if("string"==typeof t){var e=this.node(),r=(t=L(t)).length,i=-1;if(n=e.classList){for(;++i<r;)if(!n.contains(t[i]))return!1}else for(n=e.getAttribute("class");++i<r;)if(!T(t[i]).test(n))return!1;return!0}for(n in t)this.each(j(n,t[n]));return this}return this.each(j(t,n))},Ea.style=function(t,e,r){var i=arguments.length;if(3>i){if("string"!=typeof t){2>i&&(e="");for(r in t)this.each(R(r,t[r],e));return this}if(2>i){var o=this.node();return n(o).getComputedStyle(o,null).getPropertyValue(t)}r=""}return this.each(R(t,e,r))},Ea.property=function(t,n){if(arguments.length<2){if("string"==typeof t)return this.node()[t];for(n in t)this.each(D(n,t[n]));return this}return this.each(D(t,n))},Ea.text=function(t){return arguments.length?this.each("function"==typeof t?function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}:null==t?function(){this.textContent=""}:function(){this.textContent=t}):this.node().textContent},Ea.html=function(t){return arguments.length?this.each("function"==typeof t?function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}:null==t?function(){this.innerHTML=""}:function(){this.innerHTML=t}):this.node().innerHTML},Ea.append=function(t){return t=F(t),this.select(function(){return this.appendChild(t.apply(this,arguments))})},Ea.insert=function(t,n){return t=F(t),n=A(n),this.select(function(){return this.insertBefore(t.apply(this,arguments),n.apply(this,arguments)||null)})},Ea.remove=function(){return this.each(I)},Ea.data=function(t,n){function e(t,e){var r,i,o,a=t.length,f=e.length,h=Math.min(a,f),p=new Array(f),d=new Array(f),v=new Array(a);if(n){var g,m=new l,y=new Array(a);for(r=-1;++r<a;)(i=t[r])&&(m.has(g=n.call(i,i.__data__,r))?v[r]=i:m.set(g,i),y[r]=g);for(r=-1;++r<f;)(i=m.get(g=n.call(e,o=e[r],r)))?i!==!0&&(p[r]=i,i.__data__=o):d[r]=z(o),m.set(g,!0);for(r=-1;++r<a;)r in y&&m.get(y[r])!==!0&&(v[r]=t[r])}else{for(r=-1;++r<h;)i=t[r],o=e[r],i?(i.__data__=o,p[r]=i):d[r]=z(o);for(;f>r;++r)d[r]=z(e[r]);for(;a>r;++r)v[r]=t[r]}d.update=p,d.parentNode=p.parentNode=v.parentNode=t.parentNode,u.push(d),s.push(p),c.push(v)}var r,i,o=-1,a=this.length;if(!arguments.length){for(t=new Array(a=(r=this[0]).length);++o<a;)(i=r[o])&&(t[o]=i.__data__);return t}var u=W([]),s=k([]),c=k([]);if("function"==typeof t)for(;++o<a;)e(r=this[o],t.call(r,r.parentNode.__data__,o));else for(;++o<a;)e(r=this[o],t);return s.enter=function(){return u},s.exit=function(){return c},s},Ea.datum=function(t){return arguments.length?this.property("__data__",t):this.property("__data__")},Ea.filter=function(t){var n,e,r,i=[];"function"!=typeof t&&(t=q(t));for(var o=0,a=this.length;a>o;o++){i.push(n=[]),n.parentNode=(e=this[o]).parentNode;for(var u=0,s=e.length;s>u;u++)(r=e[u])&&t.call(r,r.__data__,u,o)&&n.push(r)}return k(i)},Ea.order=function(){for(var t=-1,n=this.length;++t<n;)for(var e,r=this[t],i=r.length-1,o=r[i];--i>=0;)(e=r[i])&&(o&&o!==e.nextSibling&&o.parentNode.insertBefore(e,o),o=e);return this},Ea.sort=function(t){t=V.apply(this,arguments);for(var n=-1,e=this.length;++n<e;)this[n].sort(t);return this.order()},Ea.each=function(t){return B(this,function(n,e,r){t.call(n,n.__data__,e,r)})},Ea.call=function(t){var n=ca(arguments);return t.apply(n[0]=this,n),this},Ea.empty=function(){return!this.node()},Ea.node=function(){for(var t=0,n=this.length;n>t;t++)for(var e=this[t],r=0,i=e.length;i>r;r++){var o=e[r];if(o)return o}return null},Ea.size=function(){var t=0;return B(this,function(){++t}),t};var Ta=[];sa.selection.enter=W,sa.selection.enter.prototype=Ta,Ta.append=Ea.append,Ta.empty=Ea.empty,Ta.node=Ea.node,Ta.call=Ea.call,Ta.size=Ea.size,Ta.select=function(t){for(var n,e,r,i,o,a=[],u=-1,s=this.length;++u<s;){r=(i=this[u]).update,a.push(n=[]),n.parentNode=i.parentNode;for(var l=-1,c=i.length;++l<c;)(o=i[l])?(n.push(r[l]=e=t.call(i.parentNode,o.__data__,l,u)),e.__data__=o.__data__):n.push(null)}return k(a)},Ta.insert=function(t,n){return arguments.length<2&&(n=U(this)),Ea.insert.call(this,t,n)},sa.select=function(n){var e;return"string"==typeof n?(e=[Ma(n,fa)],e.parentNode=fa.documentElement):(e=[n],e.parentNode=t(n)),k([e])},sa.selectAll=function(t){var n;return"string"==typeof t?(n=ca(ka(t,fa)),n.parentNode=fa.documentElement):(n=ca(t),n.parentNode=null),k([n])},Ea.on=function(t,n,e){var r=arguments.length;if(3>r){if("string"!=typeof t){2>r&&(n=!1);for(e in t)this.each(H(e,t[e],n));return this}if(2>r)return(r=this.node()["__on"+t])&&r._;e=!1}return this.each(H(t,n,e))};var La=sa.map({mouseenter:"mouseover",mouseleave:"mouseout"});fa&&La.forEach(function(t){"on"+t in fa&&La.remove(t)});var ja,Na=0;sa.mouse=function(t){return Z(t,_())};var Ra=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;sa.touch=function(t,n,e){if(arguments.length<3&&(e=n,n=_().changedTouches),n)for(var r,i=0,o=n.length;o>i;++i)if((r=n[i]).identifier===e)return Z(t,r)},sa.behavior.drag=function(){function t(){this.on("mousedown.drag",o).on("touchstart.drag",a)}function e(t,n,e,o,a){return function(){function u(){var t,e,r=n(h,v);r&&(t=r[0]-$[0],e=r[1]-$[1],d|=t|e,$=r,p({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:t,dy:e}))}function s(){n(h,v)&&(m.on(o+g,null).on(a+g,null),y(d),p({type:"dragend"}))}var l,c=this,f=sa.event.target.correspondingElement||sa.event.target,h=c.parentNode,p=r.of(c,arguments),d=0,v=t(),g=".drag"+(null==v?"":"-"+v),m=sa.select(e(f)).on(o+g,u).on(a+g,s),y=X(f),$=n(h,v);i?(l=i.apply(c,arguments),l=[l.x-$[0],l.y-$[1]]):l=[0,0],p({type:"dragstart"})}}var r=M(t,"drag","dragstart","dragend"),i=null,o=e(b,sa.mouse,n,"mousemove","mouseup"),a=e(J,sa.touch,y,"touchmove","touchend");return t.origin=function(n){return arguments.length?(i=n,t):i},sa.rebind(t,r,"on")},sa.touches=function(t,n){return arguments.length<2&&(n=_().touches),n?ca(n).map(function(n){var e=Z(t,n);return e.identifier=n.identifier,e}):[]};var Da=1e-6,Fa=Da*Da,Ia=Math.PI,za=2*Ia,qa=za-Da,Va=Ia/2,Ba=Ia/180,Wa=180/Ia,Ua=Math.SQRT2,Ha=2,Ya=4;sa.interpolateZoom=function(t,n){var e,r,i=t[0],o=t[1],a=t[2],u=n[0],s=n[1],l=n[2],c=u-i,f=s-o,h=c*c+f*f;if(Fa>h)r=Math.log(l/a)/Ua,e=function(t){return[i+t*c,o+t*f,a*Math.exp(Ua*t*r)]};else{var p=Math.sqrt(h),d=(l*l-a*a+Ya*h)/(2*a*Ha*p),v=(l*l-a*a-Ya*h)/(2*l*Ha*p),g=Math.log(Math.sqrt(d*d+1)-d),m=Math.log(Math.sqrt(v*v+1)-v);r=(m-g)/Ua,e=function(t){var n=t*r,e=rt(g),u=a/(Ha*p)*(e*it(Ua*n+g)-et(g));return[i+u*c,o+u*f,a*e/rt(Ua*n+g)]}}return e.duration=1e3*r,e},sa.behavior.zoom=function(){function t(t){t.on(O,f).on(Xa+".zoom",p).on("dblclick.zoom",d).on(j,h)}function e(t){return[(t[0]-_.x)/_.k,(t[1]-_.y)/_.k]}function r(t){return[t[0]*_.k+_.x,t[1]*_.k+_.y]}function i(t){_.k=Math.max(A[0],Math.min(A[1],t))}function o(t,n){n=r(n),_.x+=t[0]-n[0],_.y+=t[1]-n[1]}function a(n,e,r,a){n.__chart__={x:_.x,y:_.y,k:_.k},i(Math.pow(2,a)),o(g=e,r),n=sa.select(n),E>0&&(n=n.transition().duration(E)),n.call(t.event)}function u(){b&&b.domain(x.range().map(function(t){return(t-_.x)/_.k}).map(x.invert)),C&&C.domain(w.range().map(function(t){return(t-_.y)/_.k}).map(w.invert))}function s(t){P++||t({type:"zoomstart"})}function l(t){u(),t({type:"zoom",scale:_.k,translate:[_.x,_.y]})}function c(t){--P||(t({type:"zoomend"}),g=null)}function f(){function t(){u=1,o(sa.mouse(i),h),l(a)}function r(){f.on(T,null).on(L,null),p(u),c(a)}var i=this,a=N.of(i,arguments),u=0,f=sa.select(n(i)).on(T,t).on(L,r),h=e(sa.mouse(i)),p=X(i);Vs.call(i),s(a)}function h(){function t(){var t=sa.touches(d);return p=_.k,t.forEach(function(t){t.identifier in g&&(g[t.identifier]=e(t))}),t}function n(){var n=sa.event.target;sa.select(n).on(x,r).on(b,u),w.push(n);for(var e=sa.event.changedTouches,i=0,o=e.length;o>i;++i)g[e[i].identifier]=null;var s=t(),l=Date.now();if(1===s.length){if(500>l-$){var c=s[0];a(d,c,g[c.identifier],Math.floor(Math.log(_.k)/Math.LN2)+1),S()}$=l}else if(s.length>1){var c=s[0],f=s[1],h=c[0]-f[0],p=c[1]-f[1];m=h*h+p*p}}function r(){var t,n,e,r,a=sa.touches(d);Vs.call(d);for(var u=0,s=a.length;s>u;++u,r=null)if(e=a[u],r=g[e.identifier]){if(n)break;t=e,n=r}if(r){var c=(c=e[0]-t[0])*c+(c=e[1]-t[1])*c,f=m&&Math.sqrt(c/m);t=[(t[0]+e[0])/2,(t[1]+e[1])/2],n=[(n[0]+r[0])/2,(n[1]+r[1])/2],i(f*p)}$=null,o(t,n),l(v)}function u(){if(sa.event.touches.length){for(var n=sa.event.changedTouches,e=0,r=n.length;r>e;++e)delete g[n[e].identifier];for(var i in g)return void t()}sa.selectAll(w).on(y,null),C.on(O,f).on(j,h),M(),c(v)}var p,d=this,v=N.of(d,arguments),g={},m=0,y=".zoom-"+sa.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,w=[],C=sa.select(d),M=X(d);n(),s(v),C.on(O,null).on(j,n)}function p(){var t=N.of(this,arguments);y?clearTimeout(y):(Vs.call(this),v=e(g=m||sa.mouse(this)),s(t)),y=setTimeout(function(){y=null,c(t)},50),S(),i(Math.pow(2,.002*Ga())*_.k),o(g,v),l(t)}function d(){var t=sa.mouse(this),n=Math.log(_.k)/Math.LN2;a(this,t,e(t),sa.event.shiftKey?Math.ceil(n)-1:Math.floor(n)+1)}var v,g,m,y,$,x,b,w,C,_={x:0,y:0,k:1},k=[960,500],A=Za,E=250,P=0,O="mousedown.zoom",T="mousemove.zoom",L="mouseup.zoom",j="touchstart.zoom",N=M(t,"zoomstart","zoom","zoomend");return Xa||(Xa="onwheel"in fa?(Ga=function(){return-sa.event.deltaY*(sa.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fa?(Ga=function(){return sa.event.wheelDelta},"mousewheel"):(Ga=function(){return-sa.event.detail},"MozMousePixelScroll")),t.event=function(t){t.each(function(){var t=N.of(this,arguments),n=_;zs?sa.select(this).transition().each("start.zoom",function(){_=this.__chart__||{x:0,y:0,k:1},s(t)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],i=g?g[0]:e/2,o=g?g[1]:r/2,a=sa.interpolateZoom([(i-_.x)/_.k,(o-_.y)/_.k,e/_.k],[(i-n.x)/n.k,(o-n.y)/n.k,e/n.k]);return function(n){var r=a(n),u=e/r[2];this.__chart__=_={x:i-r[0]*u,y:o-r[1]*u,k:u},l(t)}}).each("interrupt.zoom",function(){c(t)}).each("end.zoom",function(){c(t)}):(this.__chart__=_,s(t),l(t),c(t))})},t.translate=function(n){return arguments.length?(_={x:+n[0],y:+n[1],k:_.k},u(),t):[_.x,_.y]},t.scale=function(n){return arguments.length?(_={x:_.x,y:_.y,k:null},i(+n),u(),t):_.k},t.scaleExtent=function(n){return arguments.length?(A=null==n?Za:[+n[0],+n[1]],t):A},t.center=function(n){return arguments.length?(m=n&&[+n[0],+n[1]],t):m},t.size=function(n){return arguments.length?(k=n&&[+n[0],+n[1]],t):k},t.duration=function(n){return arguments.length?(E=+n,t):E},t.x=function(n){return arguments.length?(b=n,x=n.copy(),_={x:0,y:0,k:1},t):b},t.y=function(n){return arguments.length?(C=n,w=n.copy(),_={x:0,y:0,k:1},t):C},sa.rebind(t,N,"on")};var Ga,Xa,Za=[0,1/0];sa.color=at,at.prototype.toString=function(){return this.rgb()+""},sa.hsl=ut;var Ja=ut.prototype=new at;Ja.brighter=function(t){return t=Math.pow(.7,arguments.length?t:1),new ut(this.h,this.s,this.l/t)},Ja.darker=function(t){return t=Math.pow(.7,arguments.length?t:1),new ut(this.h,this.s,t*this.l)},Ja.rgb=function(){return st(this.h,this.s,this.l)},sa.hcl=lt;var Ka=lt.prototype=new at;Ka.brighter=function(t){return new lt(this.h,this.c,Math.min(100,this.l+Qa*(arguments.length?t:1)))},Ka.darker=function(t){return new lt(this.h,this.c,Math.max(0,this.l-Qa*(arguments.length?t:1)))},Ka.rgb=function(){return ct(this.h,this.c,this.l).rgb()},sa.lab=ft;var Qa=18,tu=.95047,nu=1,eu=1.08883,ru=ft.prototype=new at;ru.brighter=function(t){return new ft(Math.min(100,this.l+Qa*(arguments.length?t:1)),this.a,this.b)},ru.darker=function(t){return new ft(Math.max(0,this.l-Qa*(arguments.length?t:1)),this.a,this.b)},ru.rgb=function(){return ht(this.l,this.a,this.b)},sa.rgb=mt;var iu=mt.prototype=new at;iu.brighter=function(t){t=Math.pow(.7,arguments.length?t:1);var n=this.r,e=this.g,r=this.b,i=30;return n||e||r?(n&&i>n&&(n=i),e&&i>e&&(e=i),r&&i>r&&(r=i),new mt(Math.min(255,n/t),Math.min(255,e/t),Math.min(255,r/t))):new mt(i,i,i)},iu.darker=function(t){return t=Math.pow(.7,arguments.length?t:1),new mt(t*this.r,t*this.g,t*this.b)},iu.hsl=function(){return wt(this.r,this.g,this.b)},iu.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var ou=sa.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ou.forEach(function(t,n){ou.set(t,yt(n))}),sa.functor=Mt,sa.xhr=kt(y),sa.dsv=function(t,n){function e(t,e,o){arguments.length<3&&(o=e,e=null);var a=At(t,n,null==e?r:i(e),o);return a.row=function(t){return arguments.length?a.response(null==(e=t)?r:i(t)):e},a}function r(t){return e.parse(t.responseText)}function i(t){return function(n){return e.parse(n.responseText,t)}}function o(n){return n.map(a).join(t)}function a(t){return u.test(t)?'"'+t.replace(/\"/g,'""')+'"':t}var u=new RegExp('["'+t+"\n]"),s=t.charCodeAt(0);return e.parse=function(t,n){var r;return e.parseRows(t,function(t,e){if(r)return r(t,e-1);var i=new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}");r=n?function(t,e){return n(i(t),e)}:i})},e.parseRows=function(t,n){function e(){if(c>=l)return a;if(i)return i=!1,o;var n=c;if(34===t.charCodeAt(n)){for(var e=n;e++<l;)if(34===t.charCodeAt(e)){if(34!==t.charCodeAt(e+1))break;++e}c=e+2;var r=t.charCodeAt(e+1);return 13===r?(i=!0,10===t.charCodeAt(e+2)&&++c):10===r&&(i=!0),t.slice(n+1,e).replace(/""/g,'"')}for(;l>c;){var r=t.charCodeAt(c++),u=1;if(10===r)i=!0;else if(13===r)i=!0,10===t.charCodeAt(c)&&(++c,++u);else if(r!==s)continue;return t.slice(n,c-u)}return t.slice(n)}for(var r,i,o={},a={},u=[],l=t.length,c=0,f=0;(r=e())!==a;){for(var h=[];r!==o&&r!==a;)h.push(r),r=e();n&&null==(h=n(h,f++))||u.push(h)}return u},e.format=function(n){if(Array.isArray(n[0]))return e.formatRows(n);var r=new m,i=[];return n.forEach(function(t){for(var n in t)r.has(n)||i.push(r.add(n))}),[i.map(a).join(t)].concat(n.map(function(n){return i.map(function(t){return a(n[t])}).join(t)})).join("\n")},e.formatRows=function(t){return t.map(o).join("\n")},e},sa.csv=sa.dsv(",","text/csv"),sa.tsv=sa.dsv("	","text/tab-separated-values");var au,uu,su,lu,cu=this[x(this,"requestAnimationFrame")]||function(t){setTimeout(t,17)};sa.timer=function(){Ot.apply(this,arguments)},sa.timer.flush=function(){Lt(),jt()},sa.round=function(t,n){return n?Math.round(t*(n=Math.pow(10,n)))/n:Math.round(t)};var fu=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(Rt);sa.formatPrefix=function(t,n){var e=0;return(t=+t)&&(0>t&&(t*=-1),n&&(t=sa.round(t,Nt(t,n))),e=1+Math.floor(1e-12+Math.log(t)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),fu[8+e/3]};var hu=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,pu=sa.map({b:function(t){return t.toString(2)},c:function(t){return String.fromCharCode(t)},o:function(t){return t.toString(8)},x:function(t){return t.toString(16)},X:function(t){return t.toString(16).toUpperCase()},g:function(t,n){return t.toPrecision(n)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},r:function(t,n){return(t=sa.round(t,Nt(t,n))).toFixed(Math.max(0,Math.min(20,Nt(t*(1+1e-15),n))))}}),du=sa.time={},vu=Date;It.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){gu.setUTCDate.apply(this._,arguments)},setDay:function(){gu.setUTCDay.apply(this._,arguments)},setFullYear:function(){gu.setUTCFullYear.apply(this._,arguments)},setHours:function(){gu.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){gu.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){gu.setUTCMinutes.apply(this._,arguments)},setMonth:function(){gu.setUTCMonth.apply(this._,arguments)},setSeconds:function(){gu.setUTCSeconds.apply(this._,arguments)},setTime:function(){gu.setTime.apply(this._,arguments)}};var gu=Date.prototype;du.year=zt(function(t){return t=du.day(t),t.setMonth(0,1),t},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t){return t.getFullYear()}),du.years=du.year.range,du.years.utc=du.year.utc.range,du.day=zt(function(t){var n=new vu(2e3,0);return n.setFullYear(t.getFullYear(),t.getMonth(),t.getDate()),n},function(t,n){t.setDate(t.getDate()+n)},function(t){return t.getDate()-1}),du.days=du.day.range,du.days.utc=du.day.utc.range,du.dayOfYear=function(t){var n=du.year(t);return Math.floor((t-n-6e4*(t.getTimezoneOffset()-n.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(t,n){n=7-n;var e=du[t]=zt(function(t){return(t=du.day(t)).setDate(t.getDate()-(t.getDay()+n)%7),t},function(t,n){t.setDate(t.getDate()+7*Math.floor(n))},function(t){var e=du.year(t).getDay();return Math.floor((du.dayOfYear(t)+(e+n)%7)/7)-(e!==n)});du[t+"s"]=e.range,du[t+"s"].utc=e.utc.range,du[t+"OfYear"]=function(t){var e=du.year(t).getDay();return Math.floor((du.dayOfYear(t)+(e+n)%7)/7)}}),du.week=du.sunday,du.weeks=du.sunday.range,du.weeks.utc=du.sunday.utc.range,du.weekOfYear=du.sundayOfYear;var mu={"-":"",_:" ",0:"0"},yu=/^\s*\d+/,$u=/^%/;sa.locale=function(t){return{numberFormat:Dt(t),timeFormat:Vt(t)}};var xu=sa.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});sa.format=xu.numberFormat,sa.geo={},cn.prototype={s:0,t:0,add:function(t){fn(t,this.t,bu),fn(bu.s,this.s,this),this.s?this.t+=bu.t:this.s=bu.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var bu=new cn;sa.geo.stream=function(t,n){t&&wu.hasOwnProperty(t.type)?wu[t.type](t,n):hn(t,n)};var wu={Feature:function(t,n){hn(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)hn(e[r].geometry,n)}},Cu={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){pn(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)pn(e[r],n,0)},Polygon:function(t,n){dn(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)dn(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)hn(e[r],n)}};sa.geo.area=function(t){return Su=0,sa.geo.stream(t,Mu),Su};var Su,_u=new cn,Mu={sphere:function(){Su+=4*Ia},point:b,lineStart:b,lineEnd:b,polygonStart:function(){_u.reset(),Mu.lineStart=vn},polygonEnd:function(){var t=2*_u;Su+=0>t?4*Ia+t:t,Mu.lineStart=Mu.lineEnd=Mu.point=b}};sa.geo.bounds=function(){function t(t,n){$.push(x=[c=t,h=t]),f>n&&(f=n),n>p&&(p=n)}function n(n,e){var r=gn([n*Ba,e*Ba]);if(m){var i=yn(m,r),o=[i[1],-i[0],0],a=yn(o,i);bn(a),a=wn(a);var s=n-d,l=s>0?1:-1,v=a[0]*Wa*l,g=xa(s)>180;if(g^(v>l*d&&l*n>v)){var y=a[1]*Wa;y>p&&(p=y)}else if(v=(v+360)%360-180,g^(v>l*d&&l*n>v)){var y=-a[1]*Wa;f>y&&(f=y)}else f>e&&(f=e),e>p&&(p=e);g?d>n?u(c,n)>u(c,h)&&(h=n):u(n,h)>u(c,h)&&(c=n):h>=c?(c>n&&(c=n),n>h&&(h=n)):n>d?u(c,n)>u(c,h)&&(h=n):u(n,h)>u(c,h)&&(c=n)}else t(n,e);m=r,d=n}function e(){b.point=n}function r(){x[0]=c,x[1]=h,b.point=t,m=null}function i(t,e){if(m){var r=t-d;y+=xa(r)>180?r+(r>0?360:-360):r}else v=t,g=e;Mu.point(t,e),n(t,e)}function o(){Mu.lineStart()}function a(){i(v,g),Mu.lineEnd(),xa(y)>Da&&(c=-(h=180)),x[0]=c,x[1]=h,m=null}function u(t,n){return(n-=t)<0?n+360:n}function s(t,n){return t[0]-n[0]}function l(t,n){return n[0]<=n[1]?n[0]<=t&&t<=n[1]:t<n[0]||n[1]<t}var c,f,h,p,d,v,g,m,y,$,x,b={point:t,lineStart:e,lineEnd:r,polygonStart:function(){b.point=i,b.lineStart=o,b.lineEnd=a,y=0,Mu.polygonStart()},polygonEnd:function(){Mu.polygonEnd(),b.point=t,b.lineStart=e,b.lineEnd=r,0>_u?(c=-(h=180),f=-(p=90)):y>Da?p=90:-Da>y&&(f=-90),x[0]=c,x[1]=h}};return function(t){p=h=-(c=f=1/0),$=[],sa.geo.stream(t,b);var n=$.length;if(n){$.sort(s);for(var e,r=1,i=$[0],o=[i];n>r;++r)e=$[r],l(e[0],i)||l(e[1],i)?(u(i[0],e[1])>u(i[0],i[1])&&(i[1]=e[1]),u(e[0],i[1])>u(i[0],i[1])&&(i[0]=e[0])):o.push(i=e);for(var a,e,d=-(1/0),n=o.length-1,r=0,i=o[n];n>=r;i=e,++r)e=o[r],(a=u(i[1],e[0]))>d&&(d=a,c=e[0],h=i[1])}return $=x=null,c===1/0||f===1/0?[[NaN,NaN],[NaN,NaN]]:[[c,f],[h,p]]}}(),sa.geo.centroid=function(t){ku=Au=Eu=Pu=Ou=Tu=Lu=ju=Nu=Ru=Du=0,sa.geo.stream(t,Fu);var n=Nu,e=Ru,r=Du,i=n*n+e*e+r*r;return Fa>i&&(n=Tu,e=Lu,r=ju,Da>Au&&(n=Eu,e=Pu,r=Ou),i=n*n+e*e+r*r,Fa>i)?[NaN,NaN]:[Math.atan2(e,n)*Wa,nt(r/Math.sqrt(i))*Wa]};var ku,Au,Eu,Pu,Ou,Tu,Lu,ju,Nu,Ru,Du,Fu={sphere:b,point:Sn,lineStart:Mn,lineEnd:kn,polygonStart:function(){Fu.lineStart=An},polygonEnd:function(){Fu.lineStart=Mn}},Iu=jn(Pn,Fn,zn,[-Ia,-Ia/2]),zu=1e9;sa.geo.clipExtent=function(){var t,n,e,r,i,o,a={stream:function(t){return i&&(i.valid=!1),i=o(t),i.valid=!0,i},extent:function(u){return arguments.length?(o=Wn(t=+u[0][0],n=+u[0][1],e=+u[1][0],r=+u[1][1]),i&&(i.valid=!1,i=null),a):[[t,n],[e,r]]}};return a.extent([[0,0],[960,500]])},(sa.geo.conicEqualArea=function(){return Un(Hn)}).raw=Hn,sa.geo.albers=function(){return sa.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},sa.geo.albersUsa=function(){function t(t){var o=t[0],a=t[1];return n=null,e(o,a),n||(r(o,a),n)||i(o,a),n}var n,e,r,i,o=sa.geo.albers(),a=sa.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),u=sa.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),s={point:function(t,e){n=[t,e]}};return t.invert=function(t){var n=o.scale(),e=o.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?a:i>=.166&&.234>i&&r>=-.214&&-.115>r?u:o).invert(t)},t.stream=function(t){var n=o.stream(t),e=a.stream(t),r=u.stream(t);return{point:function(t,i){n.point(t,i),e.point(t,i),r.point(t,i)},sphere:function(){n.sphere(),e.sphere(),r.sphere()},lineStart:function(){n.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){n.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){n.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){n.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},t.precision=function(n){return arguments.length?(o.precision(n),a.precision(n),u.precision(n),t):o.precision()},t.scale=function(n){return arguments.length?(o.scale(n),a.scale(.35*n),u.scale(n),t.translate(o.translate())):o.scale()},t.translate=function(n){if(!arguments.length)return o.translate();var l=o.scale(),c=+n[0],f=+n[1];return e=o.translate(n).clipExtent([[c-.455*l,f-.238*l],[c+.455*l,f+.238*l]]).stream(s).point,r=a.translate([c-.307*l,f+.201*l]).clipExtent([[c-.425*l+Da,f+.12*l+Da],[c-.214*l-Da,f+.234*l-Da]]).stream(s).point,i=u.translate([c-.205*l,f+.212*l]).clipExtent([[c-.214*l+Da,f+.166*l+Da],[c-.115*l-Da,f+.234*l-Da]]).stream(s).point,t},t.scale(1070)};var qu,Vu,Bu,Wu,Uu,Hu,Yu={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Vu=0,Yu.lineStart=Yn;
 },polygonEnd:function(){Yu.lineStart=Yu.lineEnd=Yu.point=b,qu+=xa(Vu/2)}},Gu={point:Gn,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Xu={point:Jn,lineStart:Kn,lineEnd:Qn,polygonStart:function(){Xu.lineStart=te},polygonEnd:function(){Xu.point=Jn,Xu.lineStart=Kn,Xu.lineEnd=Qn}};sa.geo.path=function(){function t(t){return t&&("function"==typeof u&&o.pointRadius(+u.apply(this,arguments)),a&&a.valid||(a=i(o)),sa.geo.stream(t,a)),o.result()}function n(){return a=null,t}var e,r,i,o,a,u=4.5;return t.area=function(t){return qu=0,sa.geo.stream(t,i(Yu)),qu},t.centroid=function(t){return Eu=Pu=Ou=Tu=Lu=ju=Nu=Ru=Du=0,sa.geo.stream(t,i(Xu)),Du?[Nu/Du,Ru/Du]:ju?[Tu/ju,Lu/ju]:Ou?[Eu/Ou,Pu/Ou]:[NaN,NaN]},t.bounds=function(t){return Uu=Hu=-(Bu=Wu=1/0),sa.geo.stream(t,i(Gu)),[[Bu,Wu],[Uu,Hu]]},t.projection=function(t){return arguments.length?(i=(e=t)?t.stream||re(t):y,n()):e},t.context=function(t){return arguments.length?(o=null==(r=t)?new Xn:new ne(t),"function"!=typeof u&&o.pointRadius(u),n()):r},t.pointRadius=function(n){return arguments.length?(u="function"==typeof n?n:(o.pointRadius(+n),+n),t):u},t.projection(sa.geo.albersUsa()).context(null)},sa.geo.transform=function(t){return{stream:function(n){var e=new ie(n);for(var r in t)e[r]=t[r];return e}}},ie.prototype={point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},sa.geo.projection=ae,sa.geo.projectionMutator=ue,(sa.geo.equirectangular=function(){return ae(le)}).raw=le.invert=le,sa.geo.rotation=function(t){function n(n){return n=t(n[0]*Ba,n[1]*Ba),n[0]*=Wa,n[1]*=Wa,n}return t=fe(t[0]%360*Ba,t[1]*Ba,t.length>2?t[2]*Ba:0),n.invert=function(n){return n=t.invert(n[0]*Ba,n[1]*Ba),n[0]*=Wa,n[1]*=Wa,n},n},ce.invert=le,sa.geo.circle=function(){function t(){var t="function"==typeof r?r.apply(this,arguments):r,n=fe(-t[0]*Ba,-t[1]*Ba,0).invert,i=[];return e(null,null,1,{point:function(t,e){i.push(t=n(t,e)),t[0]*=Wa,t[1]*=Wa}}),{type:"Polygon",coordinates:[i]}}var n,e,r=[0,0],i=6;return t.origin=function(n){return arguments.length?(r=n,t):r},t.angle=function(r){return arguments.length?(e=ve((n=+r)*Ba,i*Ba),t):n},t.precision=function(r){return arguments.length?(e=ve(n*Ba,(i=+r)*Ba),t):i},t.angle(90)},sa.geo.distance=function(t,n){var e,r=(n[0]-t[0])*Ba,i=t[1]*Ba,o=n[1]*Ba,a=Math.sin(r),u=Math.cos(r),s=Math.sin(i),l=Math.cos(i),c=Math.sin(o),f=Math.cos(o);return Math.atan2(Math.sqrt((e=f*a)*e+(e=l*c-s*f*u)*e),s*c+l*f*u)},sa.geo.graticule=function(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return sa.range(Math.ceil(o/g)*g,i,g).map(h).concat(sa.range(Math.ceil(l/m)*m,s,m).map(p)).concat(sa.range(Math.ceil(r/d)*d,e,d).filter(function(t){return xa(t%g)>Da}).map(c)).concat(sa.range(Math.ceil(u/v)*v,a,v).filter(function(t){return xa(t%m)>Da}).map(f))}var e,r,i,o,a,u,s,l,c,f,h,p,d=10,v=d,g=90,m=360,y=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(s).slice(1),h(i).reverse().slice(1),p(l).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.majorExtent(n).minorExtent(n):t.minorExtent()},t.majorExtent=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],l=+n[0][1],s=+n[1][1],o>i&&(n=o,o=i,i=n),l>s&&(n=l,l=s,s=n),t.precision(y)):[[o,l],[i,s]]},t.minorExtent=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],u=+n[0][1],a=+n[1][1],r>e&&(n=r,r=e,e=n),u>a&&(n=u,u=a,a=n),t.precision(y)):[[r,u],[e,a]]},t.step=function(n){return arguments.length?t.majorStep(n).minorStep(n):t.minorStep()},t.majorStep=function(n){return arguments.length?(g=+n[0],m=+n[1],t):[g,m]},t.minorStep=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(y=+n,c=me(u,a,90),f=ye(r,e,y),h=me(l,s,90),p=ye(o,i,y),t):y},t.majorExtent([[-180,-90+Da],[180,90-Da]]).minorExtent([[-180,-80-Da],[180,80+Da]])},sa.geo.greatArc=function(){function t(){return{type:"LineString",coordinates:[n||r.apply(this,arguments),e||i.apply(this,arguments)]}}var n,e,r=$e,i=xe;return t.distance=function(){return sa.geo.distance(n||r.apply(this,arguments),e||i.apply(this,arguments))},t.source=function(e){return arguments.length?(r=e,n="function"==typeof e?null:e,t):r},t.target=function(n){return arguments.length?(i=n,e="function"==typeof n?null:n,t):i},t.precision=function(){return arguments.length?t:0},t},sa.geo.interpolate=function(t,n){return be(t[0]*Ba,t[1]*Ba,n[0]*Ba,n[1]*Ba)},sa.geo.length=function(t){return Zu=0,sa.geo.stream(t,Ju),Zu};var Zu,Ju={sphere:b,point:b,lineStart:we,lineEnd:b,polygonStart:b,polygonEnd:b},Ku=Ce(function(t){return Math.sqrt(2/(1+t))},function(t){return 2*Math.asin(t/2)});(sa.geo.azimuthalEqualArea=function(){return ae(Ku)}).raw=Ku;var Qu=Ce(function(t){var n=Math.acos(t);return n&&n/Math.sin(n)},y);(sa.geo.azimuthalEquidistant=function(){return ae(Qu)}).raw=Qu,(sa.geo.conicConformal=function(){return Un(Se)}).raw=Se,(sa.geo.conicEquidistant=function(){return Un(_e)}).raw=_e;var ts=Ce(function(t){return 1/t},Math.atan);(sa.geo.gnomonic=function(){return ae(ts)}).raw=ts,Me.invert=function(t,n){return[t,2*Math.atan(Math.exp(n))-Va]},(sa.geo.mercator=function(){return ke(Me)}).raw=Me;var ns=Ce(function(){return 1},Math.asin);(sa.geo.orthographic=function(){return ae(ns)}).raw=ns;var es=Ce(function(t){return 1/(1+t)},function(t){return 2*Math.atan(t)});(sa.geo.stereographic=function(){return ae(es)}).raw=es,Ae.invert=function(t,n){return[-n,2*Math.atan(Math.exp(t))-Va]},(sa.geo.transverseMercator=function(){var t=ke(Ae),n=t.center,e=t.rotate;return t.center=function(t){return t?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return t?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90])}).raw=Ae,sa.geom={},sa.geom.hull=function(t){function n(t){if(t.length<3)return[];var n,i=Mt(e),o=Mt(r),a=t.length,u=[],s=[];for(n=0;a>n;n++)u.push([+i.call(this,t[n],n),+o.call(this,t[n],n),n]);for(u.sort(Te),n=0;a>n;n++)s.push([u[n][0],-u[n][1]]);var l=Oe(u),c=Oe(s),f=c[0]===l[0],h=c[c.length-1]===l[l.length-1],p=[];for(n=l.length-1;n>=0;--n)p.push(t[u[l[n]][2]]);for(n=+f;n<c.length-h;++n)p.push(t[u[c[n]][2]]);return p}var e=Ee,r=Pe;return arguments.length?n(t):(n.x=function(t){return arguments.length?(e=t,n):e},n.y=function(t){return arguments.length?(r=t,n):r},n)},sa.geom.polygon=function(t){return _a(t,rs),t};var rs=sa.geom.polygon.prototype=[];rs.area=function(){for(var t,n=-1,e=this.length,r=this[e-1],i=0;++n<e;)t=r,r=this[n],i+=t[1]*r[0]-t[0]*r[1];return.5*i},rs.centroid=function(t){var n,e,r=-1,i=this.length,o=0,a=0,u=this[i-1];for(arguments.length||(t=-1/(6*this.area()));++r<i;)n=u,u=this[r],e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o*t,a*t]},rs.clip=function(t){for(var n,e,r,i,o,a,u=Ne(t),s=-1,l=this.length-Ne(this),c=this[l-1];++s<l;){for(n=t.slice(),t.length=0,i=this[s],o=n[(r=n.length-u)-1],e=-1;++e<r;)a=n[e],Le(a,c,i)?(Le(o,c,i)||t.push(je(o,a,c,i)),t.push(a)):Le(o,c,i)&&t.push(je(o,a,c,i)),o=a;u&&t.push(t[0]),c=i}return t};var is,os,as,us,ss,ls=[],cs=[];Be.prototype.prepare=function(){for(var t,n=this.edges,e=n.length;e--;)t=n[e].edge,t.b&&t.a||n.splice(e,1);return n.sort(Ue),n.length},nr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},er.prototype={insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=ar(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)r=e.U,e===r.L?(i=r.R,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(ir(this,e),t=e,e=t.U),e.C=!1,r.C=!0,or(this,r))):(i=r.L,i&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(or(this,e),t=e,e=t.U),e.C=!1,r.C=!0,ir(this,r))),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,a=t.R;if(e=o?a?ar(a):o:a,i?i.L===t?i.L=e:i.R=e:this._=e,o&&a?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==a?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=a,a.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r){if(t&&t.C)return void(t.C=!1);do{if(t===this._)break;if(t===i.L){if(n=i.R,n.C&&(n.C=!1,i.C=!0,ir(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,or(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,ir(this,i),t=this._;break}}else if(n=i.L,n.C&&(n.C=!1,i.C=!0,or(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,ir(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,or(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}},sa.geom.voronoi=function(t){function n(t){var n=new Array(t.length),r=u[0][0],i=u[0][1],o=u[1][0],a=u[1][1];return ur(e(t),u).cells.forEach(function(e,u){var s=e.edges,l=e.site,c=n[u]=s.length?s.map(function(t){var n=t.start();return[n.x,n.y]}):l.x>=r&&l.x<=o&&l.y>=i&&l.y<=a?[[r,a],[o,a],[o,i],[r,i]]:[];c.point=t[u]}),n}function e(t){return t.map(function(t,n){return{x:Math.round(o(t,n)/Da)*Da,y:Math.round(a(t,n)/Da)*Da,i:n}})}var r=Ee,i=Pe,o=r,a=i,u=fs;return t?n(t):(n.links=function(t){return ur(e(t)).edges.filter(function(t){return t.l&&t.r}).map(function(n){return{source:t[n.l.i],target:t[n.r.i]}})},n.triangles=function(t){var n=[];return ur(e(t)).cells.forEach(function(e,r){for(var i,o,a=e.site,u=e.edges.sort(Ue),s=-1,l=u.length,c=u[l-1].edge,f=c.l===a?c.r:c.l;++s<l;)i=c,o=f,c=u[s].edge,f=c.l===a?c.r:c.l,r<o.i&&r<f.i&&lr(a,o,f)<0&&n.push([t[r],t[o.i],t[f.i]])}),n},n.x=function(t){return arguments.length?(o=Mt(r=t),n):r},n.y=function(t){return arguments.length?(a=Mt(i=t),n):i},n.clipExtent=function(t){return arguments.length?(u=null==t?fs:t,n):u===fs?null:u},n.size=function(t){return arguments.length?n.clipExtent(t&&[[0,0],t]):u===fs?null:u&&u[1]},n)};var fs=[[-1e6,-1e6],[1e6,1e6]];sa.geom.delaunay=function(t){return sa.geom.voronoi().triangles(t)},sa.geom.quadtree=function(t,n,e,r,i){function o(t){function o(t,n,e,r,i,o,a,u){if(!isNaN(e)&&!isNaN(r))if(t.leaf){var s=t.x,c=t.y;if(null!=s)if(xa(s-e)+xa(c-r)<.01)l(t,n,e,r,i,o,a,u);else{var f=t.point;t.x=t.y=t.point=null,l(t,f,s,c,i,o,a,u),l(t,n,e,r,i,o,a,u)}else t.x=e,t.y=r,t.point=n}else l(t,n,e,r,i,o,a,u)}function l(t,n,e,r,i,a,u,s){var l=.5*(i+u),c=.5*(a+s),f=e>=l,h=r>=c,p=h<<1|f;t.leaf=!1,t=t.nodes[p]||(t.nodes[p]=hr()),f?i=l:u=l,h?a=c:s=c,o(t,n,e,r,i,a,u,s)}var c,f,h,p,d,v,g,m,y,$=Mt(u),x=Mt(s);if(null!=n)v=n,g=e,m=r,y=i;else if(m=y=-(v=g=1/0),f=[],h=[],d=t.length,a)for(p=0;d>p;++p)c=t[p],c.x<v&&(v=c.x),c.y<g&&(g=c.y),c.x>m&&(m=c.x),c.y>y&&(y=c.y),f.push(c.x),h.push(c.y);else for(p=0;d>p;++p){var b=+$(c=t[p],p),w=+x(c,p);v>b&&(v=b),g>w&&(g=w),b>m&&(m=b),w>y&&(y=w),f.push(b),h.push(w)}var C=m-v,S=y-g;C>S?y=g+C:m=v+S;var _=hr();if(_.add=function(t){o(_,t,+$(t,++p),+x(t,p),v,g,m,y)},_.visit=function(t){pr(t,_,v,g,m,y)},_.find=function(t){return dr(_,t[0],t[1],v,g,m,y)},p=-1,null==n){for(;++p<d;)o(_,t[p],f[p],h[p],v,g,m,y);--p}else t.forEach(_.add);return f=h=t=c=null,_}var a,u=Ee,s=Pe;return(a=arguments.length)?(u=cr,s=fr,3===a&&(i=e,r=n,e=n=0),o(t)):(o.x=function(t){return arguments.length?(u=t,o):u},o.y=function(t){return arguments.length?(s=t,o):s},o.extent=function(t){return arguments.length?(null==t?n=e=r=i=null:(n=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),o):null==n?null:[[n,e],[r,i]]},o.size=function(t){return arguments.length?(null==t?n=e=r=i=null:(n=e=0,r=+t[0],i=+t[1]),o):null==n?null:[r-n,i-e]},o)},sa.interpolateRgb=vr,sa.interpolateObject=gr,sa.interpolateNumber=mr,sa.interpolateString=yr;var hs=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ps=new RegExp(hs.source,"g");sa.interpolate=$r,sa.interpolators=[function(t,n){var e=typeof n;return("string"===e?ou.has(n.toLowerCase())||/^(#|rgb\(|hsl\()/i.test(n)?vr:yr:n instanceof at?vr:Array.isArray(n)?xr:"object"===e&&isNaN(n)?gr:mr)(t,n)}],sa.interpolateArray=xr;var ds=function(){return y},vs=sa.map({linear:ds,poly:kr,quad:function(){return Sr},cubic:function(){return _r},sin:function(){return Ar},exp:function(){return Er},circle:function(){return Pr},elastic:Or,back:Tr,bounce:function(){return Lr}}),gs=sa.map({"in":y,out:wr,"in-out":Cr,"out-in":function(t){return Cr(wr(t))}});sa.ease=function(t){var n=t.indexOf("-"),e=n>=0?t.slice(0,n):t,r=n>=0?t.slice(n+1):"in";return e=vs.get(e)||ds,r=gs.get(r)||y,br(r(e.apply(null,la.call(arguments,1))))},sa.interpolateHcl=jr,sa.interpolateHsl=Nr,sa.interpolateLab=Rr,sa.interpolateRound=Dr,sa.transform=function(t){var n=fa.createElementNS(sa.ns.prefix.svg,"g");return(sa.transform=function(t){if(null!=t){n.setAttribute("transform",t);var e=n.transform.baseVal.consolidate()}return new Fr(e?e.matrix:ms)})(t)},Fr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var ms={a:1,b:0,c:0,d:1,e:0,f:0};sa.interpolateTransform=Yr,sa.layout={},sa.layout.bundle=function(){return function(t){for(var n=[],e=-1,r=t.length;++e<r;)n.push(Zr(t[e]));return n}},sa.layout.chord=function(){function t(){var t,l,f,h,p,d={},v=[],g=sa.range(o),m=[];for(e=[],r=[],t=0,h=-1;++h<o;){for(l=0,p=-1;++p<o;)l+=i[h][p];v.push(l),m.push(sa.range(o)),t+=l}for(a&&g.sort(function(t,n){return a(v[t],v[n])}),u&&m.forEach(function(t,n){t.sort(function(t,e){return u(i[n][t],i[n][e])})}),t=(za-c*o)/t,l=0,h=-1;++h<o;){for(f=l,p=-1;++p<o;){var y=g[h],$=m[y][p],x=i[y][$],b=l,w=l+=x*t;d[y+"-"+$]={index:y,subindex:$,startAngle:b,endAngle:w,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:v[y]},l+=c}for(h=-1;++h<o;)for(p=h-1;++p<o;){var C=d[h+"-"+p],S=d[p+"-"+h];(C.value||S.value)&&e.push(C.value<S.value?{source:S,target:C}:{source:C,target:S})}s&&n()}function n(){e.sort(function(t,n){return s((t.source.value+t.target.value)/2,(n.source.value+n.target.value)/2)})}var e,r,i,o,a,u,s,l={},c=0;return l.matrix=function(t){return arguments.length?(o=(i=t)&&i.length,e=r=null,l):i},l.padding=function(t){return arguments.length?(c=t,e=r=null,l):c},l.sortGroups=function(t){return arguments.length?(a=t,e=r=null,l):a},l.sortSubgroups=function(t){return arguments.length?(u=t,e=null,l):u},l.sortChords=function(t){return arguments.length?(s=t,e&&n(),l):s},l.chords=function(){return e||t(),e},l.groups=function(){return r||t(),r},l},sa.layout.force=function(){function t(t){return function(n,e,r,i){if(n.point!==t){var o=n.cx-t.x,a=n.cy-t.y,u=i-e,s=o*o+a*a;if(s>u*u/m){if(v>s){var l=n.charge/s;t.px-=o*l,t.py-=a*l}return!0}if(n.point&&s&&v>s){var l=n.pointCharge/s;t.px-=o*l,t.py-=a*l}}return!n.charge}}function n(t){t.px=sa.event.x,t.py=sa.event.y,s.resume()}var e,r,i,o,a,u,s={},l=sa.dispatch("start","tick","end"),c=[1,1],f=.9,h=ys,p=$s,d=-30,v=xs,g=.1,m=.64,$=[],x=[];return s.tick=function(){if((i*=.99)<.005)return e=null,l.end({type:"end",alpha:i=0}),!0;var n,r,s,h,p,v,m,y,b,w=$.length,C=x.length;for(r=0;C>r;++r)s=x[r],h=s.source,p=s.target,y=p.x-h.x,b=p.y-h.y,(v=y*y+b*b)&&(v=i*a[r]*((v=Math.sqrt(v))-o[r])/v,y*=v,b*=v,p.x-=y*(m=h.weight+p.weight?h.weight/(h.weight+p.weight):.5),p.y-=b*m,h.x+=y*(m=1-m),h.y+=b*m);if((m=i*g)&&(y=c[0]/2,b=c[1]/2,r=-1,m))for(;++r<w;)s=$[r],s.x+=(y-s.x)*m,s.y+=(b-s.y)*m;if(d)for(ri(n=sa.geom.quadtree($),i,u),r=-1;++r<w;)(s=$[r]).fixed||n.visit(t(s));for(r=-1;++r<w;)s=$[r],s.fixed?(s.x=s.px,s.y=s.py):(s.x-=(s.px-(s.px=s.x))*f,s.y-=(s.py-(s.py=s.y))*f);l.tick({type:"tick",alpha:i})},s.nodes=function(t){return arguments.length?($=t,s):$},s.links=function(t){return arguments.length?(x=t,s):x},s.size=function(t){return arguments.length?(c=t,s):c},s.linkDistance=function(t){return arguments.length?(h="function"==typeof t?t:+t,s):h},s.distance=s.linkDistance,s.linkStrength=function(t){return arguments.length?(p="function"==typeof t?t:+t,s):p},s.friction=function(t){return arguments.length?(f=+t,s):f},s.charge=function(t){return arguments.length?(d="function"==typeof t?t:+t,s):d},s.chargeDistance=function(t){return arguments.length?(v=t*t,s):Math.sqrt(v)},s.gravity=function(t){return arguments.length?(g=+t,s):g},s.theta=function(t){return arguments.length?(m=t*t,s):Math.sqrt(m)},s.alpha=function(t){return arguments.length?(t=+t,i?t>0?i=t:(e.c=null,e.t=NaN,e=null,l.end({type:"end",alpha:i=0})):t>0&&(l.start({type:"start",alpha:i=t}),e=Ot(s.tick)),s):i},s.start=function(){function t(t,r){if(!e){for(e=new Array(i),s=0;i>s;++s)e[s]=[];for(s=0;l>s;++s){var o=x[s];e[o.source.index].push(o.target),e[o.target.index].push(o.source)}}for(var a,u=e[n],s=-1,c=u.length;++s<c;)if(!isNaN(a=u[s][t]))return a;return Math.random()*r}var n,e,r,i=$.length,l=x.length,f=c[0],v=c[1];for(n=0;i>n;++n)(r=$[n]).index=n,r.weight=0;for(n=0;l>n;++n)r=x[n],"number"==typeof r.source&&(r.source=$[r.source]),"number"==typeof r.target&&(r.target=$[r.target]),++r.source.weight,++r.target.weight;for(n=0;i>n;++n)r=$[n],isNaN(r.x)&&(r.x=t("x",f)),isNaN(r.y)&&(r.y=t("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(o=[],"function"==typeof h)for(n=0;l>n;++n)o[n]=+h.call(this,x[n],n);else for(n=0;l>n;++n)o[n]=h;if(a=[],"function"==typeof p)for(n=0;l>n;++n)a[n]=+p.call(this,x[n],n);else for(n=0;l>n;++n)a[n]=p;if(u=[],"function"==typeof d)for(n=0;i>n;++n)u[n]=+d.call(this,$[n],n);else for(n=0;i>n;++n)u[n]=d;return s.resume()},s.resume=function(){return s.alpha(.1)},s.stop=function(){return s.alpha(0)},s.drag=function(){return r||(r=sa.behavior.drag().origin(y).on("dragstart.force",Qr).on("drag.force",n).on("dragend.force",ti)),arguments.length?void this.on("mouseover.force",ni).on("mouseout.force",ei).call(r):r},sa.rebind(s,l,"on")};var ys=20,$s=1,xs=1/0;sa.layout.hierarchy=function(){function t(i){var o,a=[i],u=[];for(i.depth=0;null!=(o=a.pop());)if(u.push(o),(l=e.call(t,o,o.depth))&&(s=l.length)){for(var s,l,c;--s>=0;)a.push(c=l[s]),c.parent=o,c.depth=o.depth+1;r&&(o.value=0),o.children=l}else r&&(o.value=+r.call(t,o,o.depth)||0),delete o.children;return ai(i,function(t){var e,i;n&&(e=t.children)&&e.sort(n),r&&(i=t.parent)&&(i.value+=t.value)}),u}var n=li,e=ui,r=si;return t.sort=function(e){return arguments.length?(n=e,t):n},t.children=function(n){return arguments.length?(e=n,t):e},t.value=function(n){return arguments.length?(r=n,t):r},t.revalue=function(n){return r&&(oi(n,function(t){t.children&&(t.value=0)}),ai(n,function(n){var e;n.children||(n.value=+r.call(t,n,n.depth)||0),(e=n.parent)&&(e.value+=n.value)})),n},t},sa.layout.partition=function(){function t(n,e,r,i){var o=n.children;if(n.x=e,n.y=n.depth*i,n.dx=r,n.dy=i,o&&(a=o.length)){var a,u,s,l=-1;for(r=n.value?r/n.value:0;++l<a;)t(u=o[l],e,s=u.value*r,i),e+=s}}function n(t){var e=t.children,r=0;if(e&&(i=e.length))for(var i,o=-1;++o<i;)r=Math.max(r,n(e[o]));return 1+r}function e(e,o){var a=r.call(this,e,o);return t(a[0],0,i[0],i[1]/n(a[0])),a}var r=sa.layout.hierarchy(),i=[1,1];return e.size=function(t){return arguments.length?(i=t,e):i},ii(e,r)},sa.layout.pie=function(){function t(a){var u,s=a.length,l=a.map(function(e,r){return+n.call(t,e,r)}),c=+("function"==typeof r?r.apply(this,arguments):r),f=("function"==typeof i?i.apply(this,arguments):i)-c,h=Math.min(Math.abs(f)/s,+("function"==typeof o?o.apply(this,arguments):o)),p=h*(0>f?-1:1),d=sa.sum(l),v=d?(f-s*p)/d:0,g=sa.range(s),m=[];return null!=e&&g.sort(e===bs?function(t,n){return l[n]-l[t]}:function(t,n){return e(a[t],a[n])}),g.forEach(function(t){m[t]={data:a[t],value:u=l[t],startAngle:c,endAngle:c+=u*v+p,padAngle:h}}),m}var n=Number,e=bs,r=0,i=za,o=0;return t.value=function(e){return arguments.length?(n=e,t):n},t.sort=function(n){return arguments.length?(e=n,t):e},t.startAngle=function(n){return arguments.length?(r=n,t):r},t.endAngle=function(n){return arguments.length?(i=n,t):i},t.padAngle=function(n){return arguments.length?(o=n,t):o},t};var bs={};sa.layout.stack=function(){function t(u,s){if(!(h=u.length))return u;var l=u.map(function(e,r){return n.call(t,e,r)}),c=l.map(function(n){return n.map(function(n,e){return[o.call(t,n,e),a.call(t,n,e)]})}),f=e.call(t,c,s);l=sa.permute(l,f),c=sa.permute(c,f);var h,p,d,v,g=r.call(t,c,s),m=l[0].length;for(d=0;m>d;++d)for(i.call(t,l[0][d],v=g[d],c[0][d][1]),p=1;h>p;++p)i.call(t,l[p][d],v+=c[p-1][d][1],c[p][d][1]);return u}var n=y,e=di,r=vi,i=pi,o=fi,a=hi;return t.values=function(e){return arguments.length?(n=e,t):n},t.order=function(n){return arguments.length?(e="function"==typeof n?n:ws.get(n)||di,t):e},t.offset=function(n){return arguments.length?(r="function"==typeof n?n:Cs.get(n)||vi,t):r},t.x=function(n){return arguments.length?(o=n,t):o},t.y=function(n){return arguments.length?(a=n,t):a},t.out=function(n){return arguments.length?(i=n,t):i},t};var ws=sa.map({"inside-out":function(t){var n,e,r=t.length,i=t.map(gi),o=t.map(mi),a=sa.range(r).sort(function(t,n){return i[t]-i[n]}),u=0,s=0,l=[],c=[];for(n=0;r>n;++n)e=a[n],s>u?(u+=o[e],l.push(e)):(s+=o[e],c.push(e));return c.reverse().concat(l)},reverse:function(t){return sa.range(t.length).reverse()},"default":di}),Cs=sa.map({silhouette:function(t){var n,e,r,i=t.length,o=t[0].length,a=[],u=0,s=[];for(e=0;o>e;++e){for(n=0,r=0;i>n;n++)r+=t[n][e][1];r>u&&(u=r),a.push(r)}for(e=0;o>e;++e)s[e]=(u-a[e])/2;return s},wiggle:function(t){var n,e,r,i,o,a,u,s,l,c=t.length,f=t[0],h=f.length,p=[];for(p[0]=s=l=0,e=1;h>e;++e){for(n=0,i=0;c>n;++n)i+=t[n][e][1];for(n=0,o=0,u=f[e][0]-f[e-1][0];c>n;++n){for(r=0,a=(t[n][e][1]-t[n][e-1][1])/(2*u);n>r;++r)a+=(t[r][e][1]-t[r][e-1][1])/u;o+=a*t[n][e][1]}p[e]=s-=i?o/i*u:0,l>s&&(l=s)}for(e=0;h>e;++e)p[e]-=l;return p},expand:function(t){var n,e,r,i=t.length,o=t[0].length,a=1/i,u=[];for(e=0;o>e;++e){for(n=0,r=0;i>n;n++)r+=t[n][e][1];if(r)for(n=0;i>n;n++)t[n][e][1]/=r;else for(n=0;i>n;n++)t[n][e][1]=a}for(e=0;o>e;++e)u[e]=0;return u},zero:vi});sa.layout.histogram=function(){function t(t,o){for(var a,u,s=[],l=t.map(e,this),c=r.call(this,l,o),f=i.call(this,c,l,o),o=-1,h=l.length,p=f.length-1,d=n?1:1/h;++o<p;)a=s[o]=[],a.dx=f[o+1]-(a.x=f[o]),a.y=0;if(p>0)for(o=-1;++o<h;)u=l[o],u>=c[0]&&u<=c[1]&&(a=s[sa.bisect(f,u,1,p)-1],a.y+=d,a.push(t[o]));return s}var n=!0,e=Number,r=bi,i=$i;return t.value=function(n){return arguments.length?(e=n,t):e},t.range=function(n){return arguments.length?(r=Mt(n),t):r},t.bins=function(n){return arguments.length?(i="number"==typeof n?function(t){return xi(t,n)}:Mt(n),t):i},t.frequency=function(e){return arguments.length?(n=!!e,t):n},t},sa.layout.pack=function(){function t(t,o){var a=e.call(this,t,o),u=a[0],s=i[0],l=i[1],c=null==n?Math.sqrt:"function"==typeof n?n:function(){return n};if(u.x=u.y=0,ai(u,function(t){t.r=+c(t.value)}),ai(u,Mi),r){var f=r*(n?1:Math.max(2*u.r/s,2*u.r/l))/2;ai(u,function(t){t.r+=f}),ai(u,Mi),ai(u,function(t){t.r-=f})}return Ei(u,s/2,l/2,n?1:1/Math.max(2*u.r/s,2*u.r/l)),a}var n,e=sa.layout.hierarchy().sort(wi),r=0,i=[1,1];return t.size=function(n){return arguments.length?(i=n,t):i},t.radius=function(e){return arguments.length?(n=null==e||"function"==typeof e?e:+e,t):n},t.padding=function(n){return arguments.length?(r=+n,t):r},ii(t,e)},sa.layout.tree=function(){function t(t,i){var c=a.call(this,t,i),f=c[0],h=n(f);if(ai(h,e),h.parent.m=-h.z,oi(h,r),l)oi(f,o);else{var p=f,d=f,v=f;oi(f,function(t){t.x<p.x&&(p=t),t.x>d.x&&(d=t),t.depth>v.depth&&(v=t)});var g=u(p,d)/2-p.x,m=s[0]/(d.x+u(d,p)/2+g),y=s[1]/(v.depth||1);oi(f,function(t){t.x=(t.x+g)*m,t.y=t.depth*y})}return c}function n(t){for(var n,e={A:null,children:[t]},r=[e];null!=(n=r.pop());)for(var i,o=n.children,a=0,u=o.length;u>a;++a)r.push((o[a]=i={_:o[a],parent:n,children:(i=o[a].children)&&i.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:a}).a=i);return e.children[0]}function e(t){var n=t.children,e=t.parent.children,r=t.i?e[t.i-1]:null;if(n.length){Ni(t);var o=(n[0].z+n[n.length-1].z)/2;r?(t.z=r.z+u(t._,r._),t.m=t.z-o):t.z=o}else r&&(t.z=r.z+u(t._,r._));t.parent.A=i(t,r,t.parent.A||e[0])}function r(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function i(t,n,e){if(n){for(var r,i=t,o=t,a=n,s=i.parent.children[0],l=i.m,c=o.m,f=a.m,h=s.m;a=Li(a),i=Ti(i),a&&i;)s=Ti(s),o=Li(o),o.a=t,r=a.z+f-i.z-l+u(a._,i._),r>0&&(ji(Ri(a,t,e),t,r),l+=r,c+=r),f+=a.m,l+=i.m,h+=s.m,c+=o.m;a&&!Li(o)&&(o.t=a,o.m+=f-c),i&&!Ti(s)&&(s.t=i,s.m+=l-h,e=t)}return e}function o(t){t.x*=s[0],t.y=t.depth*s[1]}var a=sa.layout.hierarchy().sort(null).value(null),u=Oi,s=[1,1],l=null;return t.separation=function(n){return arguments.length?(u=n,t):u},t.size=function(n){return arguments.length?(l=null==(s=n)?o:null,t):l?null:s},t.nodeSize=function(n){return arguments.length?(l=null==(s=n)?null:o,t):l?s:null},ii(t,a)},sa.layout.cluster=function(){function t(t,o){var a,u=n.call(this,t,o),s=u[0],l=0;ai(s,function(t){var n=t.children;n&&n.length?(t.x=Fi(n),t.y=Di(n)):(t.x=a?l+=e(t,a):0,t.y=0,a=t)});var c=Ii(s),f=zi(s),h=c.x-e(c,f)/2,p=f.x+e(f,c)/2;return ai(s,i?function(t){t.x=(t.x-s.x)*r[0],t.y=(s.y-t.y)*r[1]}:function(t){t.x=(t.x-h)/(p-h)*r[0],t.y=(1-(s.y?t.y/s.y:1))*r[1]}),u}var n=sa.layout.hierarchy().sort(null).value(null),e=Oi,r=[1,1],i=!1;return t.separation=function(n){return arguments.length?(e=n,t):e},t.size=function(n){return arguments.length?(i=null==(r=n),t):i?null:r},t.nodeSize=function(n){return arguments.length?(i=null!=(r=n),t):i?r:null},ii(t,n)},sa.layout.treemap=function(){function t(t,n){for(var e,r,i=-1,o=t.length;++i<o;)r=(e=t[i]).value*(0>n?0:n),e.area=isNaN(r)||0>=r?0:r}function n(e){var o=e.children;if(o&&o.length){var a,u,s,l=f(e),c=[],h=o.slice(),d=1/0,v="slice"===p?l.dx:"dice"===p?l.dy:"slice-dice"===p?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(t(h,l.dx*l.dy/e.value),c.area=0;(s=h.length)>0;)c.push(a=h[s-1]),c.area+=a.area,"squarify"!==p||(u=r(c,v))<=d?(h.pop(),d=u):(c.area-=c.pop().area,i(c,v,l,!1),v=Math.min(l.dx,l.dy),c.length=c.area=0,d=1/0);c.length&&(i(c,v,l,!0),c.length=c.area=0),o.forEach(n)}}function e(n){var r=n.children;if(r&&r.length){var o,a=f(n),u=r.slice(),s=[];for(t(u,a.dx*a.dy/n.value),s.area=0;o=u.pop();)s.push(o),s.area+=o.area,null!=o.z&&(i(s,o.z?a.dx:a.dy,a,!u.length),s.length=s.area=0);r.forEach(e)}}function r(t,n){for(var e,r=t.area,i=0,o=1/0,a=-1,u=t.length;++a<u;)(e=t[a].area)&&(o>e&&(o=e),e>i&&(i=e));return r*=r,n*=n,r?Math.max(n*i*d/r,r/(n*o*d)):1/0}function i(t,n,e,r){var i,o=-1,a=t.length,u=e.x,l=e.y,c=n?s(t.area/n):0;if(n==e.dx){for((r||c>e.dy)&&(c=e.dy);++o<a;)i=t[o],i.x=u,i.y=l,i.dy=c,u+=i.dx=Math.min(e.x+e.dx-u,c?s(i.area/c):0);i.z=!0,i.dx+=e.x+e.dx-u,e.y+=c,e.dy-=c}else{for((r||c>e.dx)&&(c=e.dx);++o<a;)i=t[o],i.x=u,i.y=l,i.dx=c,l+=i.dy=Math.min(e.y+e.dy-l,c?s(i.area/c):0);i.z=!1,i.dy+=e.y+e.dy-l,e.x+=c,e.dx-=c}}function o(r){var i=a||u(r),o=i[0];return o.x=o.y=0,o.value?(o.dx=l[0],o.dy=l[1]):o.dx=o.dy=0,a&&u.revalue(o),t([o],o.dx*o.dy/o.value),(a?e:n)(o),h&&(a=i),i}var a,u=sa.layout.hierarchy(),s=Math.round,l=[1,1],c=null,f=qi,h=!1,p="squarify",d=.5*(1+Math.sqrt(5));return o.size=function(t){return arguments.length?(l=t,o):l},o.padding=function(t){function n(n){var e=t.call(o,n,n.depth);return null==e?qi(n):Vi(n,"number"==typeof e?[e,e,e,e]:e)}function e(n){return Vi(n,t)}if(!arguments.length)return c;var r;return f=null==(c=t)?qi:"function"==(r=typeof t)?n:"number"===r?(t=[t,t,t,t],e):e,o},o.round=function(t){return arguments.length?(s=t?Math.round:Number,o):s!=Number},o.sticky=function(t){return arguments.length?(h=t,a=null,o):h},o.ratio=function(t){return arguments.length?(d=t,o):d},o.mode=function(t){return arguments.length?(p=t+"",o):p},ii(o,u)},sa.random={normal:function(t,n){var e=arguments.length;return 2>e&&(n=1),1>e&&(t=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return t+n*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var t=sa.random.normal.apply(sa,arguments);return function(){return Math.exp(t())}},bates:function(t){var n=sa.random.irwinHall(t);return function(){return n()/t}},irwinHall:function(t){return function(){for(var n=0,e=0;t>e;e++)n+=Math.random();return n}}},sa.scale={};var Ss={floor:y,ceil:y};sa.scale.linear=function(){return Xi([0,1],[0,1],$r,!1)};var _s={s:1,g:1,p:1,r:1,e:1};sa.scale.log=function(){return ro(sa.scale.linear().domain([0,1]),10,!0,[1,10])};var Ms=sa.format(".0e"),ks={floor:function(t){return-Math.ceil(-t)},ceil:function(t){return-Math.floor(-t)}};sa.scale.pow=function(){return io(sa.scale.linear(),1,[0,1])},sa.scale.sqrt=function(){return sa.scale.pow().exponent(.5)},sa.scale.ordinal=function(){return ao([],{t:"range",a:[[]]})},sa.scale.category10=function(){return sa.scale.ordinal().range(As)},sa.scale.category20=function(){return sa.scale.ordinal().range(Es)},sa.scale.category20b=function(){return sa.scale.ordinal().range(Ps)},sa.scale.category20c=function(){return sa.scale.ordinal().range(Os)};var As=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map($t),Es=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map($t),Ps=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map($t),Os=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map($t);sa.scale.quantile=function(){return uo([],[])},sa.scale.quantize=function(){return so(0,1,[0,1])},sa.scale.threshold=function(){return lo([.5],[0,1])},sa.scale.identity=function(){return co([0,1])},sa.svg={},sa.svg.arc=function(){function t(){var t=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),c=a.apply(this,arguments)-Va,f=u.apply(this,arguments)-Va,h=Math.abs(f-c),p=c>f?0:1;if(t>l&&(d=l,l=t,t=d),h>=qa)return n(l,p)+(t?n(t,1-p):"")+"Z";var d,v,g,m,y,$,x,b,w,C,S,_,M=0,k=0,A=[];if((m=(+s.apply(this,arguments)||0)/2)&&(g=o===Ts?Math.sqrt(t*t+l*l):+o.apply(this,arguments),p||(k*=-1),l&&(k=nt(g/l*Math.sin(m))),t&&(M=nt(g/t*Math.sin(m)))),l){y=l*Math.cos(c+k),$=l*Math.sin(c+k),x=l*Math.cos(f-k),b=l*Math.sin(f-k);var E=Math.abs(f-c-2*k)<=Ia?0:1;if(k&&yo(y,$,x,b)===p^E){var P=(c+f)/2;y=l*Math.cos(P),$=l*Math.sin(P),x=b=null}}else y=$=0;if(t){w=t*Math.cos(f-M),C=t*Math.sin(f-M),S=t*Math.cos(c+M),_=t*Math.sin(c+M);var O=Math.abs(c-f+2*M)<=Ia?0:1;if(M&&yo(w,C,S,_)===1-p^O){var T=(c+f)/2;w=t*Math.cos(T),C=t*Math.sin(T),S=_=null}}else w=C=0;if(h>Da&&(d=Math.min(Math.abs(l-t)/2,+i.apply(this,arguments)))>.001){v=l>t^p?0:1;var L=d,j=d;if(Ia>h){var N=null==S?[w,C]:null==x?[y,$]:je([y,$],[S,_],[x,b],[w,C]),R=y-N[0],D=$-N[1],F=x-N[0],I=b-N[1],z=1/Math.sin(Math.acos((R*F+D*I)/(Math.sqrt(R*R+D*D)*Math.sqrt(F*F+I*I)))/2),q=Math.sqrt(N[0]*N[0]+N[1]*N[1]);j=Math.min(d,(t-q)/(z-1)),L=Math.min(d,(l-q)/(z+1))}if(null!=x){var V=$o(null==S?[w,C]:[S,_],[y,$],l,L,p),B=$o([x,b],[w,C],l,L,p);d===L?A.push("M",V[0],"A",L,",",L," 0 0,",v," ",V[1],"A",l,",",l," 0 ",1-p^yo(V[1][0],V[1][1],B[1][0],B[1][1]),",",p," ",B[1],"A",L,",",L," 0 0,",v," ",B[0]):A.push("M",V[0],"A",L,",",L," 0 1,",v," ",B[0])}else A.push("M",y,",",$);if(null!=S){var W=$o([y,$],[S,_],t,-j,p),U=$o([w,C],null==x?[y,$]:[x,b],t,-j,p);d===j?A.push("L",U[0],"A",j,",",j," 0 0,",v," ",U[1],"A",t,",",t," 0 ",p^yo(U[1][0],U[1][1],W[1][0],W[1][1]),",",1-p," ",W[1],"A",j,",",j," 0 0,",v," ",W[0]):A.push("L",U[0],"A",j,",",j," 0 0,",v," ",W[0])}else A.push("L",w,",",C)}else A.push("M",y,",",$),null!=x&&A.push("A",l,",",l," 0 ",E,",",p," ",x,",",b),A.push("L",w,",",C),null!=S&&A.push("A",t,",",t," 0 ",O,",",1-p," ",S,",",_);return A.push("Z"),A.join("")}function n(t,n){return"M0,"+t+"A"+t+","+t+" 0 1,"+n+" 0,"+-t+"A"+t+","+t+" 0 1,"+n+" 0,"+t}var e=ho,r=po,i=fo,o=Ts,a=vo,u=go,s=mo;return t.innerRadius=function(n){return arguments.length?(e=Mt(n),t):e},t.outerRadius=function(n){return arguments.length?(r=Mt(n),t):r},t.cornerRadius=function(n){return arguments.length?(i=Mt(n),t):i},t.padRadius=function(n){return arguments.length?(o=n==Ts?Ts:Mt(n),t):o},t.startAngle=function(n){return arguments.length?(a=Mt(n),t):a;
-},t.endAngle=function(n){return arguments.length?(u=Mt(n),t):u},t.padAngle=function(n){return arguments.length?(s=Mt(n),t):s},t.centroid=function(){var t=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,n=(+a.apply(this,arguments)+ +u.apply(this,arguments))/2-Va;return[Math.cos(n)*t,Math.sin(n)*t]},t};var Ts="auto";sa.svg.line=function(){return xo(y)};var Ls=sa.map({linear:bo,"linear-closed":wo,step:Co,"step-before":So,"step-after":_o,basis:Oo,"basis-open":To,"basis-closed":Lo,bundle:jo,cardinal:Ao,"cardinal-open":Mo,"cardinal-closed":ko,monotone:zo});Ls.forEach(function(t,n){n.key=t,n.closed=/-closed$/.test(t)});var js=[0,2/3,1/3,0],Ns=[0,1/3,2/3,0],Rs=[0,1/6,2/3,1/6];sa.svg.line.radial=function(){var t=xo(qo);return t.radius=t.x,delete t.x,t.angle=t.y,delete t.y,t},So.reverse=_o,_o.reverse=So,sa.svg.area=function(){return Vo(y)},sa.svg.area.radial=function(){var t=Vo(qo);return t.radius=t.x,delete t.x,t.innerRadius=t.x0,delete t.x0,t.outerRadius=t.x1,delete t.x1,t.angle=t.y,delete t.y,t.startAngle=t.y0,delete t.y0,t.endAngle=t.y1,delete t.y1,t},sa.svg.chord=function(){function t(t,u){var s=n(this,o,t,u),l=n(this,a,t,u);return"M"+s.p0+r(s.r,s.p1,s.a1-s.a0)+(e(s,l)?i(s.r,s.p1,s.r,s.p0):i(s.r,s.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+i(l.r,l.p1,s.r,s.p0))+"Z"}function n(t,n,e,r){var i=n.call(t,e,r),o=u.call(t,i,r),a=s.call(t,i,r)-Va,c=l.call(t,i,r)-Va;return{r:o,a0:a,a1:c,p0:[o*Math.cos(a),o*Math.sin(a)],p1:[o*Math.cos(c),o*Math.sin(c)]}}function e(t,n){return t.a0==n.a0&&t.a1==n.a1}function r(t,n,e){return"A"+t+","+t+" 0 "+ +(e>Ia)+",1 "+n}function i(t,n,e,r){return"Q 0,0 "+r}var o=$e,a=xe,u=Bo,s=vo,l=go;return t.radius=function(n){return arguments.length?(u=Mt(n),t):u},t.source=function(n){return arguments.length?(o=Mt(n),t):o},t.target=function(n){return arguments.length?(a=Mt(n),t):a},t.startAngle=function(n){return arguments.length?(s=Mt(n),t):s},t.endAngle=function(n){return arguments.length?(l=Mt(n),t):l},t},sa.svg.diagonal=function(){function t(t,i){var o=n.call(this,t,i),a=e.call(this,t,i),u=(o.y+a.y)/2,s=[o,{x:o.x,y:u},{x:a.x,y:u},a];return s=s.map(r),"M"+s[0]+"C"+s[1]+" "+s[2]+" "+s[3]}var n=$e,e=xe,r=Wo;return t.source=function(e){return arguments.length?(n=Mt(e),t):n},t.target=function(n){return arguments.length?(e=Mt(n),t):e},t.projection=function(n){return arguments.length?(r=n,t):r},t},sa.svg.diagonal.radial=function(){var t=sa.svg.diagonal(),n=Wo,e=t.projection;return t.projection=function(t){return arguments.length?e(Uo(n=t)):n},t},sa.svg.symbol=function(){function t(t,r){return(Ds.get(n.call(this,t,r))||Go)(e.call(this,t,r))}var n=Yo,e=Ho;return t.type=function(e){return arguments.length?(n=Mt(e),t):n},t.size=function(n){return arguments.length?(e=Mt(n),t):e},t};var Ds=sa.map({circle:Go,cross:function(t){var n=Math.sqrt(t/5)/2;return"M"+-3*n+","+-n+"H"+-n+"V"+-3*n+"H"+n+"V"+-n+"H"+3*n+"V"+n+"H"+n+"V"+3*n+"H"+-n+"V"+n+"H"+-3*n+"Z"},diamond:function(t){var n=Math.sqrt(t/(2*Is)),e=n*Is;return"M0,"+-n+"L"+e+",0 0,"+n+" "+-e+",0Z"},square:function(t){var n=Math.sqrt(t)/2;return"M"+-n+","+-n+"L"+n+","+-n+" "+n+","+n+" "+-n+","+n+"Z"},"triangle-down":function(t){var n=Math.sqrt(t/Fs),e=n*Fs/2;return"M0,"+e+"L"+n+","+-e+" "+-n+","+-e+"Z"},"triangle-up":function(t){var n=Math.sqrt(t/Fs),e=n*Fs/2;return"M0,"+-e+"L"+n+","+e+" "+-n+","+e+"Z"}});sa.svg.symbolTypes=Ds.keys();var Fs=Math.sqrt(3),Is=Math.tan(30*Ba);Ea.transition=function(t){for(var n,e,r=zs||++Ws,i=Qo(t),o=[],a=qs||{time:Date.now(),ease:Mr,delay:0,duration:250},u=-1,s=this.length;++u<s;){o.push(n=[]);for(var l=this[u],c=-1,f=l.length;++c<f;)(e=l[c])&&ta(e,c,i,r,a),n.push(e)}return Zo(o,i,r)},Ea.interrupt=function(t){return this.each(null==t?Vs:Xo(Qo(t)))};var zs,qs,Vs=Xo(Qo()),Bs=[],Ws=0;Bs.call=Ea.call,Bs.empty=Ea.empty,Bs.node=Ea.node,Bs.size=Ea.size,sa.transition=function(t,n){return t&&t.transition?zs?t.transition(n):t:sa.selection().transition(t)},sa.transition.prototype=Bs,Bs.select=function(t){var n,e,r,i=this.id,o=this.namespace,a=[];t=A(t);for(var u=-1,s=this.length;++u<s;){a.push(n=[]);for(var l=this[u],c=-1,f=l.length;++c<f;)(r=l[c])&&(e=t.call(r,r.__data__,c,u))?("__data__"in r&&(e.__data__=r.__data__),ta(e,c,o,i,r[o][i]),n.push(e)):n.push(null)}return Zo(a,o,i)},Bs.selectAll=function(t){var n,e,r,i,o,a=this.id,u=this.namespace,s=[];t=E(t);for(var l=-1,c=this.length;++l<c;)for(var f=this[l],h=-1,p=f.length;++h<p;)if(r=f[h]){o=r[u][a],e=t.call(r,r.__data__,h,l),s.push(n=[]);for(var d=-1,v=e.length;++d<v;)(i=e[d])&&ta(i,d,u,a,o),n.push(i)}return Zo(s,u,a)},Bs.filter=function(t){var n,e,r,i=[];"function"!=typeof t&&(t=q(t));for(var o=0,a=this.length;a>o;o++){i.push(n=[]);for(var e=this[o],u=0,s=e.length;s>u;u++)(r=e[u])&&t.call(r,r.__data__,u,o)&&n.push(r)}return Zo(i,this.namespace,this.id)},Bs.tween=function(t,n){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(t):B(this,null==n?function(n){n[r][e].tween.remove(t)}:function(i){i[r][e].tween.set(t,n)})},Bs.attr=function(t,n){function e(){this.removeAttribute(u)}function r(){this.removeAttributeNS(u.space,u.local)}function i(t){return null==t?e:(t+="",function(){var n,e=this.getAttribute(u);return e!==t&&(n=a(e,t),function(t){this.setAttribute(u,n(t))})})}function o(t){return null==t?r:(t+="",function(){var n,e=this.getAttributeNS(u.space,u.local);return e!==t&&(n=a(e,t),function(t){this.setAttributeNS(u.space,u.local,n(t))})})}if(arguments.length<2){for(n in t)this.attr(n,t[n]);return this}var a="transform"==t?Yr:$r,u=sa.ns.qualify(t);return Jo(this,"attr."+t,n,u.local?o:i)},Bs.attrTween=function(t,n){function e(t,e){var r=n.call(this,t,e,this.getAttribute(i));return r&&function(t){this.setAttribute(i,r(t))}}function r(t,e){var r=n.call(this,t,e,this.getAttributeNS(i.space,i.local));return r&&function(t){this.setAttributeNS(i.space,i.local,r(t))}}var i=sa.ns.qualify(t);return this.tween("attr."+t,i.local?r:e)},Bs.style=function(t,e,r){function i(){this.style.removeProperty(t)}function o(e){return null==e?i:(e+="",function(){var i,o=n(this).getComputedStyle(this,null).getPropertyValue(t);return o!==e&&(i=$r(o,e),function(n){this.style.setProperty(t,i(n),r)})})}var a=arguments.length;if(3>a){if("string"!=typeof t){2>a&&(e="");for(r in t)this.style(r,t[r],e);return this}r=""}return Jo(this,"style."+t,e,o)},Bs.styleTween=function(t,e,r){function i(i,o){var a=e.call(this,i,o,n(this).getComputedStyle(this,null).getPropertyValue(t));return a&&function(n){this.style.setProperty(t,a(n),r)}}return arguments.length<3&&(r=""),this.tween("style."+t,i)},Bs.text=function(t){return Jo(this,"text",t,Ko)},Bs.remove=function(){var t=this.namespace;return this.each("end.transition",function(){var n;this[t].count<2&&(n=this.parentNode)&&n.removeChild(this)})},Bs.ease=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].ease:("function"!=typeof t&&(t=sa.ease.apply(sa,arguments)),B(this,function(r){r[e][n].ease=t}))},Bs.delay=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].delay:B(this,"function"==typeof t?function(r,i,o){r[e][n].delay=+t.call(r,r.__data__,i,o)}:(t=+t,function(r){r[e][n].delay=t}))},Bs.duration=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].duration:B(this,"function"==typeof t?function(r,i,o){r[e][n].duration=Math.max(1,t.call(r,r.__data__,i,o))}:(t=Math.max(1,t),function(r){r[e][n].duration=t}))},Bs.each=function(t,n){var e=this.id,r=this.namespace;if(arguments.length<2){var i=qs,o=zs;try{zs=e,B(this,function(n,i,o){qs=n[r][e],t.call(n,n.__data__,i,o)})}finally{qs=i,zs=o}}else B(this,function(i){var o=i[r][e];(o.event||(o.event=sa.dispatch("start","end","interrupt"))).on(t,n)});return this},Bs.transition=function(){for(var t,n,e,r,i=this.id,o=++Ws,a=this.namespace,u=[],s=0,l=this.length;l>s;s++){u.push(t=[]);for(var n=this[s],c=0,f=n.length;f>c;c++)(e=n[c])&&(r=e[a][i],ta(e,c,a,o,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),t.push(e)}return Zo(u,a,o)},sa.svg.axis=function(){function t(t){t.each(function(){var t,l=sa.select(this),c=this.__chart__||e,f=this.__chart__=e.copy(),h=null==s?f.ticks?f.ticks.apply(f,u):f.domain():s,p=null==n?f.tickFormat?f.tickFormat.apply(f,u):y:n,d=l.selectAll(".tick").data(h,f),v=d.enter().insert("g",".domain").attr("class","tick").style("opacity",Da),g=sa.transition(d.exit()).style("opacity",Da).remove(),m=sa.transition(d.order()).style("opacity",1),$=Math.max(i,0)+a,x=Wi(f),b=l.selectAll(".domain").data([0]),w=(b.enter().append("path").attr("class","domain"),sa.transition(b));v.append("line"),v.append("text");var C,S,_,M,k=v.select("line"),A=m.select("line"),E=d.select("text").text(p),P=v.select("text"),O=m.select("text"),T="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(t=na,C="x",_="y",S="x2",M="y2",E.attr("dy",0>T?"0em":".71em").style("text-anchor","middle"),w.attr("d","M"+x[0]+","+T*o+"V0H"+x[1]+"V"+T*o)):(t=ea,C="y",_="x",S="y2",M="x2",E.attr("dy",".32em").style("text-anchor",0>T?"end":"start"),w.attr("d","M"+T*o+","+x[0]+"H0V"+x[1]+"H"+T*o)),k.attr(M,T*i),P.attr(_,T*$),A.attr(S,0).attr(M,T*i),O.attr(C,0).attr(_,T*$),f.rangeBand){var L=f,j=L.rangeBand()/2;c=f=function(t){return L(t)+j}}else c.rangeBand?c=f:g.call(t,f,c);v.call(t,c,f),m.call(t,f,f)})}var n,e=sa.scale.linear(),r=Us,i=6,o=6,a=3,u=[10],s=null;return t.scale=function(n){return arguments.length?(e=n,t):e},t.orient=function(n){return arguments.length?(r=n in Hs?n+"":Us,t):r},t.ticks=function(){return arguments.length?(u=ca(arguments),t):u},t.tickValues=function(n){return arguments.length?(s=n,t):s},t.tickFormat=function(e){return arguments.length?(n=e,t):n},t.tickSize=function(n){var e=arguments.length;return e?(i=+n,o=+arguments[e-1],t):i},t.innerTickSize=function(n){return arguments.length?(i=+n,t):i},t.outerTickSize=function(n){return arguments.length?(o=+n,t):o},t.tickPadding=function(n){return arguments.length?(a=+n,t):a},t.tickSubdivide=function(){return arguments.length&&t},t};var Us="bottom",Hs={top:1,right:1,bottom:1,left:1};sa.svg.brush=function(){function t(n){n.each(function(){var n=sa.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",o).on("touchstart.brush",o),a=n.selectAll(".background").data([0]);a.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),n.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var u=n.selectAll(".resize").data(v,y);u.exit().remove(),u.enter().append("g").attr("class",function(t){return"resize "+t}).style("cursor",function(t){return Ys[t]}).append("rect").attr("x",function(t){return/[ew]$/.test(t)?-3:null}).attr("y",function(t){return/^[ns]/.test(t)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),u.style("display",t.empty()?"none":null);var s,f=sa.transition(n),h=sa.transition(a);l&&(s=Wi(l),h.attr("x",s[0]).attr("width",s[1]-s[0]),r(f)),c&&(s=Wi(c),h.attr("y",s[0]).attr("height",s[1]-s[0]),i(f)),e(f)})}function e(t){t.selectAll(".resize").attr("transform",function(t){return"translate("+f[+/e$/.test(t)]+","+h[+/^s/.test(t)]+")"})}function r(t){t.select(".extent").attr("x",f[0]),t.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function i(t){t.select(".extent").attr("y",h[0]),t.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function o(){function o(){32==sa.event.keyCode&&(E||($=null,O[0]-=f[1],O[1]-=h[1],E=2),S())}function v(){32==sa.event.keyCode&&2==E&&(O[0]+=f[1],O[1]+=h[1],E=0,S())}function g(){var t=sa.mouse(b),n=!1;x&&(t[0]+=x[0],t[1]+=x[1]),E||(sa.event.altKey?($||($=[(f[0]+f[1])/2,(h[0]+h[1])/2]),O[0]=f[+(t[0]<$[0])],O[1]=h[+(t[1]<$[1])]):$=null),k&&m(t,l,0)&&(r(_),n=!0),A&&m(t,c,1)&&(i(_),n=!0),n&&(e(_),C({type:"brush",mode:E?"move":"resize"}))}function m(t,n,e){var r,i,o=Wi(n),s=o[0],l=o[1],c=O[e],v=e?h:f,g=v[1]-v[0];return E&&(s-=c,l-=g+c),r=(e?d:p)?Math.max(s,Math.min(l,t[e])):t[e],E?i=(r+=c)+g:($&&(c=Math.max(s,Math.min(l,2*$[e]-r))),r>c?(i=r,r=c):i=c),v[0]!=r||v[1]!=i?(e?u=null:a=null,v[0]=r,v[1]=i,!0):void 0}function y(){g(),_.style("pointer-events","all").selectAll(".resize").style("display",t.empty()?"none":null),sa.select("body").style("cursor",null),T.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),P(),C({type:"brushend"})}var $,x,b=this,w=sa.select(sa.event.target),C=s.of(b,arguments),_=sa.select(b),M=w.datum(),k=!/^(n|s)$/.test(M)&&l,A=!/^(e|w)$/.test(M)&&c,E=w.classed("extent"),P=X(b),O=sa.mouse(b),T=sa.select(n(b)).on("keydown.brush",o).on("keyup.brush",v);if(sa.event.changedTouches?T.on("touchmove.brush",g).on("touchend.brush",y):T.on("mousemove.brush",g).on("mouseup.brush",y),_.interrupt().selectAll("*").interrupt(),E)O[0]=f[0]-O[0],O[1]=h[0]-O[1];else if(M){var L=+/w$/.test(M),j=+/^n/.test(M);x=[f[1-L]-O[0],h[1-j]-O[1]],O[0]=f[L],O[1]=h[j]}else sa.event.altKey&&($=O.slice());_.style("pointer-events","none").selectAll(".resize").style("display",null),sa.select("body").style("cursor",w.style("cursor")),C({type:"brushstart"}),g()}var a,u,s=M(t,"brushstart","brush","brushend"),l=null,c=null,f=[0,0],h=[0,0],p=!0,d=!0,v=Gs[0];return t.event=function(t){t.each(function(){var t=s.of(this,arguments),n={x:f,y:h,i:a,j:u},e=this.__chart__||n;this.__chart__=n,zs?sa.select(this).transition().each("start.brush",function(){a=e.i,u=e.j,f=e.x,h=e.y,t({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(f,n.x),r=xr(h,n.y);return a=u=null,function(i){f=n.x=e(i),h=n.y=r(i),t({type:"brush",mode:"resize"})}}).each("end.brush",function(){a=n.i,u=n.j,t({type:"brush",mode:"resize"}),t({type:"brushend"})}):(t({type:"brushstart"}),t({type:"brush",mode:"resize"}),t({type:"brushend"}))})},t.x=function(n){return arguments.length?(l=n,v=Gs[!l<<1|!c],t):l},t.y=function(n){return arguments.length?(c=n,v=Gs[!l<<1|!c],t):c},t.clamp=function(n){return arguments.length?(l&&c?(p=!!n[0],d=!!n[1]):l?p=!!n:c&&(d=!!n),t):l&&c?[p,d]:l?p:c?d:null},t.extent=function(n){var e,r,i,o,s;return arguments.length?(l&&(e=n[0],r=n[1],c&&(e=e[0],r=r[0]),a=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(s=e,e=r,r=s),e==f[0]&&r==f[1]||(f=[e,r])),c&&(i=n[0],o=n[1],l&&(i=i[1],o=o[1]),u=[i,o],c.invert&&(i=c(i),o=c(o)),i>o&&(s=i,i=o,o=s),i==h[0]&&o==h[1]||(h=[i,o])),t):(l&&(a?(e=a[0],r=a[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(s=e,e=r,r=s))),c&&(u?(i=u[0],o=u[1]):(i=h[0],o=h[1],c.invert&&(i=c.invert(i),o=c.invert(o)),i>o&&(s=i,i=o,o=s))),l&&c?[[e,i],[r,o]]:l?[e,r]:c&&[i,o])},t.clear=function(){return t.empty()||(f=[0,0],h=[0,0],a=u=null),t},t.empty=function(){return!!l&&f[0]==f[1]||!!c&&h[0]==h[1]},sa.rebind(t,s,"on")};var Ys={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Gs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Xs=du.format=xu.timeFormat,Zs=Xs.utc,Js=Zs("%Y-%m-%dT%H:%M:%S.%LZ");Xs.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?ra:Js,ra.parse=function(t){var n=new Date(t);return isNaN(n)?null:n},ra.toString=Js.toString,du.second=zt(function(t){return new vu(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(t.getTime()+1e3*Math.floor(n))},function(t){return t.getSeconds()}),du.seconds=du.second.range,du.seconds.utc=du.second.utc.range,du.minute=zt(function(t){return new vu(6e4*Math.floor(t/6e4))},function(t,n){t.setTime(t.getTime()+6e4*Math.floor(n))},function(t){return t.getMinutes()}),du.minutes=du.minute.range,du.minutes.utc=du.minute.utc.range,du.hour=zt(function(t){var n=t.getTimezoneOffset()/60;return new vu(36e5*(Math.floor(t/36e5-n)+n))},function(t,n){t.setTime(t.getTime()+36e5*Math.floor(n))},function(t){return t.getHours()}),du.hours=du.hour.range,du.hours.utc=du.hour.utc.range,du.month=zt(function(t){return t=du.day(t),t.setDate(1),t},function(t,n){t.setMonth(t.getMonth()+n)},function(t){return t.getMonth()}),du.months=du.month.range,du.months.utc=du.month.utc.range;var Ks=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Qs=[[du.second,1],[du.second,5],[du.second,15],[du.second,30],[du.minute,1],[du.minute,5],[du.minute,15],[du.minute,30],[du.hour,1],[du.hour,3],[du.hour,6],[du.hour,12],[du.day,1],[du.day,2],[du.week,1],[du.month,1],[du.month,3],[du.year,1]],tl=Xs.multi([[".%L",function(t){return t.getMilliseconds()}],[":%S",function(t){return t.getSeconds()}],["%I:%M",function(t){return t.getMinutes()}],["%I %p",function(t){return t.getHours()}],["%a %d",function(t){return t.getDay()&&1!=t.getDate()}],["%b %d",function(t){return 1!=t.getDate()}],["%B",function(t){return t.getMonth()}],["%Y",Pn]]),nl={range:function(t,n,e){return sa.range(Math.ceil(t/e)*e,+n,e).map(oa)},floor:y,ceil:y};Qs.year=du.year,du.scale=function(){return ia(sa.scale.linear(),Qs,tl)};var el=Qs.map(function(t){return[t[0].utc,t[1]]}),rl=Zs.multi([[".%L",function(t){return t.getUTCMilliseconds()}],[":%S",function(t){return t.getUTCSeconds()}],["%I:%M",function(t){return t.getUTCMinutes()}],["%I %p",function(t){return t.getUTCHours()}],["%a %d",function(t){return t.getUTCDay()&&1!=t.getUTCDate()}],["%b %d",function(t){return 1!=t.getUTCDate()}],["%B",function(t){return t.getUTCMonth()}],["%Y",Pn]]);el.year=du.year.utc,du.scale.utc=function(){return ia(sa.scale.linear(),el,rl)},sa.text=kt(function(t){return t.responseText}),sa.json=function(t,n){return At(t,"application/json",aa,n)},sa.html=function(t,n){return At(t,"text/html",ua,n)},sa.xml=kt(function(t){return t.responseXML}),"function"==typeof define&&define.amd?(this.d3=sa,define(sa)):"object"==typeof module&&module.exports?module.exports=sa:this.d3=sa}();
\ No newline at end of file
+},t.endAngle=function(n){return arguments.length?(u=Mt(n),t):u},t.padAngle=function(n){return arguments.length?(s=Mt(n),t):s},t.centroid=function(){var t=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,n=(+a.apply(this,arguments)+ +u.apply(this,arguments))/2-Va;return[Math.cos(n)*t,Math.sin(n)*t]},t};var Ts="auto";sa.svg.line=function(){return xo(y)};var Ls=sa.map({linear:bo,"linear-closed":wo,step:Co,"step-before":So,"step-after":_o,basis:Oo,"basis-open":To,"basis-closed":Lo,bundle:jo,cardinal:Ao,"cardinal-open":Mo,"cardinal-closed":ko,monotone:zo});Ls.forEach(function(t,n){n.key=t,n.closed=/-closed$/.test(t)});var js=[0,2/3,1/3,0],Ns=[0,1/3,2/3,0],Rs=[0,1/6,2/3,1/6];sa.svg.line.radial=function(){var t=xo(qo);return t.radius=t.x,delete t.x,t.angle=t.y,delete t.y,t},So.reverse=_o,_o.reverse=So,sa.svg.area=function(){return Vo(y)},sa.svg.area.radial=function(){var t=Vo(qo);return t.radius=t.x,delete t.x,t.innerRadius=t.x0,delete t.x0,t.outerRadius=t.x1,delete t.x1,t.angle=t.y,delete t.y,t.startAngle=t.y0,delete t.y0,t.endAngle=t.y1,delete t.y1,t},sa.svg.chord=function(){function t(t,u){var s=n(this,o,t,u),l=n(this,a,t,u);return"M"+s.p0+r(s.r,s.p1,s.a1-s.a0)+(e(s,l)?i(s.r,s.p1,s.r,s.p0):i(s.r,s.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+i(l.r,l.p1,s.r,s.p0))+"Z"}function n(t,n,e,r){var i=n.call(t,e,r),o=u.call(t,i,r),a=s.call(t,i,r)-Va,c=l.call(t,i,r)-Va;return{r:o,a0:a,a1:c,p0:[o*Math.cos(a),o*Math.sin(a)],p1:[o*Math.cos(c),o*Math.sin(c)]}}function e(t,n){return t.a0==n.a0&&t.a1==n.a1}function r(t,n,e){return"A"+t+","+t+" 0 "+ +(e>Ia)+",1 "+n}function i(t,n,e,r){return"Q 0,0 "+r}var o=$e,a=xe,u=Bo,s=vo,l=go;return t.radius=function(n){return arguments.length?(u=Mt(n),t):u},t.source=function(n){return arguments.length?(o=Mt(n),t):o},t.target=function(n){return arguments.length?(a=Mt(n),t):a},t.startAngle=function(n){return arguments.length?(s=Mt(n),t):s},t.endAngle=function(n){return arguments.length?(l=Mt(n),t):l},t},sa.svg.diagonal=function(){function t(t,i){var o=n.call(this,t,i),a=e.call(this,t,i),u=(o.y+a.y)/2,s=[o,{x:o.x,y:u},{x:a.x,y:u},a];return s=s.map(r),"M"+s[0]+"C"+s[1]+" "+s[2]+" "+s[3]}var n=$e,e=xe,r=Wo;return t.source=function(e){return arguments.length?(n=Mt(e),t):n},t.target=function(n){return arguments.length?(e=Mt(n),t):e},t.projection=function(n){return arguments.length?(r=n,t):r},t},sa.svg.diagonal.radial=function(){var t=sa.svg.diagonal(),n=Wo,e=t.projection;return t.projection=function(t){return arguments.length?e(Uo(n=t)):n},t},sa.svg.symbol=function(){function t(t,r){return(Ds.get(n.call(this,t,r))||Go)(e.call(this,t,r))}var n=Yo,e=Ho;return t.type=function(e){return arguments.length?(n=Mt(e),t):n},t.size=function(n){return arguments.length?(e=Mt(n),t):e},t};var Ds=sa.map({circle:Go,cross:function(t){var n=Math.sqrt(t/5)/2;return"M"+-3*n+","+-n+"H"+-n+"V"+-3*n+"H"+n+"V"+-n+"H"+3*n+"V"+n+"H"+n+"V"+3*n+"H"+-n+"V"+n+"H"+-3*n+"Z"},diamond:function(t){var n=Math.sqrt(t/(2*Is)),e=n*Is;return"M0,"+-n+"L"+e+",0 0,"+n+" "+-e+",0Z"},square:function(t){var n=Math.sqrt(t)/2;return"M"+-n+","+-n+"L"+n+","+-n+" "+n+","+n+" "+-n+","+n+"Z"},"triangle-down":function(t){var n=Math.sqrt(t/Fs),e=n*Fs/2;return"M0,"+e+"L"+n+","+-e+" "+-n+","+-e+"Z"},"triangle-up":function(t){var n=Math.sqrt(t/Fs),e=n*Fs/2;return"M0,"+-e+"L"+n+","+e+" "+-n+","+e+"Z"}});sa.svg.symbolTypes=Ds.keys();var Fs=Math.sqrt(3),Is=Math.tan(30*Ba);Ea.transition=function(t){for(var n,e,r=zs||++Ws,i=Qo(t),o=[],a=qs||{time:Date.now(),ease:Mr,delay:0,duration:250},u=-1,s=this.length;++u<s;){o.push(n=[]);for(var l=this[u],c=-1,f=l.length;++c<f;)(e=l[c])&&ta(e,c,i,r,a),n.push(e)}return Zo(o,i,r)},Ea.interrupt=function(t){return this.each(null==t?Vs:Xo(Qo(t)))};var zs,qs,Vs=Xo(Qo()),Bs=[],Ws=0;Bs.call=Ea.call,Bs.empty=Ea.empty,Bs.node=Ea.node,Bs.size=Ea.size,sa.transition=function(t,n){return t&&t.transition?zs?t.transition(n):t:sa.selection().transition(t)},sa.transition.prototype=Bs,Bs.select=function(t){var n,e,r,i=this.id,o=this.namespace,a=[];t=A(t);for(var u=-1,s=this.length;++u<s;){a.push(n=[]);for(var l=this[u],c=-1,f=l.length;++c<f;)(r=l[c])&&(e=t.call(r,r.__data__,c,u))?("__data__"in r&&(e.__data__=r.__data__),ta(e,c,o,i,r[o][i]),n.push(e)):n.push(null)}return Zo(a,o,i)},Bs.selectAll=function(t){var n,e,r,i,o,a=this.id,u=this.namespace,s=[];t=E(t);for(var l=-1,c=this.length;++l<c;)for(var f=this[l],h=-1,p=f.length;++h<p;)if(r=f[h]){o=r[u][a],e=t.call(r,r.__data__,h,l),s.push(n=[]);for(var d=-1,v=e.length;++d<v;)(i=e[d])&&ta(i,d,u,a,o),n.push(i)}return Zo(s,u,a)},Bs.filter=function(t){var n,e,r,i=[];"function"!=typeof t&&(t=q(t));for(var o=0,a=this.length;a>o;o++){i.push(n=[]);for(var e=this[o],u=0,s=e.length;s>u;u++)(r=e[u])&&t.call(r,r.__data__,u,o)&&n.push(r)}return Zo(i,this.namespace,this.id)},Bs.tween=function(t,n){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(t):B(this,null==n?function(n){n[r][e].tween.remove(t)}:function(i){i[r][e].tween.set(t,n)})},Bs.attr=function(t,n){function e(){this.removeAttribute(u)}function r(){this.removeAttributeNS(u.space,u.local)}function i(t){return null==t?e:(t+="",function(){var n,e=this.getAttribute(u);return e!==t&&(n=a(e,t),function(t){this.setAttribute(u,n(t))})})}function o(t){return null==t?r:(t+="",function(){var n,e=this.getAttributeNS(u.space,u.local);return e!==t&&(n=a(e,t),function(t){this.setAttributeNS(u.space,u.local,n(t))})})}if(arguments.length<2){for(n in t)this.attr(n,t[n]);return this}var a="transform"==t?Yr:$r,u=sa.ns.qualify(t);return Jo(this,"attr."+t,n,u.local?o:i)},Bs.attrTween=function(t,n){function e(t,e){var r=n.call(this,t,e,this.getAttribute(i));return r&&function(t){this.setAttribute(i,r(t))}}function r(t,e){var r=n.call(this,t,e,this.getAttributeNS(i.space,i.local));return r&&function(t){this.setAttributeNS(i.space,i.local,r(t))}}var i=sa.ns.qualify(t);return this.tween("attr."+t,i.local?r:e)},Bs.style=function(t,e,r){function i(){this.style.removeProperty(t)}function o(e){return null==e?i:(e+="",function(){var i,o=n(this).getComputedStyle(this,null).getPropertyValue(t);return o!==e&&(i=$r(o,e),function(n){this.style.setProperty(t,i(n),r)})})}var a=arguments.length;if(3>a){if("string"!=typeof t){2>a&&(e="");for(r in t)this.style(r,t[r],e);return this}r=""}return Jo(this,"style."+t,e,o)},Bs.styleTween=function(t,e,r){function i(i,o){var a=e.call(this,i,o,n(this).getComputedStyle(this,null).getPropertyValue(t));return a&&function(n){this.style.setProperty(t,a(n),r)}}return arguments.length<3&&(r=""),this.tween("style."+t,i)},Bs.text=function(t){return Jo(this,"text",t,Ko)},Bs.remove=function(){var t=this.namespace;return this.each("end.transition",function(){var n;this[t].count<2&&(n=this.parentNode)&&n.removeChild(this)})},Bs.ease=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].ease:("function"!=typeof t&&(t=sa.ease.apply(sa,arguments)),B(this,function(r){r[e][n].ease=t}))},Bs.delay=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].delay:B(this,"function"==typeof t?function(r,i,o){r[e][n].delay=+t.call(r,r.__data__,i,o)}:(t=+t,function(r){r[e][n].delay=t}))},Bs.duration=function(t){var n=this.id,e=this.namespace;return arguments.length<1?this.node()[e][n].duration:B(this,"function"==typeof t?function(r,i,o){r[e][n].duration=Math.max(1,t.call(r,r.__data__,i,o))}:(t=Math.max(1,t),function(r){r[e][n].duration=t}))},Bs.each=function(t,n){var e=this.id,r=this.namespace;if(arguments.length<2){var i=qs,o=zs;try{zs=e,B(this,function(n,i,o){qs=n[r][e],t.call(n,n.__data__,i,o)})}finally{qs=i,zs=o}}else B(this,function(i){var o=i[r][e];(o.event||(o.event=sa.dispatch("start","end","interrupt"))).on(t,n)});return this},Bs.transition=function(){for(var t,n,e,r,i=this.id,o=++Ws,a=this.namespace,u=[],s=0,l=this.length;l>s;s++){u.push(t=[]);for(var n=this[s],c=0,f=n.length;f>c;c++)(e=n[c])&&(r=e[a][i],ta(e,c,a,o,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),t.push(e)}return Zo(u,a,o)},sa.svg.axis=function(){function t(t){t.each(function(){var t,l=sa.select(this),c=this.__chart__||e,f=this.__chart__=e.copy(),h=null==s?f.ticks?f.ticks.apply(f,u):f.domain():s,p=null==n?f.tickFormat?f.tickFormat.apply(f,u):y:n,d=l.selectAll(".tick").data(h,f),v=d.enter().insert("g",".domain").attr("class","tick").style("opacity",Da),g=sa.transition(d.exit()).style("opacity",Da).remove(),m=sa.transition(d.order()).style("opacity",1),$=Math.max(i,0)+a,x=Wi(f),b=l.selectAll(".domain").data([0]),w=(b.enter().append("path").attr("class","domain"),sa.transition(b));v.append("line"),v.append("text");var C,S,_,M,k=v.select("line"),A=m.select("line"),E=d.select("text").text(p),P=v.select("text"),O=m.select("text"),T="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(t=na,C="x",_="y",S="x2",M="y2",E.attr("dy",0>T?"0em":".71em").style("text-anchor","middle"),w.attr("d","M"+x[0]+","+T*o+"V0H"+x[1]+"V"+T*o)):(t=ea,C="y",_="x",S="y2",M="x2",E.attr("dy",".32em").style("text-anchor",0>T?"end":"start"),w.attr("d","M"+T*o+","+x[0]+"H0V"+x[1]+"H"+T*o)),k.attr(M,T*i),P.attr(_,T*$),A.attr(S,0).attr(M,T*i),O.attr(C,0).attr(_,T*$),f.rangeBand){var L=f,j=L.rangeBand()/2;c=f=function(t){return L(t)+j}}else c.rangeBand?c=f:g.call(t,f,c);v.call(t,c,f),m.call(t,f,f)})}var n,e=sa.scale.linear(),r=Us,i=6,o=6,a=3,u=[10],s=null;return t.scale=function(n){return arguments.length?(e=n,t):e},t.orient=function(n){return arguments.length?(r=n in Hs?n+"":Us,t):r},t.ticks=function(){return arguments.length?(u=ca(arguments),t):u},t.tickValues=function(n){return arguments.length?(s=n,t):s},t.tickFormat=function(e){return arguments.length?(n=e,t):n},t.tickSize=function(n){var e=arguments.length;return e?(i=+n,o=+arguments[e-1],t):i},t.innerTickSize=function(n){return arguments.length?(i=+n,t):i},t.outerTickSize=function(n){return arguments.length?(o=+n,t):o},t.tickPadding=function(n){return arguments.length?(a=+n,t):a},t.tickSubdivide=function(){return arguments.length&&t},t};var Us="bottom",Hs={top:1,right:1,bottom:1,left:1};sa.svg.brush=function(){function t(n){n.each(function(){var n=sa.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",o).on("touchstart.brush",o),a=n.selectAll(".background").data([0]);a.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),n.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var u=n.selectAll(".resize").data(v,y);u.exit().remove(),u.enter().append("g").attr("class",function(t){return"resize "+t}).style("cursor",function(t){return Ys[t]}).append("rect").attr("x",function(t){return/[ew]$/.test(t)?-3:null}).attr("y",function(t){return/^[ns]/.test(t)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),u.style("display",t.empty()?"none":null);var s,f=sa.transition(n),h=sa.transition(a);l&&(s=Wi(l),h.attr("x",s[0]).attr("width",s[1]-s[0]),r(f)),c&&(s=Wi(c),h.attr("y",s[0]).attr("height",s[1]-s[0]),i(f)),e(f)})}function e(t){t.selectAll(".resize").attr("transform",function(t){return"translate("+f[+/e$/.test(t)]+","+h[+/^s/.test(t)]+")"})}function r(t){t.select(".extent").attr("x",f[0]),t.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function i(t){t.select(".extent").attr("y",h[0]),t.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function o(){function o(){32==sa.event.keyCode&&(E||($=null,O[0]-=f[1],O[1]-=h[1],E=2),S())}function v(){32==sa.event.keyCode&&2==E&&(O[0]+=f[1],O[1]+=h[1],E=0,S())}function g(){var t=sa.mouse(b),n=!1;x&&(t[0]+=x[0],t[1]+=x[1]),E||(sa.event.altKey?($||($=[(f[0]+f[1])/2,(h[0]+h[1])/2]),O[0]=f[+(t[0]<$[0])],O[1]=h[+(t[1]<$[1])]):$=null),k&&m(t,l,0)&&(r(_),n=!0),A&&m(t,c,1)&&(i(_),n=!0),n&&(e(_),C({type:"brush",mode:E?"move":"resize"}))}function m(t,n,e){var r,i,o=Wi(n),s=o[0],l=o[1],c=O[e],v=e?h:f,g=v[1]-v[0];return E&&(s-=c,l-=g+c),r=(e?d:p)?Math.max(s,Math.min(l,t[e])):t[e],E?i=(r+=c)+g:($&&(c=Math.max(s,Math.min(l,2*$[e]-r))),r>c?(i=r,r=c):i=c),v[0]!=r||v[1]!=i?(e?u=null:a=null,v[0]=r,v[1]=i,!0):void 0}function y(){g(),_.style("pointer-events","all").selectAll(".resize").style("display",t.empty()?"none":null),sa.select("body").style("cursor",null),T.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),P(),C({type:"brushend"})}var $,x,b=this,w=sa.select(sa.event.target),C=s.of(b,arguments),_=sa.select(b),M=w.datum(),k=!/^(n|s)$/.test(M)&&l,A=!/^(e|w)$/.test(M)&&c,E=w.classed("extent"),P=X(b),O=sa.mouse(b),T=sa.select(n(b)).on("keydown.brush",o).on("keyup.brush",v);if(sa.event.changedTouches?T.on("touchmove.brush",g).on("touchend.brush",y):T.on("mousemove.brush",g).on("mouseup.brush",y),_.interrupt().selectAll("*").interrupt(),E)O[0]=f[0]-O[0],O[1]=h[0]-O[1];else if(M){var L=+/w$/.test(M),j=+/^n/.test(M);x=[f[1-L]-O[0],h[1-j]-O[1]],O[0]=f[L],O[1]=h[j]}else sa.event.altKey&&($=O.slice());_.style("pointer-events","none").selectAll(".resize").style("display",null),sa.select("body").style("cursor",w.style("cursor")),C({type:"brushstart"}),g()}var a,u,s=M(t,"brushstart","brush","brushend"),l=null,c=null,f=[0,0],h=[0,0],p=!0,d=!0,v=Gs[0];return t.event=function(t){t.each(function(){var t=s.of(this,arguments),n={x:f,y:h,i:a,j:u},e=this.__chart__||n;this.__chart__=n,zs?sa.select(this).transition().each("start.brush",function(){a=e.i,u=e.j,f=e.x,h=e.y,t({type:"brushstart"})}).tween("brush:brush",function(){var e=xr(f,n.x),r=xr(h,n.y);return a=u=null,function(i){f=n.x=e(i),h=n.y=r(i),t({type:"brush",mode:"resize"})}}).each("end.brush",function(){a=n.i,u=n.j,t({type:"brush",mode:"resize"}),t({type:"brushend"})}):(t({type:"brushstart"}),t({type:"brush",mode:"resize"}),t({type:"brushend"}))})},t.x=function(n){return arguments.length?(l=n,v=Gs[!l<<1|!c],t):l},t.y=function(n){return arguments.length?(c=n,v=Gs[!l<<1|!c],t):c},t.clamp=function(n){return arguments.length?(l&&c?(p=!!n[0],d=!!n[1]):l?p=!!n:c&&(d=!!n),t):l&&c?[p,d]:l?p:c?d:null},t.extent=function(n){var e,r,i,o,s;return arguments.length?(l&&(e=n[0],r=n[1],c&&(e=e[0],r=r[0]),a=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(s=e,e=r,r=s),e==f[0]&&r==f[1]||(f=[e,r])),c&&(i=n[0],o=n[1],l&&(i=i[1],o=o[1]),u=[i,o],c.invert&&(i=c(i),o=c(o)),i>o&&(s=i,i=o,o=s),i==h[0]&&o==h[1]||(h=[i,o])),t):(l&&(a?(e=a[0],r=a[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(s=e,e=r,r=s))),c&&(u?(i=u[0],o=u[1]):(i=h[0],o=h[1],c.invert&&(i=c.invert(i),o=c.invert(o)),i>o&&(s=i,i=o,o=s))),l&&c?[[e,i],[r,o]]:l?[e,r]:c&&[i,o])},t.clear=function(){return t.empty()||(f=[0,0],h=[0,0],a=u=null),t},t.empty=function(){return!!l&&f[0]==f[1]||!!c&&h[0]==h[1]},sa.rebind(t,s,"on")};var Ys={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Gs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Xs=du.format=xu.timeFormat,Zs=Xs.utc,Js=Zs("%Y-%m-%dT%H:%M:%S.%LZ");Xs.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?ra:Js,ra.parse=function(t){var n=new Date(t);return isNaN(n)?null:n},ra.toString=Js.toString,du.second=zt(function(t){return new vu(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(t.getTime()+1e3*Math.floor(n))},function(t){return t.getSeconds()}),du.seconds=du.second.range,du.seconds.utc=du.second.utc.range,du.minute=zt(function(t){return new vu(6e4*Math.floor(t/6e4))},function(t,n){t.setTime(t.getTime()+6e4*Math.floor(n))},function(t){return t.getMinutes()}),du.minutes=du.minute.range,du.minutes.utc=du.minute.utc.range,du.hour=zt(function(t){var n=t.getTimezoneOffset()/60;return new vu(36e5*(Math.floor(t/36e5-n)+n))},function(t,n){t.setTime(t.getTime()+36e5*Math.floor(n))},function(t){return t.getHours()}),du.hours=du.hour.range,du.hours.utc=du.hour.utc.range,du.month=zt(function(t){return t=du.day(t),t.setDate(1),t},function(t,n){t.setMonth(t.getMonth()+n)},function(t){return t.getMonth()}),du.months=du.month.range,du.months.utc=du.month.utc.range;var Ks=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Qs=[[du.second,1],[du.second,5],[du.second,15],[du.second,30],[du.minute,1],[du.minute,5],[du.minute,15],[du.minute,30],[du.hour,1],[du.hour,3],[du.hour,6],[du.hour,12],[du.day,1],[du.day,2],[du.week,1],[du.month,1],[du.month,3],[du.year,1]],tl=Xs.multi([[".%L",function(t){return t.getMilliseconds()}],[":%S",function(t){return t.getSeconds()}],["%I:%M",function(t){return t.getMinutes()}],["%I %p",function(t){return t.getHours()}],["%a %d",function(t){return t.getDay()&&1!=t.getDate()}],["%b %d",function(t){return 1!=t.getDate()}],["%B",function(t){return t.getMonth()}],["%Y",Pn]]),nl={range:function(t,n,e){return sa.range(Math.ceil(t/e)*e,+n,e).map(oa)},floor:y,ceil:y};Qs.year=du.year,du.scale=function(){return ia(sa.scale.linear(),Qs,tl)};var el=Qs.map(function(t){return[t[0].utc,t[1]]}),rl=Zs.multi([[".%L",function(t){return t.getUTCMilliseconds()}],[":%S",function(t){return t.getUTCSeconds()}],["%I:%M",function(t){return t.getUTCMinutes()}],["%I %p",function(t){return t.getUTCHours()}],["%a %d",function(t){return t.getUTCDay()&&1!=t.getUTCDate()}],["%b %d",function(t){return 1!=t.getUTCDate()}],["%B",function(t){return t.getUTCMonth()}],["%Y",Pn]]);el.year=du.year.utc,du.scale.utc=function(){return ia(sa.scale.linear(),el,rl)},sa.text=kt(function(t){return t.responseText}),sa.json=function(t,n){return At(t,"application/json",aa,n)},sa.html=function(t,n){return At(t,"text/html",ua,n)},sa.xml=kt(function(t){return t.responseXML}),"function"==typeof define&&define.amd?(this.d3=sa,define(sa)):"object"==typeof module&&module.exports?module.exports=sa:this.d3=sa}(),angular.module("RecursionHelper",[]).factory("RecursionHelper",["$compile",function(t){return{compile:function(n,e){angular.isFunction(e)&&(e={post:e});var r,i=n.contents().remove();return{pre:e&&e.pre?e.pre:null,post:function(n,o){r||(r=t(i)),r(n,function(t){o.append(t)}),e&&e.post&&e.post.apply(null,arguments)}}}}}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosSubscribers.js b/xos/core/xoslib/static/js/xosSubscribers.js
index c0500fb..21fa10c 100644
--- a/xos/core/xoslib/static/js/xosSubscribers.js
+++ b/xos/core/xoslib/static/js/xosSubscribers.js
@@ -1 +1 @@
-"use strict";angular.module("xos.subscribers",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(e){e.state("user-list",{url:"/",template:"<subscribers-list></subscribers-list>"})}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).directive("subscribersList",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/subscribers-list.tpl.html",controller:["Subscribers",function(e){var t=this;this.tableConfig={filter:"field",order:!0,pagination:{pageSize:10},columns:[{label:"Name",prop:"humanReadableName"},{label:"Identity",prop:"identity",type:"object"},{label:"Related Info",prop:"related",type:"object"}]},this.smartTableConfig={resource:"Subscribers"},e.query().$promise.then(function(e){t.users=e})["catch"](function(e){throw new Error(e)})}]}}),angular.module("xos.subscribers").run(["$templateCache",function(e){e.put("templates/subscribers-list.tpl.html",'<!-- <xos-table config="vm.tableConfig" data="vm.users"></xos-table> -->\n\n<xos-smart-table config="vm.smartTableConfig"></xos-smart-table>')}]),angular.module("xos.subscribers").run(["$location",function(e){e.path("/")}]);
\ No newline at end of file
+"use strict";angular.module("xos.subscribers",["ngResource","ngCookies","ui.router","xos.helpers"]).config(["$stateProvider",function(s){s.state("user-list",{url:"/",template:"<subscribers-list></subscribers-list>"})}]).config(["$httpProvider",function(s){s.interceptors.push("NoHyperlinks")}]).directive("subscribersList",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/subscribers-list.tpl.html",controller:function(){this.smartTableConfig={resource:"Subscribers"},this.model={label:{name:"aaa"},empty:{}},this.config={exclude:["password","last_login"],formName:"sampleForm",actions:[{label:"Save",icon:"ok",cb:function(s){console.log(s)},"class":"success"}]}}}}),angular.module("xos.subscribers").run(["$templateCache",function(s){s.put("templates/subscribers-list.tpl.html",'<!-- <xos-form ng-model="vm.model" config="vm.config"></xos-form> -->\n<xos-smart-table config="vm.smartTableConfig"></xos-smart-table>')}]),angular.module("xos.subscribers").run(["$location",function(s){s.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosSynchronizerNotifier.js b/xos/core/xoslib/static/js/xosSynchronizerNotifier.js
new file mode 100644
index 0000000..5d743c6
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosSynchronizerNotifier.js
@@ -0,0 +1 @@
+"use strict";angular.module("xos.synchronizerNotifier",["ngResource","ngCookies","xos.helpers"]).run(["$rootScope",function(n){n.$on("$locationChangeStart",function(n){n.preventDefault()})}]).service("Diag",["$rootScope","$http","$q","$interval",function(n,t,s,e){var a=this,o=!1;this.getDiags=function(){var n=s.defer();return t.get("/api/core/diags").then(function(t){n.resolve(t.data)})["catch"](function(t){n.reject(t)}),n.promise},this.sendEvents=function(t){t.forEach(function(t){var s=JSON.parse(t.backend_register);s.last_run=new Date(1e3*s.last_run),s.last_duration=1e3*s.last_duration,s.last_synchronizer_start=new Date(1e3*s.last_synchronizer_start),s.last_syncrecord_start=s.last_syncrecord_start?new Date(1e3*s.last_syncrecord_start):null,n.$broadcast("diag",{name:t.name,updated:t.updated,info:s,status:a.getSyncStatus(s)})})},this.start=function(){return o=!0,a.getDiags().then(function(n){a.sendEvents(n)}),o},this.stop=function(){return o=!1},this.getSyncStatus=function(n){var t=new Date,s=9e5;return!(t-n.last_synchronizer_start>s&&t-n.last_syncrecord_start>s&&t-n.last_run>s)},e(function(){o&&a.getDiags().then(function(n){a.sendEvents(n)})},3e5)}]).directive("syncStatus",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/sync-status.tpl.html",controller:["$log","$rootScope","Diag","xosNotification","XosUserPrefs",function(n,t,s,e,a){var o=this;s.start(),this.synchronizers={},this.showNoSync=!0,t.$on("diag",function(n,t){o.synchronizers[t.name]=t,t.status?a.setSynchronizerNotificationStatus(t.name,!1):(a.getSynchronizerNotificationStatus(t.name)||e.notify("CORD Synchronizer",{icon:"/static/cord-logo.png",body:"The "+t.name+" synchronizer has not performed actions in the last 15 minutes."}),a.setSynchronizerNotificationStatus(t.name,!0)),o.showNoSync=!1,0===Object.keys(o.synchronizers).length&&(o.showNoSync=!0)})}]}}),angular.element(document).ready(function(){angular.bootstrap("#xosSynchronizerNotifier",["xos.synchronizerNotifier"])}),angular.module("xos.synchronizerNotifier").run(["$templateCache",function(n){n.put("templates/sync-status.tpl.html",'<div class="sync-status-container">\n  <div class="btn btn-default" ng-click="vm.showNotificationPanel = !vm.showNotificationPanel">\n    <i class="glyphicon glyphicon-inbox"></i>\n  </div>\n  <div class="notification-panel panel panel-default" ng-show="vm.showNotificationPanel">\n    <ul class="list-group" ng-show="!vm.showNoSync">\n      <li class="list-group-item" ng-repeat="(syncName, syncStatus) in vm.synchronizers">\n        <span class="badge" ng-class="{success: syncStatus.status, warning: !syncStatus.status}">\n          <span ng-show="syncStatus.status"><i class="glyphicon glyphicon-ok"></i></span>\n          <span ng-hide="syncStatus.status"><i class="glyphicon glyphicon-time"></i></span>\n        </span>\n        <b>{{syncName}}</b>\n        <br/>\n        <small><i>{{syncStatus.info.last_run | date:\'mediumTime\'}}</i></small>\n      </li>\n    </ul>\n    <div class="alert alert-info" ng-show="vm.showNoSync">\n      No syncronizers are running.\n    </div>\n  </div>\n</div>\n')}]),angular.module("xos.synchronizerNotifier").run(["$location",function(n){n.path("/")}]);
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xoslib/xos-backbone.js b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
index 04d5fb7..d22d0ec 100644
--- a/xos/core/xoslib/static/js/xoslib/xos-backbone.js
+++ b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
@@ -827,7 +827,7 @@
         define_model(this, {urlRoot: CORDSUBSCRIBER_API,
                             modelName: "cordSubscriber",
                             relatedCollections: {"cordUsers": "subscriber"},
-                            listFields: ["id", "service_specific_id", "vlan_id", "routeable_subnet"],
+                            listFields: ["id", "service_specific_id", "routeable_subnet"],
                             detailFields: ["id", "service_specific_id", "vcpe_id", "image_name", "instance_name",
                                            "firewall_enable", "firewall_rules", "url_filter_enable", "url_filter_rules", "cdn_enable",
                                            "nat_ip", "lan_ip", "wan_ip", "private_ip",
diff --git a/xos/services/cord/admin.py b/xos/services/cord/admin.py
index e7704d3..18f1e81 100644
--- a/xos/services/cord/admin.py
+++ b/xos/services/cord/admin.py
@@ -94,6 +94,59 @@
     def queryset(self, request):
         return VOLTTenant.get_tenant_objects_by_user(request.user)
 
+class AccessDeviceInline(XOSTabularInline):
+    model = AccessDevice
+    fields = ['volt_device','uplink','vlan']
+    readonly_fields = []
+    extra = 0
+#    max_num = 0
+    suit_classes = 'suit-tab suit-tab-accessdevices'
+
+#    @property
+#    def selflink_reverse_path(self):
+#        return "admin:cord_volttenant_change"
+
+class VOLTDeviceAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'name', 'openflow_id', 'driver' )
+    list_display_links = ('backend_status_icon', 'name', 'openflow_id')
+    fieldsets = [ (None, {'fields': ['backend_status_text','name','volt_service','openflow_id','driver','access_agent'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text',)
+    inlines = [AccessDeviceInline]
+
+    suit_form_tabs = (('general','Details'), ('accessdevices','Access Devices'))
+
+class AccessDeviceAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', 'volt_device', 'uplink', 'vlan' )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text','volt_device','uplink','vlan'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text',)
+
+    suit_form_tabs = (('general','Details'),)
+
+class AgentPortMappingInline(XOSTabularInline):
+    model = AgentPortMapping
+    fields = ['access_agent', 'mac', 'port']
+    readonly_fields = []
+    extra = 0
+#    max_num = 0
+    suit_classes = 'suit-tab suit-tab-accessportmaps'
+
+#    @property
+#    def selflink_reverse_path(self):
+#        return "admin:cord_volttenant_change"
+
+class AccessAgentAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'name', 'mac' )
+    list_display_links = ('backend_status_icon', 'name')
+    fieldsets = [ (None, {'fields': ['backend_status_text','name','volt_service','mac'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text',)
+    inlines= [AgentPortMappingInline]
+
+    suit_form_tabs = (('general','Details'), ('accessportmaps', 'Port Mappings'))
+
 #-----------------------------------------------------------------------------
 # vCPE
 #-----------------------------------------------------------------------------
@@ -398,6 +451,10 @@
 
 admin.site.register(VOLTService, VOLTServiceAdmin)
 admin.site.register(VOLTTenant, VOLTTenantAdmin)
+admin.site.register(VOLTDevice, VOLTDeviceAdmin)
+admin.site.register(AccessDevice, AccessDeviceAdmin)
+admin.site.register(AccessAgent, AccessAgentAdmin)
+
 admin.site.register(VSGService, VSGServiceAdmin)
 admin.site.register(VSGTenant, VSGTenantAdmin)
 admin.site.register(VBNGService, VBNGServiceAdmin)
diff --git a/xos/services/cord/models.py b/xos/services/cord/models.py
index 48c9597..19b3ba6 100644
--- a/xos/services/cord/models.py
+++ b/xos/services/cord/models.py
@@ -1,5 +1,5 @@
 from django.db import models
-from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool, User
 from core.models.plcorebase import StrippedCharField
 import os
 from django.db import models, transaction
@@ -188,15 +188,20 @@
     class Meta:
         app_label = "cord"
         verbose_name = "vOLT Service"
-        proxy = True
 
 class VOLTTenant(Tenant):
-    class Meta:
-        proxy = True
-
     KIND = VOLT_KIND
 
-    default_attributes = {"vlan_id": None, "s_tag": None, "c_tag": None}
+    class Meta:
+        app_label = "cord"
+        verbose_name = "vOLT Tenant"
+
+    s_tag = models.IntegerField(null=True, blank=True, help_text="s-tag")
+    c_tag = models.IntegerField(null=True, blank=True, help_text="c-tag")
+
+    # at some point, this should probably end up part of Tenant.
+    creator = models.ForeignKey(User, related_name='created_volts', blank=True, null=True)
+
     def __init__(self, *args, **kwargs):
         volt_services = VOLTService.get_service_objects().all()
         if volt_services:
@@ -205,32 +210,6 @@
         self.cached_vcpe = None
 
     @property
-    def s_tag(self):
-        return self.get_attribute("s_tag", self.default_attributes["s_tag"])
-
-    @s_tag.setter
-    def s_tag(self, value):
-        self.set_attribute("s_tag", value)
-
-    @property
-    def c_tag(self):
-        return self.get_attribute("c_tag", self.default_attributes["c_tag"])
-
-    @c_tag.setter
-    def c_tag(self, value):
-        self.set_attribute("c_tag", value)
-
-    # for now, vlan_id is a synonym for c_tag
-
-    @property
-    def vlan_id(self):
-        return self.c_tag
-
-    @vlan_id.setter
-    def vlan_id(self, value):
-        self.c_tag = value
-
-    @property
     def vcpe(self):
         vcpe = self.get_newest_subscribed_tenant(VSGTenant)
         if not vcpe:
@@ -257,28 +236,6 @@
             return None
         return subs[0]
 
-    @property
-    def creator(self):
-        if getattr(self, "cached_creator", None):
-            return self.cached_creator
-        creator_id=self.get_attribute("creator_id")
-        if not creator_id:
-            return None
-        users=User.objects.filter(id=creator_id)
-        if not users:
-            return None
-        user=users[0]
-        self.cached_creator = users[0]
-        return user
-
-    @creator.setter
-    def creator(self, value):
-        if value:
-            value = value.id
-        if (value != self.get_attribute("creator_id", None)):
-            self.cached_creator=None
-        self.set_attribute("creator_id", value)
-
     def manage_vcpe(self):
         # Each VOLT object owns exactly one VCPE object
 
@@ -347,9 +304,6 @@
 
         super(VOLTTenant, self).save(*args, **kwargs)
         model_policy_volt(self.pk)
-        #self.manage_vcpe()
-        #self.manage_subscriber()
-        #self.cleanup_orphans()
 
     def delete(self, *args, **kwargs):
         self.cleanup_vcpe()
@@ -366,6 +320,49 @@
         volt.manage_subscriber()
         volt.cleanup_orphans()
 
+class VOLTDevice(PlCoreBase):
+    class Meta:
+        app_label = "cord"
+
+    name = models.CharField(max_length=254, help_text="name of device", null=False, blank=False)
+    volt_service = models.ForeignKey(VOLTService, related_name='volt_devices')
+    openflow_id = models.CharField(max_length=254, help_text="OpenFlow ID", null=True, blank=True)
+    driver = models.CharField(max_length=254, help_text="driver", null=True, blank=True)
+    access_agent = models.ForeignKey("AccessAgent", related_name='volt_devices', blank=True, null=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+class AccessDevice(PlCoreBase):
+    class Meta:
+        app_label = "cord"
+
+    volt_device = models.ForeignKey(VOLTDevice, related_name='access_devices')
+    uplink = models.IntegerField(null=True, blank=True)
+    vlan = models.IntegerField(null=True, blank=True)
+
+    def __unicode__(self): return u'%s-%d:%d' % (self.volt_device.name,self.uplink,self.vlan)
+
+class AccessAgent(PlCoreBase):
+    class Meta:
+        app_label = "cord"
+
+    name = models.CharField(max_length=254, help_text="name of agent", null=False, blank=False)
+    volt_service = models.ForeignKey(VOLTService, related_name='access_agents')
+    mac = models.CharField(max_length=32, help_text="MAC Address or Access Agent", null=True, blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+class AgentPortMapping(PlCoreBase):
+    class Meta:
+        app_label = "cord"
+
+    access_agent = models.ForeignKey(AccessAgent, related_name='port_mappings')
+    mac = models.CharField(max_length=32, help_text="MAC Address", null=True, blank=True)
+    port = models.CharField(max_length=32, help_text="Openflow port ID", null=True, blank=True)
+
+    def __unicode__(self): return u'%s-%s-%s' % (self.access_agent.name, self.port, self.mac)
+
+
 # -------------------------------------------
 # VCPE
 # -------------------------------------------
diff --git a/xos/services/cord/templates/voltadmin.html b/xos/services/cord/templates/voltadmin.html
index e6887c5..807ab2c 100644
--- a/xos/services/cord/templates/voltadmin.html
+++ b/xos/services/cord/templates/voltadmin.html
@@ -1,6 +1,10 @@
 <div class = "row text-center">
     <div class="col-xs-12">
         <a href="/admin/cord/volttenant/">vOLT Tenants</a>
+    </div><div class="col-xs-12">
+        <a href="/admin/cord/voltdevice/">vOLT Devices</a>
+    </div><div class="col-xs-12">
+        <a href="/admin/cord/accessagent/">vOLT Access Agents</a>
     </div>
 </div>
 
diff --git a/xos/services/mcord/admin.py b/xos/services/mcord/admin.py
index b496ef7..ee19c7e 100644
--- a/xos/services/mcord/admin.py
+++ b/xos/services/mcord/admin.py
@@ -4,7 +4,7 @@
 from core.models import User
 from django import forms
 from django.contrib import admin
-from services.mcord.models import MCORDService, VBBUComponent, MCORD_KIND
+from services.mcord.models import MCORDService, VBBUComponent, VPGWCComponent, MCORD_KIND
 
 # The class to provide an admin interface on the web for the service.
 # We do only configuration here and don't change any logic because the logic
@@ -114,6 +114,55 @@
     class Meta:
         model = VBBUComponent
 
+# Class to represent the form to add and edit tenants.
+# We need to define this instead of just using an admin like we did for the
+# service because tenants vary more than services and there isn't a common form.
+# This allows us to change the python behavior for the admin form to save extra
+# fields and control defaults.
+class VPGWCComponentForm(forms.ModelForm):
+    # Defines a field for the creator of this service. It is a dropdown which
+    # is populated with all of the users.
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    # Defines a text field for the display message, it is not required.
+    display_message = forms.CharField(required=False)
+
+    def __init__(self, *args, **kwargs):
+        super(VPGWCComponentForm, self).__init__(*args, **kwargs)
+        # Set the kind field to readonly
+        self.fields['kind'].widget.attrs['readonly'] = True
+        # Define the logic for obtaining the objects for the provider_service
+        # dropdown of the tenant form.
+        self.fields[
+            'provider_service'].queryset = MCORDService.get_service_objects().all()
+        # Set the initial kind to HELLO_WORLD_KIND for this tenant.
+        self.fields['kind'].initial = MCORD_KIND
+        # If there is an instance of this model then we can set the initial
+        # form values to the existing values.
+        if self.instance:
+            self.fields['creator'].initial = self.instance.creator
+            self.fields[
+                'display_message'].initial = self.instance.display_message
+
+        # If there is not an instance then we need to set initial values.
+        if (not self.instance) or (not self.instance.pk):
+            self.fields['creator'].initial = get_request().user
+            if MCORDService.get_service_objects().exists():
+                self.fields["provider_service"].initial = MCORDService.get_service_objects().all()[0]
+
+    # This function describes what happens when the save button is pressed on
+    # the tenant form. In this case we set the values for the instance that were
+    # entered.
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.display_message = self.cleaned_data.get(
+            "display_message")
+        return super(VPGWCComponentForm, self).save(commit=commit)
+
+    class Meta:
+        model = VPGWCComponent
+
+
+
 # Define the admin form for the tenant. This uses a similar structure as the
 # service but uses HelloWorldTenantCompleteForm to change the python behavior.
 
@@ -136,6 +185,28 @@
     def queryset(self, request):
         return VBBUComponent.get_tenant_objects_by_user(request.user)
 
+
+# Define the admin form for the tenant. This uses a similar structure as the
+# service but uses HelloWorldTenantCompleteForm to change the python behavior.
+class VPGWCComponentAdmin(ReadOnlyAwareAdmin):
+    verbose_name = "vPGWC Component"
+    verbose_name_plural = "vPGWC Components"
+    list_display = ('id', 'backend_status_icon', 'instance', 'display_message')
+    list_display_links = ('backend_status_icon', 'instance', 'display_message',
+                          'id')
+    fieldsets = [(None, {'fields': ['backend_status_text', 'kind',
+                                    'provider_service', 'instance', 'creator',
+                                    'display_message'],
+                         'classes': ['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance',)
+    form = VPGWCComponentForm
+
+    suit_form_tabs = (('general', 'Details'),)
+
+    def queryset(self, request):
+        return VPGWCComponent.get_tenant_objects_by_user(request.user)
+
 # Associate the admin forms with the models.
 admin.site.register(MCORDService, MCORDServiceAdmin)
 admin.site.register(VBBUComponent, VBBUComponentAdmin)
+admin.site.register(VPGWCComponent, VPGWCComponentAdmin)
diff --git a/xos/services/mcord/models.py b/xos/services/mcord/models.py
index 1b2bd65..6d070d8 100644
--- a/xos/services/mcord/models.py
+++ b/xos/services/mcord/models.py
@@ -18,8 +18,9 @@
 MCORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
 VBBU_KIND = "RAN"
 VSGW_KIND = "vSGW"
-VPGW_KIND = "vPGW"
-net_types = ("s1u", "s1mme", "rru")
+VPGWC_KIND = "RAN"
+vbbu_net_types = ("s1u", "s1mme", "rru")
+vpgwc_net_types = ("s5s8")
 # The class to represent the service. Most of the service logic is given for us
 # in the Service class but, we have some configuration that is specific for
 # this example.
@@ -91,7 +92,7 @@
         with transaction.atomic():
             super(VBBUComponent, self).save_instance(instance)
             if instance.isolation in ["vm"]:
-                for ntype in net_types:
+                for ntype in vbbu_net_types:
                     lan_network = self.get_lan_network(instance, ntype)
                     port = self.find_or_make_port(instance,lan_network)
                     if (ntype == "s1u"):
@@ -271,6 +272,193 @@
     def rru_mac(self):
         return self.addresses.get("rru", (None, None))[1]
 
+
+# This is the class to represent the tenant. Most of the logic is given to use
+# in TenantWithContainer, however there is some configuration and logic that
+# we need to define for this example.
+class VPGWCComponent(TenantWithContainer):
+
+    class Meta:
+        # Same as a above, HelloWorldTenantComplete is represented as a
+        # TenantWithContainer, but we change the python behavior.
+        proxy = True
+        verbose_name = "VPGWC MCORD Service Component"
+
+    # The kind of the service is used on forms to differentiate this service
+    # from the other services.
+    KIND = VPGWC_KIND
+
+    # Ansible requires that the sync_attributes field contain nat_ip and nat_mac
+    # these will be used to determine where to SSH to for ansible.
+    # Getters must be defined for every attribute specified here.
+    sync_attributes = ("s5s8_pgw_ip", "s5s8_pgw_mac")
+
+    # default_attributes is used cleanly indicate what the default values for
+    # the fields are.
+    default_attributes = {"display_message": "New vPGWC Component", "s5s8_pgw_tag": "300"}
+    def __init__(self, *args, **kwargs):
+        mcord_services = MCORDService.get_service_objects().all()
+        # When the tenant is created the default service in the form is set
+        # to be the first created HelloWorldServiceComplete
+        if mcord_services:
+            self._meta.get_field(
+                "provider_service").default = mcord_services[0].id
+        super(VPGWCComponent, self).__init__(*args, **kwargs)
+
+    def can_update(self, user):
+        #Allow creation of this model instances for non-admin users also
+        return True
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a monitoring channel since it creates a slice
+                raise XOSProgrammingError("ServiceComponents's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("ServiceComponents's self.creator was not set")
+
+        super(VPGWCComponent, self).save(*args, **kwargs)
+        # This call needs to happen so that an instance is created for this
+        # tenant is created in the slice. One instance is created per tenant.
+        model_policy_mcord_servicecomponent(self.pk)
+
+    def save_instance(self, instance):
+        with transaction.atomic():
+            super(VPGWCComponent, self).save_instance(instance)
+            if instance.isolation in ["vm"]:
+                for ntype in vpgwc_net_types:
+                    lan_network = self.get_lan_network(instance, ntype)
+                    port = self.find_or_make_port(instance,lan_network)
+                    if (ntype == "s5s8"):
+                        port.set_parameter("s_tag", self.s5s8_pgw_tag)
+                        port.set_parameter("neutron_port_name", "stag-%s" % self.s5s8_pgw_tag)
+                        port.save()
+                    else:
+			return True
+
+    def delete(self, *args, **kwargs):
+        # Delete the instance that was created for this tenant
+        self.cleanup_container()
+        super(VPGWCComponent, self).delete(*args, **kwargs)
+
+    def find_or_make_port(self, instance, network, **kwargs):
+        port = Port.objects.filter(instance=instance, network=network)
+        if port:
+            port = port[0]
+            print "port already exist", port[0]
+        else:
+            port = Port(instance=instance, network=network, **kwargs)
+            print "NETWORK", network, "MAKE_PORT", port 
+            port.save()
+        return port
+
+    def get_lan_network(self, instance, ntype):
+        slice = self.provider_service.slices.all()[0]
+        lan_networks = [x for x in slice.networks.all() if ntype in x.name]
+        if not lan_networks:
+            raise XOSProgrammingError("No lan_network")
+        return lan_networks[0]
+
+    def manage_container(self):
+        from core.models import Instance, Flavor
+
+        if self.deleted:
+            return
+
+        # For container or container_vm isolation, use what TenantWithCotnainer
+        # provides us
+        slice = self.get_slice()
+        if slice.default_isolation in ["container_vm", "container"]:
+            super(VPGWCComponent,self).manage_container()
+            return
+
+        if not self.s5s8_pgw_tag:
+            raise XOSConfigurationError("S5S8_PGW_TAG is missed")
+
+        if self.instance:
+            # We're good.
+            return
+
+        instance = self.make_instance()
+        self.instance = instance
+        super(TenantWithContainer, self).save()
+
+    def get_slice(self):
+        if not self.provider_service.slices.count():
+            raise XOSConfigurationError("The service has no slices")
+        slice = self.provider_service.slices.all()[0]
+        return slice
+
+    def make_instance(self):
+        slice = self.provider_service.slices.all()[0]            
+        flavors = Flavor.objects.filter(name=slice.default_flavor)
+#        flavors = Flavor.objects.filter(name="m1.xlarge")
+        if not flavors:
+            raise XOSConfigurationError("No default flavor")
+        default_flavor = slice.default_flavor
+        slice = self.provider_service.slices.all()[0]
+        if slice.default_isolation == "container_vm":
+            (node, parent) = ContainerVmScheduler(slice).pick()
+        else:
+            (node, parent) = LeastLoadedNodeScheduler(slice).pick()
+        instance = Instance(slice = slice,
+                        node = node,
+                        image = self.image,
+                        creator = self.creator,
+                        deployment = node.site_deployment.deployment,
+                        flavor = flavors[0],
+                        isolation = slice.default_isolation,
+                        parent = parent)
+        self.save_instance(instance)
+        return instance
+
+    def ip_to_mac(self, ip):
+        (a, b, c, d) = ip.split('.')
+        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
+    # Getter for the message that will appear on the webpage
+    # By default it is "Hello World!"
+    @property
+    def display_message(self):
+        return self.get_attribute(
+            "display_message",
+            self.default_attributes['display_message'])
+
+    @display_message.setter
+    def display_message(self, value):
+        self.set_attribute("display_message", value)
+
+    @property
+    def s5s8_pgw_tag(self):
+        return self.get_attribute(
+            "s5s8_pgw_tag",
+            self.default_attributes['s5s8_pgw_tag'])
+
+    @s5s8_pgw_tag.setter
+    def s5s8_pgw_tag(self, value):
+        self.set_attribute("s5s8_pgw_tag", value)
+
+
+    @property
+    def addresses(self):
+        if (not self.id) or (not self.instance):
+            return {}
+
+        addresses = {}
+        for ns in self.instance.ports.all():
+            if "s5s8_pgw" in ns.network.name.lower():
+                addresses["s5s8_pgw"] = (ns.ip, ns.mac)
+        return addresses
+
+
+    @property
+    def s5s8_pgw_ip(self):
+        return self.addresses.get("s5s8_pgw", (None, None))[0]
+    @property
+    def s5s8_pgw_mac(self):
+        return self.addresses.get("s5s8_pgw", (None, None))[1]
+
 def model_policy_mcord_servicecomponent(pk):
     # This section of code is atomic to prevent race conditions
     with transaction.atomic():
@@ -281,3 +469,15 @@
         # Since this code is atomic it is safe to always use the first tenant
         component = component[0]
         component.manage_container()
+
+
+def model_policy_mcord_servicecomponent(pk):
+    # This section of code is atomic to prevent race conditions
+    with transaction.atomic():
+        # We find all of the tenants that are waiting to update
+        component = VPGWCComponent.objects.select_for_update().filter(pk=pk)
+        if not component:
+            return
+        # Since this code is atomic it is safe to always use the first tenant
+        component = component[0]
+        component.manage_container()
diff --git a/xos/synchronizers/base/backend.py b/xos/synchronizers/base/backend.py
index d7307fa..af51e73 100644
--- a/xos/synchronizers/base/backend.py
+++ b/xos/synchronizers/base/backend.py
@@ -7,12 +7,16 @@
 from xos.logger import Logger, logging
 from synchronizers.model_policy import run_policy
 from xos.config import Config
+from django.utils import timezone
+from diag import update_diag
 
 logger = Logger(level=logging.INFO)
 
 class Backend:
 
     def run(self):
+        update_diag(sync_start=time.time(), backend_status="0 - Synchronizer Start")
+
         # start the openstack observer
         observer = XOSObserver()
         observer_thread = threading.Thread(target=observer.run,name='synchronizer')
diff --git a/xos/synchronizers/base/diag.py b/xos/synchronizers/base/diag.py
new file mode 100644
index 0000000..87fab70
--- /dev/null
+++ b/xos/synchronizers/base/diag.py
@@ -0,0 +1,40 @@
+import os
+import time
+import sys
+import traceback
+import json
+
+from core.models import Diag
+from xos.config import Config, XOS_DIR
+from xos.logger import Logger, logging, logger
+
+logger = Logger(level=logging.INFO)
+
+def update_diag(loop_end=None, loop_start=None, syncrecord_start=None, sync_start=None, backend_status=None):
+    try:
+        observer_name = Config().observer_name
+    except:
+        observer_name = 'openstack'
+
+    try:
+        diag = Diag.objects.filter(name=observer_name).first()
+        if (not diag):
+            diag = Diag(name=observer_name)
+        br_str = diag.backend_register
+        br = json.loads(br_str)
+        if loop_end:
+            br['last_run'] = loop_end
+        if loop_end and loop_start:
+            br['last_duration'] = loop_end - loop_start
+        if syncrecord_start:
+            br['last_syncrecord_start'] = syncrecord_start
+        if sync_start:
+            br['last_synchronizer_start'] = sync_start
+        if backend_status:
+            diag.backend_status = backend_status
+        diag.backend_register = json.dumps(br)
+        diag.save()
+    except:
+        logger.log_exc("Exception in update_diag")
+        traceback.print_exc()
+
diff --git a/xos/synchronizers/base/event_loop.py b/xos/synchronizers/base/event_loop.py
index 0f23c04..ae97329 100644
--- a/xos/synchronizers/base/event_loop.py
+++ b/xos/synchronizers/base/event_loop.py
@@ -29,6 +29,8 @@
 from synchronizers.base.error_mapper import *
 from synchronizers.openstack.openstacksyncstep import OpenStackSyncStep
 from synchronizers.base.steps.sync_object import SyncObject
+from django.utils import timezone
+from diag import update_diag
 
 # Load app models
 
@@ -520,7 +522,7 @@
                                 schedule = self.ordered_steps if not deletion else reversed(self.ordered_steps)
 
                                 for S in schedule:
-                                        thread = threading.Thread(target=self.sync, args=(S, deletion))
+                                        thread = threading.Thread(target=self.sync, name='synchronizer', args=(S, deletion))
 
                                         logger.info('Deletion=%r...'%deletion)
                                         threads.append(thread)
@@ -544,20 +546,10 @@
 
                         loop_end = time.time()
 
-                        try:
-                            observer_name = Config().observer_name
-                        except:
-                            observer_name = ''
+                        update_diag(loop_end=loop_end, loop_start=loop_start, backend_status="1 - Bottom Of Loop")
 
-                        diag = Diag.objects.filter(name=observer_name).first()
-                        if (diag):
-                            br_str = diag.backend_register
-                            br = json.loads(br_str)
-                            br['last_run'] = loop_end
-                            br['last_duration'] = loop_end - loop_start
-                            diag.backend_register = json.dumps(br)
-                            diag.save() 
                 except Exception, e:
                         logger.error('Core error. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % e)
                         logger.log_exc("Exception in observer run loop")
                         traceback.print_exc()
+                        update_diag(backend_status="2 - Exception in Event Loop")
diff --git a/xos/synchronizers/base/syncstep.py b/xos/synchronizers/base/syncstep.py
index 3ddf75e..eeb61db 100644
--- a/xos/synchronizers/base/syncstep.py
+++ b/xos/synchronizers/base/syncstep.py
@@ -10,8 +10,8 @@
 from django.db import reset_queries
 from synchronizers.base.ansible import *
 from generate.dependency_walker import *
+from diag import update_diag
 
-from time import time
 import json
 import time
 import pdb
@@ -238,9 +238,11 @@
 
                         self.sync_record(o)
 
-                        if (not run_always):
-                            o.enacted = new_enacted
+#                         if (not run_always):
+#                             o.enacted = new_enacted
 
+                        update_diag(syncrecord_start = time.time(), backend_status="1 - Synced Record")
+                        o.enacted = new_enacted
                         scratchpad = {'next_run':0, 'exponent':0, 'last_success':time.time()}
                         o.backend_register = json.dumps(scratchpad)
                         o.backend_status = "1 - OK"
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
index 1c4da12..ca72c5f 100644
--- a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
+++ b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
@@ -66,13 +66,21 @@
 #      dest=/etc/resolv.conf
 {% endif %}
 
+# FIXME: Temporary workaround to delete the monitoring-channel_ceilometer_proxy_config file always 
+# to trigger ansible notify handlers in the following task. 
+# Due to some issue, ansible "changed" flag is set to false even though there is a change of 
+# ceilometer configuration file, because of which the configuration change is not reflecting in 
+# ceilometer containers 
+#  - file: path=/usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config state=absent
+
   - name: ceilometer proxy config
     template: src=/opt/xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_config.j2 dest=/usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config mode=0777
     notify:
-#    - restart monitoring-channel
-     - stop monitoring-channel
-     - remove container
-     - start monitoring-channel
+     - copy ceilo-config-file
+     - restart monitoring-channel container
+#     - stop monitoring-channel
+#     - remove container
+#     - start monitoring-channel
 
   - name: Monitoring channel upstart
     template: src=/opt/xos/synchronizers/monitoring_channel/templates/monitoring-channel.conf.j2 dest=/etc/init/monitoring-channel-{{ unique_id }}.conf
@@ -118,6 +126,12 @@
 {% endif %}
 
   handlers:
+  - name: copy ceilo-config-file
+    shell: docker cp /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config monitoring-channel-{{ unique_id }}:/usr/local/share/ceilometer_proxy_config
+
+  - name: restart monitoring-channel container
+    shell: docker restart monitoring-channel-{{ unique_id }}
+
   - name: restart monitoring-channel
     shell: service monitoring-channel-{{ unique_id }} stop; sleep 1; service monitoring-channel-{{ unique_id }} start
 
diff --git a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2 b/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
index 1685e07..4486985 100755
--- a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
+++ b/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
@@ -24,9 +24,11 @@
     #sudo docker pull srikanthvavila/monitoring-channel
 if [ -z "$HEADNODEFLATLANIP" ] || [ "$HEADNODEFLATLANIP" == "None" ]
 then
-    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+#    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
 else
-    docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+#    docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+    docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
 fi
 else
     docker start $MONITORING_CHANNEL
@@ -41,6 +43,7 @@
 
 # Now copy ceilometer proxy configuration to container
 #cat /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config | sudo docker exec -i $MONITORING_CHANNEL bash -c 'cat > /usr/local/share/ceilometer_proxy_config'
+docker cp /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config $MONITORING_CHANNEL:/usr/local/share/ceilometer_proxy_config
 
 # Attach to container
-#docker start -a $MONITORING_CHANNEL
+docker start -a $MONITORING_CHANNEL
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.py b/xos/synchronizers/onos/steps/sync_onosapp.py
index 64c9452..3a9abfc 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.py
+++ b/xos/synchronizers/onos/steps/sync_onosapp.py
@@ -18,6 +18,7 @@
 from xos.logger import Logger, logging
 from services.vrouter.models import VRouterService
 from services.vtn.models import VTNService
+from services.cord.models import VOLTService, VOLTDevice, AccessDevice
 
 # hpclibrary will be in steps/..
 parentdir = os.path.join(os.path.dirname(__file__),"..")
@@ -243,18 +244,44 @@
         return json.dumps(data, indent=4, sort_keys=True)
 
     def get_volt_network_config(self, o, attrs):
-        data = {
-            "devices" : {
-                "of:1000000000000001" : {
-                    "accessDevice" : {
-                        "uplink" : "2",
-                        "vlan"   : "222",
-                    },
-                    "basic" : {
-                        "driver" : "pmc-olt"
-                    }
+        try:
+            volt = VOLTService.get_service_objects().all()[0]
+        except:
+            return None
+
+        devices = []
+        for voltdev in volt.volt_devices.all():
+            access_devices = []
+            for access in voltdev.access_devices.all():
+                access_device = {
+                    "uplink" : access.uplink,
+                    "vlan" : access.vlan
+                }
+                access_devices.append(access_device)
+
+            if voltdev.access_agent:
+                agent = voltdev.access_agent
+                olts = {}
+                for port_mapping in agent.port_mappings.all():
+                    olts[port_mapping.port] = port_mapping.mac
+                agent_config = {
+                    "olts" : olts,
+                    "mac" : agent.mac
+                }
+
+            device = {
+                voltdev.openflow_id : {
+                    "accessDevice" : access_devices,
+                    "accessAgent" : agent_config
+                },
+                "basic" : {
+                    "driver" : voltdev.driver
                 }
             }
+            devices.append(device)
+
+        data = {
+            "devices" : devices
         }
         return json.dumps(data, indent=4, sort_keys=True)
 
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
index 9e3dfac..d8bc525 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
@@ -130,11 +130,9 @@
         else:
             logger.info("neither bbs_slice nor bbs_server is configured in the vCPE",extra=o.tologdict())
 
-        vlan_ids = []
         s_tags = []
         c_tags = []
         if o.volt:
-            vlan_ids.append(o.volt.vlan_id)  # XXX remove this
             s_tags.append(o.volt.s_tag)
             c_tags.append(o.volt.c_tag)
 
@@ -146,15 +144,14 @@
         safe_macs=[]
         if vcpe_service.url_filter_kind == "safebrowsing":
             if o.volt and o.volt.subscriber:
-                for user in o.volt.subscriber.users:
+                for user in o.volt.subscriber.devices:
                     level = user.get("level",None)
                     mac = user.get("mac",None)
                     if level in ["G", "PG"]:
                         if mac:
                             safe_macs.append(mac)
 
-        fields = {"vlan_ids": vlan_ids,   # XXX remove this
-                "s_tags": s_tags,
+        fields = {"s_tags": s_tags,
                 "c_tags": c_tags,
                 "dnsdemux_ip": dnsdemux_ip,
                 "cdn_prefixes": cdn_prefixes,
@@ -199,7 +196,7 @@
         if o.volt and o.volt.subscriber:
             url_filter_enable = o.volt.subscriber.url_filter_enable
             url_filter_level = o.volt.subscriber.url_filter_level
-            url_filter_users = o.volt.subscriber.users
+            url_filter_users = o.volt.subscriber.devices
 
         if service.url_filter_kind == "broadbandshield":
             # disable url_filter if there are no bbs_addrs
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
index 3823328..9be0f98 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
@@ -9,10 +9,6 @@
       dnsdemux_ip: {{ dnsdemux_ip }}
       firewall_enable: {{ firewall_enable }}
       url_filter_enable: {{ url_filter_enable }}
-      vlan_ids:
-        {% for vlan_id in vlan_ids %}
-        - {{ vlan_id }}
-        {% endfor %}
       c_tags:
         {% for c_tag in c_tags %}
         - {{ c_tag }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
index 324e274..435b721 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
@@ -10,10 +10,6 @@
       dnsdemux_ip: {{ dnsdemux_ip }}
       firewall_enable: {{ firewall_enable }}
       url_filter_enable: {{ url_filter_enable }}
-      vlan_ids:
-        {% for vlan_id in vlan_ids %}
-        - {{ vlan_id }}
-        {% endfor %}
       c_tags:
         {% for c_tag in c_tags %}
         - {{ c_tag }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
index 09e4d23..b24d15a 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
@@ -10,10 +10,6 @@
       dnsdemux_ip: {{ dnsdemux_ip }}
       firewall_enable: {{ firewall_enable }}
       url_filter_enable: {{ url_filter_enable }}
-      vlan_ids:
-        {% for vlan_id in vlan_ids %}
-        - {{ vlan_id }}
-        {% endfor %}
       c_tags:
         {% for c_tag in c_tags %}
         - {{ c_tag }}
diff --git a/xos/synchronizers/vcpe/templates/vlan_sample.j2 b/xos/synchronizers/vcpe/templates/vlan_sample.j2
index a26c840..b73954b 100644
--- a/xos/synchronizers/vcpe/templates/vlan_sample.j2
+++ b/xos/synchronizers/vcpe/templates/vlan_sample.j2
@@ -1,5 +1,5 @@
 # below is a list of all vlan_ids associated with this vcpe
 
-{% for vlan_id in vlan_ids %}
+{% for vlan_id in c_tags %}
 {{ vlan_id }}
 {% endfor %}
diff --git a/xos/synchronizers/vpgwc/__init__.py b/xos/synchronizers/vpgwc/__init__.py
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/xos/synchronizers/vpgwc/__init__.py
diff --git a/xos/synchronizers/vpgwc/model-deps b/xos/synchronizers/vpgwc/model-deps
new file mode 100755
index 0000000..0967ef4
--- /dev/null
+++ b/xos/synchronizers/vpgwc/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/synchronizers/vpgwc/run.sh b/xos/synchronizers/vpgwc/run.sh
new file mode 100755
index 0000000..821e149
--- /dev/null
+++ b/xos/synchronizers/vpgwc/run.sh
@@ -0,0 +1,3 @@
+# Runs the XOS observer using helloworldservice_config
+export XOS_DIR=/opt/xos
+python vpgwc-synchronizer.py  -C $XOS_DIR/synchronizers/vpgwc/vpgwc_config
diff --git a/xos/synchronizers/vpgwc/steps/sync_vpgwc.py b/xos/synchronizers/vpgwc/steps/sync_vpgwc.py
new file mode 100644
index 0000000..446a521
--- /dev/null
+++ b/xos/synchronizers/vpgwc/steps/sync_vpgwc.py
@@ -0,0 +1,37 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.mcord.models import MCORDService, VPGWCComponent
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVPGWCComponent(SyncInstanceUsingAnsible):
+
+    provides = [VPGWCComponent]
+
+    observes = VPGWCComponent
+
+    requested_interval = 0
+
+    template_name = "sync_vpgwc.yaml"
+
+    service_key_name = "/opt/xos/configurations/mcord/mcord_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVPGWCComponent, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = VPGWCComponent.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+
+            objs = VPGWCComponent.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_extra_attributes(self, o):
+        return {"display_message": o.display_message, "s5s8_pgw_tag": o.s5s8_pgw_tag}
diff --git a/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml b/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml
new file mode 100644
index 0000000..a793976
--- /dev/null
+++ b/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml
@@ -0,0 +1,13 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  tasks:
+
+  - name: write message
+    shell: echo "{{ display_message }}" > /var/tmp/index.html
+
+  - name: setup s5s8_pgw interface config
+    shell: ./start_3gpp_int.sh eth1 {{ s5s8_pgw_tag }} {{ s5s8_pgw_ip }}/24 
diff --git a/xos/synchronizers/vpgwc/stop.sh b/xos/synchronizers/vpgwc/stop.sh
new file mode 100755
index 0000000..299641a
--- /dev/null
+++ b/xos/synchronizers/vpgwc/stop.sh
@@ -0,0 +1,2 @@
+# Kill the observer
+pkill -9 -f vpgwc-synchronizer.py
diff --git a/xos/synchronizers/vpgwc/vpgwc-synchronizer.py b/xos/synchronizers/vpgwc/vpgwc-synchronizer.py
new file mode 100755
index 0000000..95f4081
--- /dev/null
+++ b/xos/synchronizers/vpgwc/vpgwc-synchronizer.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+# Runs the standard XOS observer
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(
+    os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/vpgwc/vpgwc_config b/xos/synchronizers/vpgwc/vpgwc_config
new file mode 100755
index 0000000..c6b9c23
--- /dev/null
+++ b/xos/synchronizers/vpgwc/vpgwc_config
@@ -0,0 +1,40 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the observer
+[observer]
+# Optional name
+name=vpgwc
+# This is the location to the dependency graph you generate
+dependency_graph=/opt/xos/synchronizers/vpgwc/model-deps
+# The location of your SyncSteps
+steps_dir=/opt/xos/synchronizers/vpgwc/steps
+# A temporary directory that will be used by ansible
+sys_dir=/opt/xos/synchronizers/vpgwc/sys
+# Location of the file to save logging messages to the backend log is often used
+logfile=/var/log/xos_backend.log
+# If this option is true, then nothing will change, we simply pretend to run
+pretend=False
+# If this is False then XOS will use an exponential backoff when the observer
+# fails, since we will be waiting for an instance, we don't want this.
+backoff_disabled=True
+# We want the output from ansible to be logged
+save_ansible_output=True
+# This determines how we SSH to a client, if this is set to True then we try
+# to ssh using the instance name as a proxy, if this is disabled we ssh using
+# the NAT IP of the instance. On CloudLab the first option will fail so we must
+# set this to False
+proxy_ssh=True
+proxy_ssh_key=/root/setup/id_rsa
+proxy_ssh_user=root
+[networking]
+use_vtn=True
diff --git a/xos/templates/admin/base.html b/xos/templates/admin/base.html
index ba01201..408a1e8 100644
--- a/xos/templates/admin/base.html
+++ b/xos/templates/admin/base.html
@@ -1,4 +1,4 @@
-{% load admin_static %}{% load suit_tags %}{% load url from future %}
+{% load admin_static %}{% load suit_tags core_tags %}{% load url from future %}
 <!DOCTYPE html>
 <html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
 <head>
@@ -148,6 +148,7 @@
                     {% endblock %}
 
                     {% if user.is_active and user.is_staff %}
+                    {% notification %}
                       <div id="user-tools">
                         {% trans 'Welcome,' %}
                         <a href="http://{{ request.get_host}}/admin/core/user/{{user.id}}">{{user.email}}</a>
diff --git a/xos/templates/admin/tags/notification.html b/xos/templates/admin/tags/notification.html
new file mode 100644
index 0000000..558b9ff
--- /dev/null
+++ b/xos/templates/admin/tags/notification.html
@@ -0,0 +1 @@
+{{template | safe}}
\ No newline at end of file
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 4af9050..9497b6d 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -408,6 +408,16 @@
                 required: true
                 description: MAC address for this device.
 
+    tosca.nodes.VOLTService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vOLT Service
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
     tosca.nodes.VOLTTenant:
         derived_from: tosca.nodes.Root
         description: >
@@ -424,6 +434,58 @@
                 required: false
                 description: c_tag, identifies which subscriber within s_tag
 
+    tosca.nodes.VOLTDevice:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Device.
+        properties:
+            xos_base_props
+            openflow_id:
+                type: string
+                required: false
+                description: openflow id
+            driver:
+                type: string
+                required: false
+                description: driver name
+            access_devices:
+                type: string
+                required: false
+                description: list of access devices, in format "uplink vlan", multiple entries separated by commas
+
+# XXX - uncomment if we want access device to be specified as separate Tosca
+# objects, rather than encoding them into VOLTDevice.access_devices
+#    tosca.nodes.AccessDevice:
+#        derived_from: tosca.nodes.Root
+#        description: >
+#            CORD: A vOLT Access Device.
+#        properties:
+#            xos_base_props
+#            uplink:
+#               type: integer
+#               required: false
+#               description: uplink
+#            vlan:
+#               type: integer
+#               required: false
+#               description: vlan
+
+    tosca.nodes.AccessAgent:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Access Agent.
+        properties:
+            xos_base_props
+            mac:
+                type: string
+                required: false
+                description: mac address
+            port_mappings:
+                type: string
+                required: false
+                description: list of port mappings, in format "port mac", multiple entries separated by commas
+
+
     tosca.nodes.User:
         derived_from: tosca.nodes.Root
 
@@ -1066,9 +1128,9 @@
         derived_from: tosca.relationships.Root
 
     tosca.relationships.MemberOfDevice:
-        derived_from: tosca.relationships.Root

-

-    tosca.relationships.UsesAgent:

+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsesAgent:
         derived_from: tosca.relationships.Root
 
     tosca.relationships.HasResource:
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index aacc2a2..66229d5 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -925,6 +925,64 @@
                 required: true
                 description: MAC address for this device.
 
+    tosca.nodes.VOLTService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vOLT Service
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+
     tosca.nodes.VOLTTenant:
         derived_from: tosca.nodes.Root
         description: >
@@ -948,6 +1006,88 @@
                 required: false
                 description: c_tag, identifies which subscriber within s_tag
 
+    tosca.nodes.VOLTDevice:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Device.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            openflow_id:
+                type: string
+                required: false
+                description: openflow id
+            driver:
+                type: string
+                required: false
+                description: driver name
+            access_devices:
+                type: string
+                required: false
+                description: list of access devices, in format "uplink vlan", multiple entries separated by commas
+
+# XXX - uncomment if we want access device to be specified as separate Tosca
+# objects, rather than encoding them into VOLTDevice.access_devices
+#    tosca.nodes.AccessDevice:
+#        derived_from: tosca.nodes.Root
+#        description: >
+#            CORD: A vOLT Access Device.
+#        properties:
+#            xos_base_props
+#            uplink:
+#               type: integer
+#               required: false
+#               description: uplink
+#            vlan:
+#               type: integer
+#               required: false
+#               description: vlan
+
+    tosca.nodes.AccessAgent:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: A vOLT Access Agent.
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            mac:
+                type: string
+                required: false
+                description: mac address
+            port_mappings:
+                type: string
+                required: false
+                description: list of port mappings, in format "port mac", multiple entries separated by commas
+
+
     tosca.nodes.User:
         derived_from: tosca.nodes.Root
 
@@ -1875,9 +2015,9 @@
         derived_from: tosca.relationships.Root
 
     tosca.relationships.MemberOfDevice:
-        derived_from: tosca.relationships.Root

-

-    tosca.relationships.UsesAgent:

+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsesAgent:
         derived_from: tosca.relationships.Root
 
     tosca.relationships.HasResource:
diff --git a/xos/tosca/resources/accessagent.py b/xos/tosca/resources/accessagent.py
new file mode 100644
index 0000000..368ce55
--- /dev/null
+++ b/xos/tosca/resources/accessagent.py
@@ -0,0 +1,56 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import AccessAgent, VOLTDevice, VOLTService, AgentPortMapping
+from xosresource import XOSResource
+
+class XOSAccessAgent(XOSResource):
+    provides = "tosca.nodes.AccessAgent"
+    xos_model = AccessAgent
+    copyin_props = ["mac"]
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSAccessAgent, self).get_xos_args()
+
+        volt_service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if volt_service_name:
+            args["volt_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=volt_service_name)
+
+        return args
+
+    def postprocess(self, obj):
+        # For convenient, allow the port mappings to be specified by a Tosca
+        # string with commas between lines.
+        #      <port> <mac>,
+        #      <port> <mac>,
+        #      ...
+        #      <port> <mac>
+
+        port_mappings_str = self.get_property("port_mappings")
+        port_mappings = []
+        if port_mappings_str:
+            lines = [x.strip() for x in port_mappings_str.split(",")]
+            for line in lines:
+                if not (" " in line):
+                    raise "Malformed port mapping `%s`", line
+                (port, mac) = line.split(" ")
+                port=port.strip()
+                mac=mac.strip()
+                port_mappings.append( (port, mac) )
+
+            for apm in list(AgentPortMapping.objects.filter(access_agent=obj)):
+                if (apm.port, apm.mac) not in port_mappings:
+                    print "Deleting AgentPortMapping '%s'" % apm
+                    apm.delete()
+
+            for port_mapping in port_mappings:
+                existing_objs = AgentPortMapping.objects.filter(access_agent=obj, port=port_mapping[0], mac=port_mapping[1])
+                if not existing_objs:
+                    apm = AgentPortMapping(access_agent=obj, port=port_mapping[0], mac=port_mapping[1])
+                    apm.save()
+                    print "Created AgentPortMapping '%s'" % apm
+
diff --git a/xos/tosca/resources/accessdevice.py b/xos/tosca/resources/accessdevice.py
new file mode 100644
index 0000000..94deb86
--- /dev/null
+++ b/xos/tosca/resources/accessdevice.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import AccessDevice, VOLTDevice
+from xosresource import XOSResource
+
+class XOSAccessDevice(XOSResource):
+    provides = "tosca.nodes.AccessDevice"
+    xos_model = AccessDevice
+    copyin_props = ["uplink", "vlan"]
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSAccessDevice, self).get_xos_args()
+
+        volt_device_name = self.get_requirement("tosca.relationships.MemberOfDevice", throw_exception=throw_exception)
+        if volt_device_name:
+            args["volt_device"] = self.get_xos_object(VOLTDevice, throw_exception=throw_exception, name=volt_device_name)
+
+        return args
+
+    # AccessDevice has no name field, so we rely on matching the keys. We assume
+    # the for a given VOLTDevice, there is only one AccessDevice per (uplink, vlan)
+    # pair.
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        volt_device = args.get("volt_device", None)
+        uplink = args.get("uplink", None)
+        vlan = args.get("vlan", None)
+        if (volt_device is not None) and (uplink is not None) and (vlan is not None):
+            existing_obj = self.get_xos_object(AccessDevice, volt_device=volt_device, uplink=uplink, vlan=vlan, throw_exception=False)
+            if existing_obj:
+                return [ existing_obj ]
+        return []
+
diff --git a/xos/tosca/resources/voltdevice.py b/xos/tosca/resources/voltdevice.py
new file mode 100644
index 0000000..f1c6830
--- /dev/null
+++ b/xos/tosca/resources/voltdevice.py
@@ -0,0 +1,52 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import VOLTDevice, VOLTService, AccessDevice, AccessAgent
+from xosresource import XOSResource
+
+class XOSVOLTDevice(XOSResource):
+    provides = "tosca.nodes.VOLTDevice"
+    xos_model = VOLTDevice
+    copyin_props = ["openflow_id", "driver"]
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVOLTDevice, self).get_xos_args()
+
+        volt_service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if volt_service_name:
+            args["volt_service"] = self.get_xos_object(VOLTService, throw_exception=throw_exception, name=volt_service_name)
+
+        agent_name = self.get_requirement("tosca.relationships.UsesAgent", throw_exception=throw_exception)
+        if agent_name:
+            args["access_agent"] = self.get_xos_object(AccessAgent, throw_exception=throw_exception, name=agent_name)
+
+        return args
+
+    def postprocess(self, obj):
+        access_devices_str = self.get_property("access_devices")
+        access_devices = []
+        if access_devices_str:
+            lines = [x.strip() for x in access_devices_str.split(",")]
+            for line in lines:
+                if not (" " in line):
+                    raise "Malformed access device `%s`", line
+                (uplink, vlan) = line.split(" ")
+                uplink=int(uplink.strip())
+                vlan=int(vlan.strip())
+                access_devices.append( (uplink, vlan) )
+
+            for ad in list(AccessDevice.objects.filter(volt_device=obj)):
+                if (ad.uplink, ad.vlan) not in access_devices:
+                    print "Deleting AccessDevice '%s'" % ad
+                    ad.delete()
+
+            for access_device in access_devices:
+                existing_objs = AccessDevice.objects.filter(volt_device=obj, uplink=access_device[0], vlan=access_device[1])
+                if not existing_objs:
+                    ad = AccessDevice(volt_device=obj, uplink=access_device[0], vlan=access_device[1])
+                    ad.save()
+                    print "Created AccessDevice '%s'" % ad
diff --git a/xos/tosca/resources/voltservice.py b/xos/tosca/resources/voltservice.py
new file mode 100644
index 0000000..57cf846
--- /dev/null
+++ b/xos/tosca/resources/voltservice.py
@@ -0,0 +1,15 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.cord.models import VOLTService
+
+from service import XOSService
+
+class XOSVOLTService(XOSService):
+    provides = "tosca.nodes.VOLTService"
+    xos_model = VOLTService
+    copyin_props = ["view_url", "icon_url", "kind", "enabled", "published", "public_key", "private_key_fn", "versionNumber"]
diff --git a/xos/tosca/resources/vpgwccomponent.py b/xos/tosca/resources/vpgwccomponent.py
new file mode 100644
index 0000000..3b87111
--- /dev/null
+++ b/xos/tosca/resources/vpgwccomponent.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.mcord.models import VPGWCComponent, MCORDService
+
+from xosresource import XOSResource
+
+class XOSVPGWCComponent(XOSResource):
+    provides = "tosca.nodes.VPGWCComponent"
+    xos_model = VPGWCComponent
+    copyin_props = ["s5s8_pgw_tag", "display_message"]
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVPGWCComponent, self).get_xos_args()
+
+        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(MCORDService, throw_exception=throw_exception, name=provider_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_service = args.get("provider", None)
+        if provider_service:
+            return [ self.get_xos_object(provider_service=provider_service) ]
+        return []
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSVPGWCComponent, self).can_delete(obj)
+
diff --git a/xos/tosca/run.py b/xos/tosca/run.py
old mode 100644
new mode 100755