Delete nemo-impl updateLanguage and nemo-ui files 36/31336/1
authorsaomenmen <zhangmroy@163.com>
Tue, 15 Dec 2015 02:19:58 +0000 (10:19 +0800)
committersaomenmen <zhangmroy@163.com>
Tue, 15 Dec 2015 02:21:10 +0000 (10:21 +0800)
Change-Id: I3a81084ff84d6a70633ccd2c4b6cc2917e365d8f
Signed-off-by: saomenmen <zhangmroy@163.com>
40 files changed:
nemo-impl/src/test/java/org/opendaylight/nemo/user/vnspacemanager/languagestyle/updateintentlang/LanguageIntentTest.java [deleted file]
nemo-ui/src/main/resources/nemo/css/AQ.css [deleted file]
nemo-ui/src/main/resources/nemo/css/NE.css [deleted file]
nemo-ui/src/main/resources/nemo/css/RR.css [deleted file]
nemo-ui/src/main/resources/nemo/css/SI.css [deleted file]
nemo-ui/src/main/resources/nemo/css/SP.css [deleted file]
nemo-ui/src/main/resources/nemo/css/jquery-ui.min.css [deleted file]
nemo-ui/src/main/resources/nemo/css/nemo_main.css [deleted file]
nemo-ui/src/main/resources/nemo/css/register.css [deleted file]
nemo-ui/src/main/resources/nemo/images/alert.png [deleted file]
nemo-ui/src/main/resources/nemo/images/error.png [deleted file]
nemo-ui/src/main/resources/nemo/images/host.png [deleted file]
nemo-ui/src/main/resources/nemo/images/null.gif [deleted file]
nemo-ui/src/main/resources/nemo/images/ok.png [deleted file]
nemo-ui/src/main/resources/nemo/images/shut.png [deleted file]
nemo-ui/src/main/resources/nemo/images/view_desc_2.png [deleted file]
nemo-ui/src/main/resources/nemo/js/EI_tranjson.js [deleted file]
nemo-ui/src/main/resources/nemo/js/Nemo_Annouce_vis.js [deleted file]
nemo-ui/src/main/resources/nemo/js/Nemo_Main.js [deleted file]
nemo-ui/src/main/resources/nemo/js/Nemo_Order.js [deleted file]
nemo-ui/src/main/resources/nemo/js/Network_Entity.js [deleted file]
nemo-ui/src/main/resources/nemo/js/Service_Instance.js [deleted file]
nemo-ui/src/main/resources/nemo/js/Service_Policy.js [deleted file]
nemo-ui/src/main/resources/nemo/js/Service_views_main.js [deleted file]
nemo-ui/src/main/resources/nemo/js/analyjson.js [deleted file]
nemo-ui/src/main/resources/nemo/js/analyjson2.js [deleted file]
nemo-ui/src/main/resources/nemo/js/jquery-1.7.1.min.js [deleted file]
nemo-ui/src/main/resources/nemo/js/jquery-ui.min.js [deleted file]
nemo-ui/src/main/resources/nemo/js/jquery.shCircleLoader-min.js [deleted file]
nemo-ui/src/main/resources/nemo/js/scrollrun.js [deleted file]
nemo-ui/src/main/resources/nemo/js/submit.js [deleted file]
nemo-ui/src/main/resources/nemo/js/submit2.js [deleted file]
nemo-ui/src/main/resources/nemo/js/topo_data.js [deleted file]
nemo-ui/src/main/resources/nemo/js/vis.js [deleted file]
nemo-ui/src/main/resources/nemo/nemo.controller.js [deleted file]
nemo-ui/src/main/resources/nemo/nemo.directives.js [deleted file]
nemo-ui/src/main/resources/nemo/nemo.module.js [deleted file]
nemo-ui/src/main/resources/nemo/nemo.services.js [deleted file]
nemo-ui/src/main/resources/nemo/nemo.tpl.html [deleted file]
nemo-ui/src/main/resources/nemo/register.html [deleted file]

diff --git a/nemo-impl/src/test/java/org/opendaylight/nemo/user/vnspacemanager/languagestyle/updateintentlang/LanguageIntentTest.java b/nemo-impl/src/test/java/org/opendaylight/nemo/user/vnspacemanager/languagestyle/updateintentlang/LanguageIntentTest.java
deleted file mode 100644 (file)
index a098cc4..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.opendaylight.nemo.user.vnspacemanager.languagestyle;
-
-import org.opendaylight.nemo.user.vnspacemanager.languagestyle.LanguageIntent;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.nemo.user.tenantmanager.AAA;
-import org.opendaylight.nemo.user.tenantmanager.TenantManage;
-import org.opendaylight.nemo.user.vnspacemanager.languagestyle.NEMOParse.NEMOparser;
-import org.opendaylight.nemo.user.vnspacemanager.languagestyle.NEMOParse.ParseException;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.UserId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.LanguageStyleNemoRequestInput;
-
-import java.io.StringReader;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Created by ldzd11 on 2015/12/14.
- */
-public class LanguageIntentTest {
-
-    private LanguageIntent languageIntent;
-    private DataBroker dataBroker;
-    private TenantManage tenantManage;
-    private NEMOparser nemOparser;
-    private AAA aaa;
-    private UserId userId;
-   // private  NemoStatement nemoStatement;
-    private LanguageStyleNemoRequestInput languageStyleNemoRequestInput;
-    private String errorInfo;
-
-    @org.junit.Before
-    public void setUp() throws Exception {
-        userId = mock(UserId.class);
-       // nemoStatement = mock(NemoStatement.class);
-        dataBroker = mock(DataBroker.class);
-        tenantManage = mock(TenantManage.class);
-        languageStyleNemoRequestInput = mock(LanguageStyleNemoRequestInput.class);
-        aaa = mock(AAA.class);
-       // nemOparser = new NEMOparser(new StringReader(""));
-        errorInfo = new String();
-        languageIntent = new LanguageIntent(dataBroker,tenantManage);
-
-    }
-
-    @org.junit.Test
-    public void testLanIntentHandler() throws Exception {
-        when(languageStyleNemoRequestInput.getUserId()).thenReturn(userId);
-        when(languageStyleNemoRequestInput.getNemoStatement()).thenReturn(new String("test"));
-        when(aaa.checkUser(languageStyleNemoRequestInput.getUserId())).thenReturn(null);
-        try{
-            Assert.assertEquals(languageIntent.LanIntentHandler(aaa, languageStyleNemoRequestInput),nemOparser.parseNEMO(languageStyleNemoRequestInput.getUserId(),languageStyleNemoRequestInput.getNemoStatement(),dataBroker,tenantManage));
-        }
-        catch(ParseException e){
-        }
-
-        when(aaa.checkUser(languageStyleNemoRequestInput.getUserId())).thenReturn(errorInfo);
-        try{
-            Assert.assertEquals(languageIntent.LanIntentHandler(aaa, languageStyleNemoRequestInput),errorInfo);
-        }
-        catch(ParseException e){
-        }
-    }
-}
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/css/AQ.css b/nemo-ui/src/main/resources/nemo/css/AQ.css
deleted file mode 100644 (file)
index 8a3a8d4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-.AQ_up h3 {\r
-  color: black;\r
-  font-size: 18px;\r
-}
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/css/NE.css b/nemo-ui/src/main/resources/nemo/css/NE.css
deleted file mode 100644 (file)
index 0c942d5..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-.NE_up, .NE_middle, .NE_down\r
-{\r
-    margin-left:2px;\r
-}\r
-.NE_up\r
-{\r
-    position:relative;\r
-    /*border:2px solid green;*/\r
-    width:357px;\r
-    height:140px;\r
-}\r
-.up_group1\r
-{   margin-left:0px;\r
-    /*border:2px solid green;*/\r
-    width:350px;\r
-       /*meng*/\r
-    height:53px;\r
-       margin-top:20px;\r
-}\r
-.up_group1_2\r
-{\r
-    margin-left:0px;\r
-    /*border:2px solid green;*/\r
-    width:350px;\r
-       /*meng*/\r
-    height:53px;\r
-       margin-top:35px;\r
-}\r
-.up_group1 h3\r
-{   \r
-    color:black;\r
-    font-size:18px;\r
-}\r
-.up_group1>select\r
-{  \r
-    width:348px;\r
-    height:25px;\r
-    margin-right:0px;\r
-    margin-top:1px;\r
-       top:0px;\r
-}\r
-/* #sel_1\r
-{\r
-    position:absolute;\r
-    top:0px;\r
-    right:18px;\r
-} */\r
-#sel_2{\r
-    width:220px;\r
-}\r
-\r
-#NE_Edit\r
-{\r
-   position:absolute;\r
-    top:106px;\r
-    right:68px;\r
-    width:60px;\r
-    height:25px;\r
-    background-color:#939;\r
-}\r
-#NE_Delete\r
-{\r
-    position:absolute;\r
-    top:106px;\r
-    right:5px;\r
-    width:60px;\r
-    height:25px;\r
-    background-color:#939;\r
-}\r
-#up_down\r
-{\r
-     margin-left:0px;\r
-    /*border:2px solid green;*/\r
-    position:absolute;\r
-    top:140px;\r
-    left:0px;\r
-    width:357px;\r
-    height:25px;\r
-}\r
-    #up_down select\r
-    {\r
-        width:280px;\r
-        height:25px;\r
-   }\r
-    #up_down input\r
-    {\r
-    width:65px;\r
-    height:25px;\r
-    background-color:#939;\r
-       margin-left:-4px;\r
-    }\r
-\r
-       \r
-.NE_middle\r
-{\r
-    /*border:2px solid green;*/\r
-\r
-    width:360px;\r
-    height:140px;\r
-}\r
-.NE_middle *{margin-left:4px;}\r
-   \r
-   \r
-   .NE_middle input\r
-    {\r
-    width:345px;\r
-    height:25px;\r
-    }\r
-  .NE_middle select\r
-    {\r
-    width:348px;\r
-    height:25px;\r
-    }\r
-\r
-.NE_down\r
-{\r
-    /*border:2px solid green;*/\r
-    width:360px;\r
-    height:50px;\r
-}\r
-.NE_down *{margin-left:4px;}\r
-    .NE_down select\r
-    {\r
-        width:120px;\r
-        height:25px;\r
-    }\r
-    .NE_down input\r
-    {\r
-        width:120px;\r
-        height:20px;\r
-    }\r
-\r
-   .NE_down .NE_save\r
-    {\r
-       float:right;\r
-    width:100px;\r
-    height:25px;\r
-    background-color:#399;\r
-       right:-7px;\r
-       margin:20px;\r
-       margin-right:4px;\r
-    margin-bottom: 35px;\r
-    }\r
-.NE_close_show\r
-{\r
-   position:absolute;\r
-    right:4px;\r
-    top:0px;\r
-    width:20px;\r
-    height:20px;\r
-}\r
-\r
-\r
-.NE_down .txt\r
-    {\r
-    width:345px;\r
-    height:25px;\r
-       margin-left:0px;\r
-    }\r
-       \r
-.property_type .txt\r
-{\r
-    width:300px;\r
-    height:25px;\r
-}\r
-.NE_down .sel\r
-    {\r
-    width:140px;\r
-    height:25px;\r
-       margin-left:0px;\r
-       width:348px;\r
-    }\r
-#host_type\r
-{\r
-    padding-left:0px;\r
-    width:360px;\r
-    height:180px;  \r
-}\r
-#firewall_type\r
-{\r
-    display:none;\r
-    padding-left:0px;\r
-    width:360px;\r
-    height:130px;  \r
-}\r
-#forwarding_type,#internet_type,#loadBalance_type\r
-{\r
-    display:none;\r
-    padding-left:0px;\r
-    width:360px;\r
-    /*height:80px;*/ \r
-       height:130px;\r
-}\r
-.NE_Add_show\r
-{\r
-    display:none;\r
-    position:absolute;\r
-       top:250px;\r
-       margin-left:-4px;\r
-}\r
-\r
-\r
-\r
-\r
-\r
-.NE_conn_show\r
-{\r
-    position:absolute;\r
-    display:none;\r
-    font-size:16px;\r
-    margin-left:-6px;\r
-    /*border:2px solid green;*/\r
-    width:350px;\r
-    height:300px;\r
-       top:250px;\r
-}\r
-.NE_flow_show\r
-{\r
-    position:relative;\r
-    display:none;\r
-    font-size:16px;\r
-    margin-left:-4px;\r
-    /*border:2px solid green;*/\r
-    width:350px;\r
-    height:200px;      \r
-       margin-top:65px;\r
-}\r
-.NE_conn_show input.long\r
-{\r
-     width:345px;\r
-     height:25px;\r
-}\r
-\r
-.NE_conn_show input.short\r
-{\r
-\r
-     width:100px;\r
-     height:25px;\r
-}\r
-.NE_conn_show select\r
-{\r
-     width:348px;\r
-     height:25px;\r
-}\r
-.NE_conn_show .NE_close_show\r
-{\r
-    right:-2px;\r
-}\r
\r
-    .NE_conn_show #p2p_type\r
-    {     \r
-    /*border:2px solid green;*/\r
-    font-size:16px;\r
-    margin-left:-1px;\r
-    width:350px;\r
-    height:120px;\r
-    }\r
-\r
-\r
- .NE_conn_show .property_type\r
-{\r
-    font-size:16px;\r
-    margin-left:0px;\r
-     width:360px;\r
-     height:75px;\r
-}\r
-\r
-span.black {\r
-    color: black;\r
-}\r
-.NE_con_save,.NE_flow_save\r
-{\r
-    float:right;\r
-    margin-right:-7px;\r
-       margin-top:20px;\r
-    width:100px !important;\r
-    height:25px !important;\r
-    background-color:#399 !important;\r
-       margin-bottom:35px;\r
-}\r
-#p2mp_node-name1\r
-{\r
-   width:348px;\r
-}\r
-#p2mp_type .other_node_list\r
-{\r
-    overflow:auto;\r
-    margin-left:6px;\r
-    width:345px;\r
-    height:75px;\r
-}\r
-#p2mp_node-name2 table\r
-{\r
-    margin-left:0px;\r
-\r
-}\r
-#p2mp_node-name2 table td\r
-{\r
-    width:25px;\r
-    font-size:16px;\r
-    height:20px;\r
-\r
-}\r
-#p2mp_node-name2 table td input\r
-{\r
-    width:15px;\r
-    height:15px;\r
-\r
-}\r
-\r
- .NE_conn_show #p2mp_type\r
-    {   \r
-    display:none;\r
-    font-size:16px;\r
-    margin-left:-3px;\r
-    width:360px;\r
-    height:200px;\r
-    }\r
-  .NE_conn_show #mesh_type\r
-    {   \r
-    /*border:2px solid green;*/\r
-    display:none;\r
-    font-size:16px;\r
-    margin-left:-3px;\r
-    width:350px;\r
-    height:200px;\r
-    }\r
-  .NE_conn_show #chain_type\r
-    {   \r
-    /*border:2px solid green;*/\r
-    display:none;\r
-    font-size:16px;\r
-    margin-left:-3px;\r
-    width:350px;\r
-    height:200px;\r
-    }\r
-select#mesh_select,select#chain_select {\r
-    margin-left: 6px;\r
-}\r
-\r
-.NE_flow_show .match_items\r
-{\r
-    width:165px;\r
-    height:25px;\r
-}\r
-.NE_flow_show input.long,select.long\r
-{\r
-    width:345px;\r
-    height:25px;\r
-}\r
-.NE_flow_show .match_value\r
-{\r
-    \r
-     width:165px;\r
-    height:21px;\r
-}\r
-.NE_flow_show table\r
-{\r
-    margin-bottom:10px;\r
-       margin-left:3px;\r
-}\r
-#ety_dialog\r
-{\r
-    display:none;\r
-}\r
-#flow_dialog\r
-{\r
-    display:none;\r
-}\r
-\r
-.node_type_group\r
-{\r
-  padding-left: 0px;\r
-  width: 360px;\r
-  height: 130px;\r
-}\r
-#l2-group_type{\r
-    height:380px;\r
-}\r
-.node_type_group_group\r
-{\r
-  height: 280px;\r
-}\r
-\r
-#ext-group_type\r
-{\r
-     height: 240px;\r
-}\r
-#chain-group_type\r
-{\r
-    /*border: solid 1px red;*/\r
-     height: 200px;\r
-}\r
-.add_node,.del_node,.add_group,.del_group, .del_p2mp_node,.del_mesh_node,.del_chain_node\r
-{\r
-    background-color:#939;\r
-    width:55px !important;\r
-    height:25px !important;\r
-}\r
-.del_node,.del_p2mp_node,.del_mesh_node,.del_chain_node\r
-{\r
-       margin-left:30px;\r
-}\r
-.select_table\r
-{\r
-    margin-top:10px;\r
-}\r
-#l2_delgroup,#l3_delgroup,#chain_delgroup\r
-{\r
-    margin-top:5px;\r
-    width:278px;\r
-    height:110px;\r
-    border:1px solid #808080;\r
-    overflow:auto;\r
-}\r
-.del_sub_node\r
-{\r
-    margin-left:60px;\r
-    background-color:#939;\r
-    width:55px !important;\r
-    height:20px !important;\r
-    margin-top:5px;\r
-    margin-bottom:5px;\r
-}\r
-.l2_select_table tr\r
-{\r
-    margin-left:5px;\r
-    margin-bottom:10px;\r
-}\r
-\r
-/*out table set*/\r
-.conn_node_group\r
-{\r
-width:360px;\r
-}\r
-.conn_node_group_p2mp\r
-{\r
-width:360px;\r
-height:100px;\r
-/*border: 1px solid red;*/\r
-}\r
-.conn_node_group_mesh\r
-{\r
-width:360px;\r
-height:150px;\r
-/*border: 1px solid red;*/\r
-}\r
-.conn_node_group_chain\r
-{\r
-width:360px;\r
-height:100px;\r
-/*border: 1px solid red;*/\r
-}\r
-/*out table set*/\r
-\r
-/*border show div set*/\r
-#p2p_node_group\r
-{\r
-    margin-top:5px;\r
-    border:1px solid #808080;\r
-    width:335px;\r
-    height:100px;\r
-}\r
-\r
-#p2mp_node_group\r
-{\r
-    margin-top:5px;\r
-    border:1px solid #808080;\r
-    width:335px;\r
-    height:130px;\r
-    overflow:auto;\r
-}\r
-#mesh_node_group\r
-{\r
-    margin-top:5px;\r
-    border:1px solid #808080;\r
-    width:335px;\r
-    height:140px;\r
-    overflow:auto;\r
-}\r
-#chain_node_group\r
-{\r
-    margin-top:5px;\r
-    border:1px solid #808080;\r
-    width:335px;\r
-    height:140px;\r
-    overflow:auto;\r
-}\r
-/*border show div set*/\r
-\r
-#p2p_node_group table tr\r
-{\r
-    height:20px;\r
-}\r
-#p2mp_node_group table tr,#mesh_node_group table tr,#chain_node_group table tr\r
-{\r
-height:20px;\r
-width:220px;\r
-}\r
-    #p2mp_node_group table tr td\r
-    {\r
-        /*width:120px;*/\r
-    }\r
-\r
-#p2p_type {\r
-  height: 150px !important;\r
-}\r
-.txt3\r
-{\r
-  width: 110px !important;\r
-  height: 25px !important;\r
-  margin-left: 5px\r
-}\r
-\r
-#p2p_select_ok,#p2mp_select_ok\r
-{\r
-width:100px !important;\r
-}\r
-\r
-#p2p_select_ok2,#p2mp_select_ok2\r
-{\r
-    width:110px !important;\r
-}
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/css/RR.css b/nemo-ui/src/main/resources/nemo/css/RR.css
deleted file mode 100644 (file)
index 58cbac7..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-.RR_top\r
-{\r
-       margin-top:20px;\r
-       margin-left:-5px;\r
-}\r
-.btn_item_show #json_select\r
-{\r
- position:absolute; \r
- top:30px; \r
- left:0px; \r
- height:24px; \r
- width:265px;\r
- height:28px;}\r
\r
-.que_group\r
-{\r
-    width:300px;\r
-    height:30px;\r
-}\r
-.btn_item_show #query_topo\r
-{ \r
-    margin-top:5px;\r
-    margin-left:10px;\r
-    width:180px;\r
-    height:25px;\r
-    background-color: #939;\r
-}\r
-.RR_up h3\r
-{\r
-    font-size: 18px;\r
-    color: black;\r
-    text-align: center;\r
-    font-family: 微软雅黑,Verdana,Geneva,Arial,sans-serif;\r
-    margin-top: 20px;\r
-}
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/css/SI.css b/nemo-ui/src/main/resources/nemo/css/SI.css
deleted file mode 100644 (file)
index 7c59a9e..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-.Si_group h3 ,.Si_group p,.Si_group select,.Si_group .btn_group_less,.Si_group span{margin:0px 0 10px 0;}
-.Si_group h3{
-    font-size:18px;
-    color:black;
-       text-align:center;
-    font-family:微软雅黑,Verdana,Geneva,Arial,sans-serif;
-    margin-top:20px;
-}
-.Si_group p{
-    font-size:16px;
-    font-family:微软雅黑,Verdana,Geneva,Arial,sans-serif;
-       color:DarkSlateGray;
-       margin-bottom:1px;
-       margin-top:2px;
-}
-.select_item
-{
-    /*width:200px;*/
-       width:180px;
-    height:25px;
-       margin-left:0px;
-}
-#h3_height
-{
-    height:30px;
-}
-
-/*meng*/
-.btn_group_less
-{
-    /*border:2px solid green;*/
-    margin-top:10px;
-    /*width:250px;*/
-    height:30px;
-   padding-top:6px;
-       /*
-       meng
-       */
-       position:absolute;
-       top:84px;
-       left:190px;
-       width:166px;
-}
-.btn_group_less input
-{
- width:50px !important;
-}
-#Add_show
-{
-      position:relative;
-    margin-top:20px;
-    width:340px;
-    height:250px;
-       margin-left:0px;
-}
-    #Add_show span
-    {
-        display:block;
-        margin-top:5px;
-    }
-
-.close_group
-{
-    position:absolute;
-    right:0px;
-    top:0px;
-    width:20px;
-    height:20px;
-}
-
-.select_btn
-{
-    height:40px;
-       margin-left:0px;
-}
-
-.btn_SI
-{    height:25px; 
-    background-color:#939;
-       /*meng*/
-       margin-left:0px;
-       width:50px;
-       font-size:15px;
-       font-family:黑体;
-}
-.text_item
-{
-    height:25px;
-       /*meng*/
-       width:340px;
-       margin-left:0px;
-}
-/* .desc_text
-{
-    width:315px;
-} */
-
-.save_group
-{
-     width:100px;
-     height:27px;
-     float:right;
-     margin-top:30px;
-     margin-right:-3px;
-     background-color:#399;
-}
-.submit_group
-{
-     /*width:360px;
-     height:40px;
-     margin:50px auto;
-     background-color:#939;
-     font-size:17px;*/
-
-}
-#dialog
-{
-    display:none;
-    width:500px;
-}
-#ser_dialoge,#del_ser_dialog
-{
-    display:none;
-}
diff --git a/nemo-ui/src/main/resources/nemo/css/SP.css b/nemo-ui/src/main/resources/nemo/css/SP.css
deleted file mode 100644 (file)
index 14c7e6a..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-.SP_up, .SP_btn_group, .SP_down{margin-left:2px;}\r
-.SP_add_show{\r
-    display:none;\r
-    margin-left:-8px;\r
-}\r
-.SP_up\r
-{\r
-    /*border:2px solid green;*/\r
-    width:356px;\r
-    height:155px;\r
-}\r
-.SP_up h3\r
-{\r
-  color:black;\r
-  font-size:18px;\r
-}\r
- .SP_up span\r
-    {\r
-     margin-top:0px;\r
-      /*border:2px solid green;*/\r
-      display:block;\r
-        width:180px;\r
-        float:left;\r
-        \r
-    }\r
-    .SP_up select\r
-    {       \r
-        margin-top:0px;\r
-        width:348px;\r
-        height:25px;\r
-               margin-bottom:10px;\r
-    }\r
-    .SP_up .select_item\r
-    {\r
-        width:348px;\r
-        height:25px;\r
-        margin-left:6px;\r
-    }\r
-.SP_btn_group\r
-{\r
-    float:right;\r
-    /*border:2px solid green;*/\r
-    width:160px;\r
-    height:25px;\r
-       margin-right:0px;\r
-}\r
-    .SP_btn_group input\r
-    {\r
-        /*float:right;*/\r
-        margin-left:-6px;\r
-        width:50px;\r
-        height:25px;\r
-        background-color:#939;\r
-    }\r
-       \r
-       \r
-.SP_down\r
-{\r
-    /*border:2px solid green;*/\r
-    width:360px;\r
-       height:850px;\r
-}\r
-    .SP_down table tr\r
-    {\r
-        height:26px;\r
-    }\r
-    .SP_down .id_,#policy_name,#policy_priority\r
-    {\r
-        width:343px;\r
-        height:25px;\r
-    }\r
-    .SP_down select\r
-    {\r
-        width:346px;\r
-        height:25px;\r
-    }\r
-       select#policy_data\r
-       {\r
-           width:284px;\r
-       }\r
-       \r
-    .SP_down .Con_group input\r
-    {\r
-        width:340px;\r
-        height:25px;\r
-    }\r
-    .SP_down .list_nodes\r
-    {\r
-    /*border:1px solid #7e5b42;\r
-    background-color:#f2f2f2;*/\r
-    overflow:auto;\r
-    margin-left:13px;\r
-    width:336px;\r
-    height:90px;\r
-    }\r
-       .list_nodes table td\r
-{\r
-    /*border:2px solid black;*/\r
-    /*width:154px;*/\r
-    width:25px;\r
-    font-size:16px;\r
-    height:20px;\r
-\r
-}\r
-    .list_nodes table td input\r
-{\r
-    /*border:2px solid black;*/\r
-    /*width:154px;*/\r
-       margin-top:7px;\r
-    width:15px;\r
-    height:15px;\r
-\r
-}\r
-    .SP_down .btn_edit\r
-    {\r
-        width:50px;\r
-        height:25px;\r
-        background-color:#939;\r
-        margin-left:1px;\r
-    }\r
-.SP_btn_save\r
-{\r
-    /*border:2px solid green;*/\r
-    width:360px;\r
-    height:25px;\r
-}\r
-.SP_btn_save .btn_\r
-{\r
-\r
-    width:100px;\r
-    height:25px;\r
-    margin-left:254px;\r
-    background-color:#399;\r
-    margin-top:60px;\r
-       margin-bottom:30px;\r
-}\r
-input#policy_edit{\r
-margin-left:0px;\r
-margin-right:2px;\r
-}\r
-#SP_close_show\r
-{\r
-    float:right;\r
-       margin-right:10px;\r
-    width:20px;\r
-    height:20px;\r
-}\r
-#adc_dialog\r
-{\r
-    display:none;\r
-    padding-top:10px;  \r
-    width:500px;\r
-    height:395px;\r
-    font-size:16px;\r
-       /*overflow-y:scroll;*/\r
-}\r
-    #adc_dialog p\r
-    {\r
-        font-family:微软雅黑;\r
-        margin-top:20px;\r
-        margin-left:7px;\r
-    }\r
-    #adc_dialog input\r
-{ \r
-        margin-top:5px;\r
-        margin-bottom:10px;\r
-        margin-left:6px;\r
-    width:285px;\r
-    height:25px;\r
-}\r
-#adc_dialog input.btn_\r
-{ \r
-     color:white;\r
-    -moz-border-radius: 6px;\r
-    -webkit-border-radius: 6px;\r
-    -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    text-shadow: 0 -1px 1px rgba(0,0,0,0.25);\r
-    border-bottom: 1px solid rgba(0,0,0,0.25);\r
-    cursor:pointer;\r
-       font-size:15px;\r
-       font-family:黑体;\r
-    width:111px;\r
-    height:24px;\r
-    background-color:#939;\r
-}\r
-\r
-    #adc_dialog span,h3{\r
-    color:black;\r
-    }\r
-#adc_node\r
-{\r
-   width:280px;\r
-   height:25px;\r
-   margin-left:6px;\r
-}\r
-\r
-#num\r
-{\r
-   width:242px;\r
-   height:25px;\r
-}\r
-\r
-#adc_dialog span\r
-{\r
-   margin-left:7px;\r
-}\r
-\r
-\r
-#adc_dialog h3\r
-{\r
-   text-align:center;\r
-}\r
-\r
-\r
-.ui-button\r
-{\r
-    width:92px;\r
-}\r
-    #table_tab th,#table_tab td\r
-    {\r
-        height:20px;\r
-               border:1px solid #696969;\r
-    }  \r
- #table_tab th\r
-    {\r
-        background-color:#A9A9A9;\r
-    }          \r
-               \r
-       \r
-#table_tab .first_colum\r
-{\r
-    width:45px;\r
-}\r
-#table_show\r
-{\r
-    width:408px;\r
-    height:140px;\r
-    overflow:scroll;\r
-}\r
-#table_tab\r
-{ \r
-    border-collapse:collapse;\r
-    border:1px solid #696969;\r
-    width:380px;\r
-    height:50px;\r
-       margin-top:10px;\r
-    overflow-y:scroll;\r
-}\r
-\r
-#firewall_dialog\r
-{\r
-    display:none;\r
-    padding-top:10px;  \r
-    width:500px;\r
-    height:395px;\r
-    font-size:16px;\r
-       /*overflow-y:scroll;*/\r
-}\r
-    #firewall_dialog p\r
-    {\r
-        font-family:微软雅黑;\r
-        margin-top:20px;\r
-        margin-left:7px;\r
-    }\r
-    #firewall_dialog input\r
-{ \r
-        margin-top:5px;\r
-        margin-bottom:10px;\r
-        margin-left:6px;\r
-    width:285px;\r
-    height:25px;\r
-}\r
-#firewall_dialog input.btn_\r
-{ \r
-     color:white;\r
-    -moz-border-radius: 6px;\r
-    -webkit-border-radius: 6px;\r
-    -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    text-shadow: 0 -1px 1px rgba(0,0,0,0.25);\r
-    border-bottom: 1px solid rgba(0,0,0,0.25);\r
-    cursor:pointer;\r
-       font-size:15px;\r
-       font-family:黑体;\r
-    width:111px;\r
-    height:24px;\r
-    background-color:#939;\r
-}\r
-\r
-    #firewall_dialog span,h3{\r
-    color:black;\r
-    }\r
-#firewall_node\r
-{\r
-   width:280px;\r
-   height:25px;\r
-   margin-left:6px;\r
-}\r
-\r
-#firewall_num\r
-{\r
-   width:242px;\r
-   height:25px;\r
-}\r
-\r
-#firewall_dialog span\r
-{\r
-   margin-left:7px;\r
-}\r
-\r
-\r
-#firewall_dialog h3\r
-{\r
-   text-align:center;\r
-}\r
-\r
-\r
-.ui-button\r
-{\r
-    width:92px;\r
-}\r
-    #firewall_table_tab th,#firewall_table_tab td\r
-    {\r
-        height:20px;\r
-               border:1px solid #696969;\r
-    }  \r
- #firewall_table_tab th\r
-    {\r
-        background-color:#A9A9A9;\r
-    }          \r
-               \r
-       \r
-#firewall_table_tab .first_colum\r
-{\r
-    width:45px;\r
-}\r
-#firewall_table_show\r
-{\r
-    width:408px;\r
-    height:140px;\r
-    overflow:scroll;\r
-}\r
-#firewall_table_tab\r
-{ \r
-    border-collapse:collapse;\r
-    border:1px solid #696969;\r
-    width:380px;\r
-    height:50px;\r
-       margin-top:10px;\r
-    overflow-y:scroll;\r
-}\r
-\r
-\r
-#policy_name_list\r
-{\r
-    width:180px;\r
-}\r
-.Con_group\r
-{\r
-   margin-left:1px;\r
-}\r
-\r
-#policy_name_icon\r
-{\r
-  height:14px;\r
-  margin-bottom:-3px;\r
-}\r
-#start_time_icon\r
-{\r
-   height:14px;\r
-   margin-bottom:-3px;\r
-}\r
-#node_list_table tr\r
-{\r
-   padding-top:1px;\r
-   padding-bottom:1px;\r
-}\r
-\r
-#policy_dialog\r
-{\r
-    display:none;\r
-}\r
-\r
-\r
-.con_show:nth-child(1)\r
-{\r
-    width:70px;\r
-    height:25px;\r
-}\r
-.con_show:nth-child(2)\r
-{\r
-    width:132px;\r
-    height:25px;\r
-}\r
-input.con_show:nth-child(3)\r
-{\r
-    width:75px;\r
-    height:25px;\r
-}\r
-input.con_button\r
-{\r
-    width:60px;\r
-    background-color:#939;\r
-     height:25px;\r
-}\r
-\r
-select.ext_con_1\r
-{\r
-    width:115px;\r
-    height:25px;\r
-    margin-top:10px;\r
-    margin-bottom:10px;\r
-}\r
-input.ext_con_2\r
-{\r
-    width:60px;\r
-    height:25px;\r
-}\r
-input.ext_con_3\r
-{\r
-    width:85px;\r
-    height:25px;\r
-}\r
-input.ext_con_4\r
-{\r
-    height:25px;\r
-    width:60px;\r
-}\r
-#con_clear\r
-{\r
-  background-color:#939;\r
-  margin-left: 90px;\r
-  margin-top: 15px;\r
-  margin-bottom: 5px;\r
-  width:65px;\r
-  height:25px;\r
-}\r
-#con_select\r
-{\r
-    border:1px solid #ccc;\r
-    overflow-x:scroll;\r
-    width:320px;\r
-    height:100px;\r
-}
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/css/jquery-ui.min.css b/nemo-ui/src/main/resources/nemo/css/jquery-ui.min.css
deleted file mode 100644 (file)
index 3646534..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*! jQuery UI - v1.11.4 - 2015-03-11
-* http://jqueryui.com
-* Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
-* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
-* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
-
-.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{color:black;padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ccc;background:#ccc url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px}
diff --git a/nemo-ui/src/main/resources/nemo/css/nemo_main.css b/nemo-ui/src/main/resources/nemo/css/nemo_main.css
deleted file mode 100644 (file)
index 63366df..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-*{margin:0px;padding:0px;}\r
-body{background-color:#f2f2f2;}\r
-.group\r
-{\r
-border:transparent;\r
-width:1250px;\r
-height:850px;\r
-margin:0 auto;\r
-font-family:微软雅黑;\r
-}\r
-\r
-.group_left\r
-{\r
-float:left;\r
-position:relative;\r
-/*border:2px solid green;*/\r
-width:400px;\r
-height:850px;\r
-margin-top:25px;\r
-margin-left:10px;\r
-background-color:#fff; \r
-}\r
-\r
-.group_right\r
-{\r
-float:right;\r
-position:relative;\r
-/*border:2px solid green;*/\r
-width:800px;\r
-height:840px;  \r
-margin-top:5px;\r
-margin-right:10px;\r
-}\r
-\r
-.up\r
-{\r
-width:800px;\r
-height:590px;  \r
-background-color:#fff;\r
-}\r
-#graph\r
-{\r
-    width:800px;\r
-    height:500px;\r
-}\r
-.down\r
-{\r
-background-color:#fff;\r
-/*border:2px solid green;*/\r
-width:800px;\r
-height:230px;  \r
-margin-top:10px;\r
-}\r
-.title\r
-{\r
-/*border:2px solid green;*/\r
-height:30px;   \r
-background-color:#f2f2f2;\r
-}\r
-.tt{\r
-margin-top:-18px;\r
-}\r
-.btn_item_none\r
-{\r
-  background-color:#f2f2f2;\r
-}\r
-.btn_item_click\r
- {\r
-background-color:#ccc !important;\r
- }\r
-.group_left .btn_item\r
-{\r
-/*border:2px solid green;*/\r
-background-color:#f2f2f2;\r
-width:380px;\r
-height:40px;   \r
-margin:10px 10px 0px 10px;\r
-font-size:18px;\r
-text-decoration: none;\r
--moz-border-radius: 6px;\r
--webkit-border-radius: 6px;\r
--moz-box-shadow: 0 1px 3px rgba(0,0,0,0.6);\r
--webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.6);\r
-text-shadow: 0 -1px 1px rgba(0,0,0,0.25);\r
-border-bottom: 1px solid rgba(0,0,0,0.25);\r
-position: relative;\r
-cursor:pointer;\r
-font-family:黑体;\r
-}\r
-\r
-\r
-h2\r
-{\r
-    color:#b571b3;\r
-}\r
-.btn_item_show\r
-{\r
-    /*overflow:scroll;*/\r
-       overflow-y:scroll;\r
-    position:relative;\r
-    padding-top:10px;\r
-    border:0px solid green;\r
-    margin:10px auto;\r
-    margin-bottom:10px;\r
-    display:none;\r
-    width:380px;\r
-    height:520px;\r
-    background-color:#fafafa;\r
-}\r
-    .btn_item_show *\r
-    {\r
-        margin-left:6px\r
-    }\r
-       \r
-.group_left .btn_\r
-{\r
-    color:white;\r
-    -moz-border-radius: 6px;\r
-    -webkit-border-radius: 6px;\r
-    -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    text-shadow: 0 -1px 1px rgba(0,0,0,0.25);\r
-    border-bottom: 1px solid rgba(0,0,0,0.25);\r
-    cursor:pointer;\r
-       font-size:15px;\r
-       font-family:黑体;\r
-}\r
-.group_right .btn_\r
-{\r
-    color:white;\r
-    -moz-border-radius: 6px;\r
-    -webkit-border-radius: 6px;\r
-    -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    text-shadow: 0 -1px 1px rgba(0,0,0,0.25);\r
-    border-bottom: 1px solid rgba(0,0,0,0.25);\r
-    cursor:pointer;\r
-    font-size:15px;\r
-    background-color: #939;\r
-    font-family:黑体;\r
-    width:90px;\r
-    height:25px;\r
-   /* position: absolute;\r
-    top:22px;\r
-    right: 10px;*/\r
-}\r
-#btn_local\r
-{\r
-     /*border:2px solid green;*/\r
-     width:370px;\r
-     height:45px;\r
-     /*position:absolute;*/\r
-     margin-left:4px;\r
-     left:10px;\r
-}\r
-\r
-.btn_submit\r
-{\r
-    position:absolute;\r
-    bottom:2px;\r
-     width:390px !important;\r
-     height:40px !important; \r
-     background-color:#939;\r
-     font-size:20px !important;\r
-}\r
-.btn_item_show .close_item_show img\r
-{\r
-    position:absolute;\r
-    top:0px;\r
-    right:0px;\r
-    width:30px;\r
-    height:30px;\r
-}\r
-.second_title\r
-{\r
-    font-size:16px;\r
-    font-family:微软雅黑;\r
-       color:DarkSlateGray;\r
-       margin-bottom:1px;\r
-       width:348px;\r
-}\r
-.h3_style\r
-{\r
-    height:35px;\r
-       font-size:14px;\r
-       text-align:center;\r
-    font-family:微软雅黑;\r
-    margin-top:20px;\r
-}\r
-#nemo_str_show p,#con_select p\r
-{\r
-    white-space:pre;\r
-    display:normal;\r
-    margin:0px;\r
-    margin-left:4px;\r
-    font-size:13px;\r
-}\r
-span.key\r
-{\r
-    display:normal;\r
-    font-size:13px;\r
-    color:red;\r
-}\r
-\r
-#nemo_str_show\r
-{\r
-  \r
-  height:200px;\r
-       white-space:pre; \r
-  overflow:scroll;\r
-}\r
-\r
-#trans_info\r
-{ \r
-  width:760px;\r
-  height:200px;\r
-  white-space:pre; \r
-  overflow:scroll;\r
-  font-family: 微软雅黑;\r
-}\r
-.alert_\r
-{\r
-  height:15px;\r
-  width:15px;\r
-  margin-bottom:-3px;\r
-}\r
-.big_second_title\r
-{\r
-  margin-top:30px;\r
-  height:25px;\r
-  padding-left:3px;\r
-}\r
-.big_second_title span{\r
-  color:black;\r
-  font-size: 17px;\r
-   margin-left: -1px;\r
-}\r
-#net_ent_init, #ser_poc_init,#advance_query\r
-{\r
-   margin-left:30px;\r
-   width:340px;\r
-   height:30px;\r
-   background-color:#fcfcfc;\r
-}\r
-.group h2\r
-{\r
-font-family: 微软雅黑;\r
-padding-top:4px;\r
-color:black;\r
-font-size:18px;\r
-font-weight:600;\r
-}\r
-\r
-.third_title span{\r
-color:black;\r
-}\r
-#tabs\r
-{\r
-  width: 800px;\r
-  height: 250px;\r
-}\r
-#tabs li a\r
-{\r
-font-family: 微软雅黑,宋体;\r
-font-size: 15px;\r
-color:black;\r
-}\r
-#tabs .ui-tabs-active a\r
-{\r
-color:red !important;\r
-}\r
-#loader\r
-{\r
-  width: 20px;\r
-  height: 20px;\r
-  border: 0px solid red;\r
-  margin-top:-25px;\r
-}\r
-.node_type_group\r
-{\r
-  padding-left: 0px;\r
-  width: 360px;\r
-  height: 130px;\r
-}\r
-.node_type_group_group\r
-{\r
-  height: 360px;\r
-}\r
-.txt2\r
-{\r
-  width: 280px !important;\r
-  height: 25px !important;\r
-  margin-left: 0px\r
-}\r
-.add_node,.del_node,.add_group,.del_group\r
-{\r
-    width:55px !important;\r
-    height:25px !important;\r
-}\r
-.select_table\r
-{\r
-    margin-top:10px;\r
-}\r
-.grey_background,.grey_background span\r
-{\r
-    color:rgba(122,122,122,1);\r
-}\r
-.conn_type_group span {\r
-    color: black !important;\r
-}\r
-.property_type span{\r
-  color:black !important;\r
-}\r
-\r
-div#right_top span {\r
-color: black;\r
-}\r
-#right_top{\r
-  /*border: solid 1px red;*/\r
-  position: absolute;\r
-   top: 22px;\r
-  right: 0px;\r
-  width: 286px;\r
-}\r
-#getUserName{\r
-/*position: absolute;\r
-top: 22px;\r
-  right: 110px;*/\r
-  width: 100px;\r
-  height: 25px;\r
-}\r
-\r
-/*hide service names*/\r
-.NE_up #sel_1,.NE_up .NE_serviceName,.SP_up .select_item,.SP_up .OP_serviceName{\r
-  display: none;;\r
-}\r
-.up_group1_2 {\r
-  margin-top: 3px !important;\r
-}\r
-.NE_up{\r
-  position:static !important;\r
-}\r
-div#pageContent {\r
-  height: 850px;\r
-}\r
-  \r
-body {\r
-    width: 1530px;\r
-    overflow: scroll;\r
-    margin-right: 0px;\r
-}\r
diff --git a/nemo-ui/src/main/resources/nemo/css/register.css b/nemo-ui/src/main/resources/nemo/css/register.css
deleted file mode 100644 (file)
index 8bd7e4f..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-* {margin:0;padding: 0}\r
-body\r
-{\r
-       font-family: 宋体;\r
-       background-color: #ccc;\r
-}\r
-#logPage{\r
-       \r
-}\r
-#reg,#log\r
-{\r
-       border: 1px solid rgb(220,220,220);\r
-       background-color:rgba(240,240,240,0.8);\r
-       width: 350px;\r
-       height: 250px;\r
-   margin: 180px auto;\r
-   position: relative;\r
-}\r
-#reg\r
-{\r
-       width: 350px;\r
-       height: 280px;\r
-       display: none;\r
-}\r
-#reg_title\r
-{\r
-       margin-top: 10px;\r
-       margin-left: 100px;\r
-       font-size: 20px;\r
-}\r
-#log_title\r
-{\r
-       margin-top: 10px;\r
-       margin-left: 130px;\r
-       font-size: 20px;\r
-}\r
-#reg_info,#log_info\r
-{\r
-       width: 310px;\r
-       height: 200px;\r
-       margin-top: 20px;\r
-       margin-left: 30px;\r
-}\r
-#reg_info table,#log_info table\r
-{\r
-\r
-       width: 280px;\r
-       height: 150px;\r
-       margin-top: 20px;\r
-       margin-left: 0px;\r
-}\r
-#reg_info table\r
-{\r
-       height: 200px;\r
-}\r
-table tr\r
-{\r
-\r
-       /* width: 260px; */\r
-       height: 20px;\r
-       margin-top: 10px;\r
-       margin-left: 0px;\r
-        -moz-border-radius: 6px;\r
-    -webkit-border-radius: 6px;\r
-    -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    border-bottom: 0px solid rgba(0,0,0,0.25);\r
-}\r
-table tr td\r
-{\r
-               /*background-color:E8E8E8;*/\r
-               text-align: center;\r
-}\r
-#show_reg \r
-{\r
-       /*padding-top: 15px;*/\r
-}\r
-#show_reg td \r
-{\r
-       text-align: right;\r
-}\r
-#show_reg span {\r
-    color: #5A0707;\r
-    font-size: 15px;\r
-}\r
-input\r
-{\r
-       width: 160px;\r
-       height: 20px;\r
-}\r
-select\r
-{\r
-       width: 165px;\r
-       height: 25px;\r
-}\r
-button\r
-{\r
-       margin-top: 10px;\r
-       margin-left: 20px;\r
-       margin-right: 20px;\r
-       width: 65px;\r
-       height: 25px;\r
-       color:white;\r
-    -moz-border-radius: 6px;\r
-    -webkit-border-radius: 6px;\r
-    -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.6);\r
-    text-shadow: 0 -1px 1px rgba(0,0,0,0.25);\r
-    border-bottom: 1px solid rgba(0,0,0,0.25);\r
-    cursor:pointer;\r
-       font-size:15px;\r
-       font-family:黑体;\r
-       background-color:#993399;\r
-}\r
-#reg_cancle\r
-{\r
-       \r
-}\r
diff --git a/nemo-ui/src/main/resources/nemo/images/alert.png b/nemo-ui/src/main/resources/nemo/images/alert.png
deleted file mode 100644 (file)
index f5d4392..0000000
Binary files a/nemo-ui/src/main/resources/nemo/images/alert.png and /dev/null differ
diff --git a/nemo-ui/src/main/resources/nemo/images/error.png b/nemo-ui/src/main/resources/nemo/images/error.png
deleted file mode 100644 (file)
index 198770b..0000000
Binary files a/nemo-ui/src/main/resources/nemo/images/error.png and /dev/null differ
diff --git a/nemo-ui/src/main/resources/nemo/images/host.png b/nemo-ui/src/main/resources/nemo/images/host.png
deleted file mode 100644 (file)
index 67cd29a..0000000
Binary files a/nemo-ui/src/main/resources/nemo/images/host.png and /dev/null differ
diff --git a/nemo-ui/src/main/resources/nemo/images/null.gif b/nemo-ui/src/main/resources/nemo/images/null.gif
deleted file mode 100644 (file)
index 1d11fa9..0000000
Binary files a/nemo-ui/src/main/resources/nemo/images/null.gif and /dev/null differ
diff --git a/nemo-ui/src/main/resources/nemo/images/ok.png b/nemo-ui/src/main/resources/nemo/images/ok.png
deleted file mode 100644 (file)
index 833512d..0000000
Binary files a/nemo-ui/src/main/resources/nemo/images/ok.png and /dev/null differ
diff --git a/nemo-ui/src/main/resources/nemo/images/shut.png b/nemo-ui/src/main/resources/nemo/images/shut.png
deleted file mode 100644 (file)
index 2d2bd39..0000000
Binary files a/nemo-ui/src/main/resources/nemo/images/shut.png and /dev/null differ
diff --git a/nemo-ui/src/main/resources/nemo/images/view_desc_2.png b/nemo-ui/src/main/resources/nemo/images/view_desc_2.png
deleted file mode 100644 (file)
index b4a4d81..0000000
Binary files a/nemo-ui/src/main/resources/nemo/images/view_desc_2.png and /dev/null differ
diff --git a/nemo-ui/src/main/resources/nemo/js/EI_tranjson.js b/nemo-ui/src/main/resources/nemo/js/EI_tranjson.js
deleted file mode 100644 (file)
index b1bc177..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-var restful_json=[];\r
-\r
-\r
-\r
-var restful_count=[];\r
-var restful_query_json=[];\r
-var restful_query_count=[];\r
-var restful_exec_flag = 0;\r
-var intterval_id = 0;\r
-//###############################################EXEC_Query##################################################//\r
-       function query_status_exec()\r
-       {\r
-               //var query_str = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'"}}';\r
-               //var query_json = jQuery.parseJSON(query_str);\r
-               jQuery.ajax({ \r
-                           url: "/restconf/config/intent-processing-status:intent-processing-statuses/user-intent-status/"+user_id+"/transaction-status/", \r
-                               type:"GET",\r
-                               //data:query_str,\r
-                               //contentType:"application/json; charset=UTF-8",\r
-                               dataType:"json",\r
-                               success: function(data){\r
-                                       if(data["output"]["result-code"] == "ok")\r
-                                       {\r
-                                               restful_exec_flag = 0;\r
-                                               jQuery("#show_status").hide();\r
-                                               if(intterval_id != 0)\r
-                                               {\r
-                             exec_success();\r
-                                                       alert("Exec succeed!!!");\r
-                                                       //clearInterval(intterval_id);\r
-                                               }\r
-                                       }\r
-                               },\r
-                                error:function(data){\r
-                                       console.log(data);\r
-                                       //alert("exec query failed");                           \r
-                               }\r
-               });\r
-       }\r
-//#####################################################################################################################//\r
-jQuery(document).ready(function ($) {\r
-       \r
-});\r
-\r
-\r
-\r
-\r
-//##################################### CREATE_JSON(Entity,Policy,Delete,Query) ######################################//\r
-function create_json(SI_name)\r
-{\r
-       var restful_node=[];\r
-       var restful_connection=[];\r
-       var restful_flow=[];\r
-       var restful_policy=[];\r
-       var restful_delete=[];\r
-       restful_query_count[SI_name] = 0;\r
-       // var node_json_count = 0;\r
-       // var connection_json_count = 0;\r
-       // var flow_json_count = 0;\r
-       // var node_json_count = 0;\r
-       // var delete_json_count = 0;\r
-       restful_json[SI_name]=[];\r
-       var json_query_tmp = [];\r
-       console.log(localStorage.length);\r
-\r
-       for (var i = 0; i<localStorage.length;i++)\r
-       {\r
-               if(localStorage.key(i).indexOf(SI_name+'__') == -1)\r
-                       continue;\r
-               else if(localStorage.key(i).indexOf(SI_name+'__node') > -1 || localStorage.key(i).indexOf('connection_') > -1 || localStorage.key(i).indexOf('flow_') > -1 )\r
-               {\r
-                       var type_info = tran_tpjson_entity(localStorage.getItem(localStorage.key(i)));\r
-                       if(localStorage.key(i).indexOf(SI_name+'__node') > -1)\r
-                       {\r
-                               for (var j = 0; j < type_info.length; j++) {\r
-                                       restful_node.push(type_info[j]);\r
-                               }\r
-                   }\r
-                   else if(localStorage.key(i).indexOf('connection_') > -1){\r
-                               restful_connection.push(type_info);\r
-                   }\r
-                   else if(localStorage.key(i).indexOf('flow_') > -1)\r
-                   {\r
-                       restful_flow.push(type_info);\r
-                   }\r
-               }\r
-               else if(localStorage.key(i).indexOf(SI_name+'__policy') > -1)\r
-               {\r
-                       restful_policy.push(tran_tpjson_policy(localStorage.getItem(localStorage.key(i))));\r
-               }\r
-               else if(localStorage.key(i).indexOf(SI_name+'__delete') > -1)\r
-               {\r
-                       var delete_id;\r
-                       if(localStorage.key(i).indexOf('node') > -1)\r
-                       {\r
-                               var delete_data = jQuery.parseJSON(localStorage.getItem(localStorage.key(i)));\r
-                               delete_id = delete_data["node_id"];\r
-                       }\r
-                       else if(localStorage.key(i).indexOf('connection') > -1)\r
-                       {\r
-                               var delete_data = jQuery.parseJSON(localStorage.getItem(localStorage.key(i)));\r
-                               delete_id = delete_data["connection_id"];\r
-                       }\r
-                       else if(localStorage.key(i).indexOf('flow') > -1)\r
-                       {\r
-                               var delete_data = jQuery.parseJSON(localStorage.getItem(localStorage.key(i)));\r
-                               delete_id = delete_data["flow_id"];\r
-                       }\r
-                       else if(localStorage.key(i).indexOf('policy') > -1)\r
-                       {\r
-                               var delete_data = jQuery.parseJSON(localStorage.getItem(localStorage.key(i)));\r
-                               delete_id = delete_data["policy_id"];\r
-                       }\r
-                       restful_delete.push(tran_tpjson_delete(delete_id));\r
-               }\r
-               else if(localStorage.key(i).indexOf(SI_name+'__query') > -1)\r
-               {\r
-                       json_query_tmp[restful_query_count[SI_name]] = tran_tpjson_query(localStorage.getItem(localStorage.key(i)));\r
-                       restful_query_count[SI_name]++;\r
-               }\r
-       }\r
-       for(var json_cursor in restful_delete)\r
-               restful_json[SI_name].push(restful_delete[json_cursor]);\r
-       for(var json_cursor in restful_node)\r
-               restful_json[SI_name].push(restful_node[json_cursor]);\r
-       for(var json_cursor in restful_connection)\r
-               restful_json[SI_name].push(restful_connection[json_cursor]);\r
-       for(var json_cursor in restful_flow)\r
-               restful_json[SI_name].push(restful_flow[json_cursor]);\r
-       for(var json_cursor in restful_policy)\r
-               restful_json[SI_name].push(restful_policy[json_cursor]);\r
-       restful_query_json[SI_name] = json_query_tmp;\r
-       console.log(restful_json[SI_name]);\r
-       console.log(restful_query_json[SI_name]);\r
-}\r
-//#####################################################################################################################//\r
-\r
-\r
-//#################################################### CREATE_Entity_Json##############################################//\r
-function tran_tpjson_entity(entity_str)\r
-{\r
-       var entity_json = jQuery.parseJSON(entity_str);\r
-       var restful_json_temp;\r
-       for(var key in entity_json)\r
-       {\r
-               if(entity_json[key]["Entity_Type"] == "node")\r
-               {\r
-                       restful_json_temp=tran_tojson_node(entity_json[key]);\r
-               }\r
-               else if(entity_json[key]["Entity_Type"] == "connection")\r
-               {\r
-                       restful_json_temp=tran_tojson_connection(entity_json[key]);\r
-               }\r
-               else if(entity_json[key]["Entity_Type"] == "flow")\r
-               {\r
-                       restful_json_temp=tran_tojson_flow(entity_json[key]);\r
-               }\r
-               \r
-       }\r
-    return restful_json_temp;\r
-}\r
-//#####################################################################################################################//\r
-\r
-//#################################################### CREATE_Policy_Json##############################################//\r
-function tran_tpjson_policy(policy_str)\r
-{\r
-       var policy_data;\r
-       var policy_json = jQuery.parseJSON(policy_str);\r
-       var restful_json_temp;\r
-       for(var key_ in policy_json)\r
-       {\r
-               policy_data = policy_json[key_];\r
-       }\r
-       \r
-       var condition_count = 0;\r
-       restful_json_temp = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'",';\r
-    //test\r
-       //restful_json_temp += '"operations":{"operation":[{"operation-id":"'+1+'","operation-name":"'+2+'","priority":"'+3+'","target-object":"'+5+'","condition":[';\r
-       //alert(policy_data["apply_entity_id"].substring(5,policy_data["apply_entity_id"].length));\r
-       restful_json_temp += '"operations":{"operation":[{"operation-id":"'+policy_data["policy_id"]+'","operation-name":"'+policy_data["policy_name"]+'","target-object":"'+find_flow_id(policy_data["apply_entity_id"].substring(5,policy_data["apply_entity_id"].length))+'","priority":"'+policy_data["policy_priority"]+'","condition":[';\r
-        //console.log(policy_data["condition"][0]);\r
-        for(var key_2 in policy_data["condition"])\r
-        {\r
-               var condition_array = policy_data["condition"][key_2].split(' ');\r
-               //console.log(condition_array);\r
-               restful_json_temp += '{"condition-segement-id":"'+condition_array[5].substring(1,condition_array[5].length-1)+'","condition-parameter-name": "'+condition_array[0]+'","condition-parameter-match-pattern":"'+condition_array[1]+'","condtion-parameter-target-value":{"int-value":"'+condition_array[2]+'"},"condition-relation-operator":"'+condition_array[3]+'","order":"'+condition_array[4]+'"},';\r
-               condition_count++;       \r
-        }\r
-        if(condition_count>0)\r
-        {\r
-               restful_json_temp = restful_json_temp.substring(0,(restful_json_temp.length-1));\r
-               restful_json_temp+='],';\r
-        }\r
-               \r
-       else\r
-               restful_json_temp = restful_json_temp.substring(0,(restful_json_temp.length-13));\r
-\r
-       //test\r
-    //restful_json_temp += '{"condition-segement-id":"'+1+'","condition-parameter-name": "'+2+'","condition-parameter-match-pattern":"'+3+'","condtion-parameter-target-value":{"int-value":"'+4+'"},"condition-relation-operator":"'+5+'","order":"'+6+'"}';\r
-\r
-       restful_json_temp += '"action":[{"action-name":"'+policy_data["action"]+'","parameter-values":{"string-value":[{"value":"'+find_node_id(policy_data["data"])+'","order":"'+0+'"}]},"order":"0"}]';\r
-       restful_json_temp += '}]}}}';\r
-       console.log(restful_json_temp);\r
-       return restful_json_temp;\r
-}\r
-//#####################################################################################################################//\r
-\r
-//#################################################### CREATE_Delete_Json##############################################//\r
-function tran_tpjson_delete(delete_id)\r
-{\r
-       var restful_json_temp;\r
-       \r
-       restful_json_temp = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'",';\r
-restful_json_temp += '"objects":{node":["'+delete_id+'"]';\r
-       restful_json_temp += '}}}';\r
-       return restful_json_temp;\r
-}\r
-//#####################################################################################################################//\r
-\r
-\r
-//#################################################### CREATE_Query_Json##############################################//\r
-function tran_tpjson_query(query_str)\r
-{\r
-       var query_data = jQuery.parseJSON(query_str);\r
-       var restful_json_temp;\r
-       \r
-       restful_json_temp = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'",';\r
-       restful_json_temp += '"query-condition":[{"query-condition-id":"'+1+'","query-condition-name":"'+2+'","query-intent-type":"'+3+'","query-condition-match-pattern":"'+4+'","query-condition-match-pattern":{"int-value":"'+5+'"}}]';\r
-       restful_json_temp += '}}';\r
-       return restful_json_temp;\r
-}\r
-//#####################################################################################################################//\r
-\r
-\r
-//######################################### CREATE_Entity_Json(node,connection,flow)###################################//\r
-function find_node_id(node_name)\r
-{\r
-       var SI_name = jQuery(".NE_up #sel_1").children('option:selected').val();\r
-       for (var find_cursor = 0; find_cursor<localStorage.length;find_cursor++)\r
-       {\r
-               if(localStorage.key(find_cursor).indexOf(SI_name+'__') == -1)\r
-                       continue;\r
-               else if(localStorage.key(find_cursor).indexOf('node_') > -1 )\r
-               {\r
-                       var find_json_temp = jQuery.parseJSON(localStorage.getItem(localStorage.key(find_cursor)));\r
-                       for(var key in find_json_temp)\r
-                       {\r
-                               if(find_json_temp[key]["node_name"] == node_name)\r
-                                       return find_json_temp[key]["node_id"];\r
-                       }\r
-               }       \r
-       }\r
-       alert("no node id name match!!!");\r
-}\r
-function find_flow_id(flow_name)\r
-{\r
-       var SI_name = jQuery(".NE_up #sel_1").children('option:selected').val();\r
-       for (var find_cursor = 0; find_cursor<localStorage.length;find_cursor++)\r
-       {\r
-               if(localStorage.key(find_cursor).indexOf(SI_name+'__') == -1)\r
-                       continue;\r
-               else if(localStorage.key(find_cursor).indexOf('__flow_') > -1 )\r
-               {\r
-                       var find_json_temp = jQuery.parseJSON(localStorage.getItem(localStorage.key(find_cursor)));\r
-                       for(var key in find_json_temp)\r
-                       {\r
-                               if(find_json_temp[key]["flow_name"] == flow_name)\r
-                                       return find_json_temp[key]["flow_id"];\r
-                       }\r
-               }       \r
-       }\r
-       alert("no flow id name match!!!");\r
-}\r
-\r
-function tran_tojson_node(node_data)\r
-{\r
-       var node_json;\r
-       console.log(node_data);\r
-       var host_subnode=[];//sub node \r
-\r
-       node_json = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'",';\r
-       node_json += '"objects":{"node":[{"node-id":"'+node_data["node_id"]+'","node-name":"'+node_data["node_name"]+'","node-type":"'+node_data["node_type"]+'"';\r
-       \r
-       if(node_data["sub-node"] != null && node_data["sub-node"]["sub-node"].length > 0)\r
-       {\r
-               node_json += ',"sub-node":[';\r
-               var sub_count = 0;\r
-               for(var value in node_data["sub-node"]["sub-node"])\r
-               {\r
-                       if(host_id[node_data["sub-node"]["sub-node"][value].split(":")[1]] != null)\r
-                       {\r
-                               host_subnode.push(node_data["sub-node"]["sub-node"][value].split(":")[1]);\r
-                       }\r
-                       var id_temp;\r
-                       //node_json += '{"node-id":"'+host_id[node_data["sub-node"]["sub-node_host"][value]]+'"},';\r
-                       if(host_id[node_data["sub-node"]["sub-node"][value].split(":")[1]] == null && find_node_id(node_data["sub-node"]["sub-node"][value].split(":")[1]) ==null)\r
-                               continue;\r
-                       else\r
-                       {\r
-                               if (host_id[node_data["sub-node"]["sub-node"][value].split(":")[1]] != null)\r
-                                       id_temp = host_id[node_data["sub-node"]["sub-node"][value].split(":")[1]];\r
-                               else\r
-                                       id_temp = find_node_id(node_data["sub-node"]["sub-node"][value].split(":")[1]);\r
-                       }\r
-                       node_json += '{"node-id":"'+id_temp+'",';\r
-                       if(node_data["node_type"]=="chain-group")\r
-                       {\r
-                        node_json+='"order":"'+sub_count+'"},';\r
-                    }\r
-                    else\r
-                    {\r
-                        node_json+='"order":"0"},';\r
-                    }\r
-                       sub_count++;\r
-               }\r
-               if(sub_count>0)\r
-                       node_json = node_json.substring(0,node_json.length-1);\r
-               node_json += ']';\r
-       }\r
-       node_json += ',"property":[';\r
-       var property_count = 0;\r
-       for(var property_cursor in node_data["property"])\r
-       {       \r
-               if(node_data["property"][property_cursor] != '')\r
-               {\r
-                       node_json += '{"property-name":"'+property_cursor+'","property-values":{"string-value":[{"value":"'+node_data["property"][property_cursor]+'","order":"0"}]}},'\r
-                       property_count++;\r
-               }\r
-               \r
-       }\r
-       if(property_count > 0)\r
-       {\r
-               node_json = node_json.substring(0,node_json.length-1);\r
-               node_json += ']';\r
-       }\r
-       else\r
-               node_json = node_json.substring(0,node_json.length-13);\r
-\r
-       node_json += '}]}}}';\r
-       console.log(node_json);\r
-    \r
-    var host_json_str=[];\r
-       for(i in host_subnode){\r
-       var host_json = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'",';\r
-        host_json += '"objects":{"node":[{"node-id":"'+host_id[host_subnode[i]]+'","node-name":"'+host_subnode[i]+'","node-type":"host"}]}';\r
-        host_json +="}}";\r
-        host_json_str.push(host_json)\r
-       }\r
-       host_json_str.push(node_json);\r
-\r
-       return host_json_str;\r
-}\r
-\r
-function tran_tojson_connection(connection_data)\r
-{\r
-       var connection_json;\r
-       \r
-       connection_json = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'",';\r
-       connection_json += '"objects":{"connection":[{"connection-id":"'+connection_data["connection_id"]+'","connection-name":"'+connection_data["connection_name"]+'","connection-type":"'+connection_data["connection_type"]+'",';\r
-       \r
-\r
-       if(connection_data["connection_type"] == 'p2p')\r
-       {\r
-       var para1 = connection_data["End-nodes"]["one_node_name"].split(":");\r
-       var c1="";\r
-         if(para1.length>1)\r
-               {\r
-                       c1=para1[1];\r
-                }\r
-                else{\r
-            c1=para1[0];\r
-                }\r
-     \r
-     var para2 = connection_data["End-nodes"]["other_node_name"].split(":");\r
-         var c2="";\r
-          if(para1.length>1)\r
-               {\r
-                       c2=para2[1];\r
-                }\r
-                else{\r
-            c2=para2[0];\r
-                }\r
-               connection_json += '"end-node":[ {"node-id":"'+find_node_id(c1)+'","order":"0"},{"node-id":"'+find_node_id(c2)+'","order":"0"}';\r
-       }\r
-       else if(connection_data["connection_type"] == 'p2mp') \r
-       {\r
-               var para1 = connection_data["End-nodes"]["one_node_name"].split(":");\r
-           var c1="";\r
-           if(para1.length>1)\r
-                 {\r
-                       c1=para1[1];\r
-                  }\r
-                 else{\r
-            c1=para1[0];\r
-                  }\r
-     \r
-         var para2 =connection_data["End-nodes"]["other_node_name"][p2mp_cursor].split(":");\r
-            var c2="";\r
-           if(para1.length>1)\r
-               {\r
-                       c2=para2[1];\r
-                }\r
-                else{\r
-            c2=para2[0];\r
-                 }\r
-\r
-               connection_json += '"end-node":[{"node-id":"'+find_node_id(c1)+'","order":"0"},';\r
-               for(var p2mp_cursor in connection_data["End-nodes"]["other_node_name"])\r
-               {\r
-                       connection_json += '{"node-id":"'+find_node_id(c2)+'","order":"0"},';\r
-               }\r
-               connection_json = connection_json.substring(0,connection_json.length-1);\r
-       }\r
-       else if(connection_data["connection_type"] == 'mesh')\r
-       {\r
-               var para1 = connection_data["node"][mesh_cursor].split(":");\r
-           var c1="";\r
-           if(para1.length>1)\r
-                 {\r
-                       c1=para1[1];\r
-                  }\r
-                 else{\r
-            c1=para1[0];\r
-                  }\r
-               connection_json += '"end-node":[';\r
-               for(var mesh_cursor in connection_data["node"])\r
-               {\r
-                       connection_json += '{"node-id":"'+find_node_id(c1)+'","order":"0"},';\r
-               }\r
-               connection_json = connection_json.substring(0,connection_json.length-1);\r
-       }       \r
-       else if(connection_data["connection_type"] == 'chain')\r
-       {\r
-               connection_json += '"end-node":[';\r
-               for(var chain_cursor in connection_data["node"])\r
-               {\r
-                       connection_json += '{"node-id":"'+find_node_id(connection_data["node"][chain_cursor].split(":")[1])+'","order":"0"},';\r
-               }\r
-               connection_json = connection_json.substring(0,connection_json.length-1);\r
-       }               \r
-\r
-       connection_json += ']';\r
-\r
-       \r
-       if(connection_data["property"]["bandwidth"]!="")\r
-       {\r
-       connection_json +=',"property":[';\r
-    }\r
-       for(var key in connection_data["property"])\r
-       {\r
-\r
-               if(connection_data["property"][key] != '')\r
-                       connection_json += '{"property-name":"'+key+'","property-values":{"int-value":[{"value":"'+connection_data["property"][key]+'","order":"0"}]}},';\r
-               \r
-       }\r
-       connection_json = connection_json.substring(0,connection_json.length-1);\r
-       connection_json += ']}]}}}';\r
-       console.log(connection_json);\r
-       return connection_json;\r
-}\r
-\r
-function tran_tojson_flow(flow_data)\r
-{\r
-       var flow_json;\r
-       \r
-       flow_json = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'",';\r
-       flow_json += '"objects":{"flow":[{"flow-id":"'+flow_data["flow_id"]+'","flow-name":"'+flow_data["flow_name"]+'","match-item":[';\r
-       for(var key in flow_data["match_items"])\r
-       {\r
-               if(flow_data["match_items"][key] != '')\r
-                       flow_json += '{"match-item-name":"'+key+'","match-item-value":{"string-value":"'+flow_data["match_items"][key]+'"}},';\r
-       }\r
-       flow_json = flow_json.substring(0,flow_json.length-1);\r
-       flow_json += ']}]}}}';\r
-       console.log(flow_json);\r
-       return flow_json;\r
-}\r
-//#####################################################################################################################//\r
-\r
-\r
-\r
-/* function test()\r
-{\r
-       console.log(tran_tojson_user());\r
-       tran_tojson_delete('c0ae82a9-8fa0-9ab2-4bff-8c2151160201');\r
-       tran_tpjson_entity('{"mms__node_inet1":{"Entity_Type":"node","node_id":"c0ae82a9-8fa0-9ab2-4bff-8c2151160201","node_name":"inet1","node_type":"internet","property":{"location":"WAN_port1","ipprefix":"asdas"}}}');\r
-    tran_tpjson_entity('{"mms__connection_conn1":{"Entity_Type":"connection","connection_id":"eb307116-dc28-a84c-5539-62cb0cac9516","connection_name":"conn1","connection_type":"p2p","End-nodes":{"one_node_name":"inet","other_node_name":"inet1"},"property":{"bandwidth":"21","latency":"","Jitter":""}}}');\r
-       tran_tpjson_entity('{"mms__flow_f3":{"Entity_Type":"flow","flow_id":"41cf1ba9-2ab9-f91a-30ec-d1f0e29553c7","flow_name":"f3","match_items":{"src_node":"g1","dest_node":"inet","src_ip":"","dest_ip":"","src_port":"","dest_port":"","protocol":"","vlanid":"30","bidirect":"true"}}}');\r
-} */\r
diff --git a/nemo-ui/src/main/resources/nemo/js/Nemo_Annouce_vis.js b/nemo-ui/src/main/resources/nemo/js/Nemo_Annouce_vis.js
deleted file mode 100644 (file)
index dffa4d3..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-//////////////////////////////////////////zm//////////////////////////////////////////////////
-       
-    var ne_flag=0;
-       // Node_List = a[Node_Id][x](x = 0,label;x = 1,title;x = 2,P2mpGroupId)
-    var Node_List = new Array();
-       // Edge_List = b[Edge_Id][y](y = 0,connection name;y = 1,from;y = 2,to)
-    var Edge_List = new Array();
-       
-       var node_count=0;
-       var node_X=[];
-
-    var conn_Item=[];
-       
-       var vlandata1;
-
-
-/////////////Main Data//////////////
-       var nodes, edges, graph;
-    var Node_Id = 0;
-    var Edge_Id = 0;   
-       var Edge_Count=0;
-
-       
-       var Node_Sp=[];
-       var Node_Sp_Id=[];
-       var Node_Sc=[];
-       var Node_Sc_Id=[];
-       var policy_count=[];
-       var policy_set=[];
-    var chain_count=[];
-       var chain_set=[];
-       var conn_set=[];
-       
-
-       //flow
-       var flow_count = [];
-       var ext_ip = [];                        
-       
-    // create an array with nodes
-    nodes = new vis.DataSet();
-       
-       
-
-       
-    // create an array with edges
-    edges = new vis.DataSet();
-
-/////////////P2mp Group Data//////////////
-       var Group_Id = 0;
-       var Group_List= new Array();
-       
-    var options = {
-               stabilize: true,
-               //Manipulation:true,
-               //hierarchicalLayout: true,
-               nodes: {
-          // default for all nodes
-                       shape: 'dot', 
-                       fontSize:16     ,
-                       radius:16,
-                       fixed:true
-               },
-               edges: {
-               smooth: false
-                       //length:1
-               },
-        groups: {
-                null: {
-            color: {
-              border: 'white',
-              background: 'white',
-              highlight: {
-                border: 'white',
-                background: '#white'
-              }
-            },
-            fontSize: 0,
-                       radius:0,
-            //fontFace: 'arial',
-            shape: 'dot'
-          },
-          host: {
-            color: {
-              border: 'black',
-              background: '#B0E2FF',
-              highlight: {
-                border: 'black',
-                background: '#4F94CD'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-          firewall: {  
-            color: {
-              border: 'black',
-              background: '#FF0000',
-              highlight: {
-                border: 'black',
-                background: '#FF7256'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-                 internet: {
-            color: {
-              border: 'black',
-              background: '#7FFF00',
-              highlight: {
-                border: 'black',
-                background: '#6B8E23'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-          forwarding: {
-            color: {
-              border: 'black',
-              background: '#878787',
-              highlight: {
-                border: 'black',
-                background: '#4A4A4A'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-                  loadbalance: {
-            color: {
-              border: '#black',
-              background: '#FF9933',
-              highlight: {
-                border: 'black',
-                background: '#FDCEBF'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-                  group: {
-            color: {
-              border: 'black',
-              background: 'yellow',
-              highlight: {
-                border: 'black',
-                background: '#ECE5D0'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          }
-        }
-               
-       };
-       
-       
-
-       // used in Service_Policy
-var options2 = {
-               stabilize: false,
-               //Manipulation:true,
-               //hierarchicalLayout: true,
-               nodes: {
-          // default for all nodes
-                       shape: 'dot', 
-                       fontSize:16     ,
-                       radius:16,
-                       fixed:true
-               },
-               edges: {
-               smooth: false
-                       //length:1
-               },
-        groups: {
-                       null: {
-            color: {
-              border: 'white',
-              background: 'white',
-              highlight: {
-                border: 'white',
-                background: '#white'
-              }
-            },
-            fontSize: 0,
-                       radius:0,
-            //fontFace: 'arial',
-            shape: 'dot'
-          },
-          host: {
-            color: {
-              border: 'black',
-              background: '#B0E2FF',
-              highlight: {
-                border: 'black',
-                background: '#4F94CD'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-          firewall: {  
-            color: {
-              border: 'black',
-              background: '#FF0000',
-              highlight: {
-                border: 'black',
-                background: '#FF7256'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-                 internet: {
-            color: {
-              border: 'black',
-              background: '#7FFF00',
-              highlight: {
-                border: 'black',
-                background: '#6B8E23'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-          forwarding: {
-            color: {
-              border: 'black',
-              background: '#878787',
-              highlight: {
-                border: 'black',
-                background: '#4A4A4A'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-                  loadbalance: {
-            color: {
-              border: '#black',
-              background: '#FF9933',
-              highlight: {
-                border: 'black',
-                background: '#FDCEBF'
-              }
-            },
-            fontSize: 15,
-                       radius:15,
-            fontFace: 'arial',
-            shape: 'dot'
-          },
-                  group: {
-            color: {
-              border: 'black',
-              background: 'yellow',
-              highlight: {
-                border: 'black',
-                background: '#ECE5D0'
-              }
-            },
-                       fontSize: 15,
-                       radius:15,
-                 
-        }
-               },
-       physics: {
-      repulsion: {
-        centralGravity: 0,
-        springLength: 100,//弹簧长度
-        springConstant: 0,//弹簧常数
-        nodeDistance: 0,
-        damping: 0 //阻尼,减幅,衰减
-      }}
-               
-       };
-       
-
-    var DOMURL = window.URL || window.webkitURL || window;     
-       var nemoModule = [
-                        /* no host in mode */
-                        '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" opacity="1">' +
-                        '<circle cx="100" cy="100" r="95" stroke-width="2" stroke="#000000" fill="#FFFFFF" opacity="1"/>'+
-                        '</svg>',
-                        /* 1 host in mode */
-                                               '<svg xmlns="http://www.w3.org/2000/svg" width="300" height="235" opacity="1">' +
-                                               '<circle cx="130" cy="140" r="80" stroke-width="5" stroke="#000000" fill="#FFFFFF" opacity="1"/>\
-                                               <circle cx="130" cy="140" r="40"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="20" y="100" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml">\
-                                               <span style="padding-left:65px; padding-top:100px; color:black; font-size:25px;">\
-                                               {{host1}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               </svg>',
-                        /* 2 hosts in mode */
-                        '<svg xmlns="http://www.w3.org/2000/svg" width="300" height="235" opacity="1">' +
-                                               '<circle cx="150" cy="150" r="80" stroke-width="5" stroke="#000000" fill="#FFFFFF" opacity="1"/>\
-                                               <circle cx="115.5" cy="150" r="35"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="20" y="100" width="50%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml">\
-                                               <span style="padding-left:65px; padding-top:100px; color:black; font-size:25px;">\
-                                               {{host1}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               <circle cx="155" cy="150" r="35"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="140" y="140" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">\
-                                               <span style="padding-left:15px; color:black; font-size:25px;">\
-                                               {{host2}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               </svg>',
-                        /* 3 hosts in mode */
-                        '<svg xmlns="http://www.w3.org/2000/svg" width="300" height="235" opacity="1">\
-                                               <circle cx="150" cy="150" r="80" stroke-width="5" stroke="#153345" fill="#FFFFFF" opacity="1"/>\
-                                               <circle cx="150" cy="110" r="32"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="85" y="90" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml" >\
-                                               <span style="padding-left:50px; color:black; font-size:25px;">\
-                                               {{host1}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               <circle cx="110" cy="170" r="32"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="45" y="160" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml">\
-                                               <span style="padding-left:50px; color:black; font-size:25px;">\
-                                               {{host2}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               <circle cx="190" cy="170" r="32"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="130" y="150" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml">\
-                                               <span style="padding-left:50px; color:black; font-size:25px;">\            {{host3}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               </svg>' ,
-                        /* 4 hosts in mode */
-                        '<svg xmlns="http://www.w3.org/2000/svg" width="300" height="235" opacity="1">' +
-                                               '<circle cx="130" cy="140" r="80" stroke-width="5" stroke="#000000" fill="#FFFFFF" opacity="1"/>\
-                                               <circle cx="100" cy="110" r="30"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="20" y="100" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml">\
-                                               <span style="padding-left:65px; padding-top:100px; color:black; font-size:25px;">\
-                                               {{host1}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               <circle cx="100" cy="170" r="30"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="20" y="140" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">\
-                                               <span style="padding-left:15px; color:black; font-size:25px;">\
-                                               {{host3}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               <circle cx="160" cy="110" r="30"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="150" y="80" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">\
-                                               <span style="padding-left:15px; color:black; font-size:25px;">\
-                                               {{host2}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               <circle cx="160" cy="170" r="30"  stroke-width="2" stroke="red" fill="#FFFFFF"></circle>\
-                                               <foreignObject x="150" y="140" width="40%" height="20%">\
-                                               <div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">\
-                                               <span style="padding-left:15px; color:black; font-size:25px;">\
-                                               {{host4}}</span>\
-                                               </div>\
-                                               </foreignObject>\
-                                               </svg>',
-                        /* more than 4 hosts in mode */
-                        '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="235" opacity="1">' +
-                        '<circle cx="100" cy="100" r="95" stroke-width="2" stroke="#000000" fill="#FFFFFF" opacity="1"/>'+
-                        '<rect x="40" y="38" width="30%" height="30%" stroke-width="2" stroke="#000000" fill="#FFFFFF"></rect>' +
-                        '<foreignObject x="15" y="55" width="40%" height="20%">' +
-                        '<div xmlns="http://www.w3.org/1999/xhtml" >' +
-                        '<span style="padding-left:40px;color:black; font-size:20px;">' +
-                        '{{host1}}</span>' +
-                        '</div>' +
-                        '</foreignObject>' +
-                        '<rect x="40" y="108" width="30%" height="30%" stroke-width="2" stroke="#000000" fill="#FFFFFF"></rect>' +
-                        '<foreignObject x="15" y="155" width="40%" height="20%">' +
-                        '<div xmlns="http://www.w3.org/1999/xhtml">' +
-                        '<span style="padding-left:40px;color:black; font-size:20px;">' +
-                        '{{host2}}</span>' +
-                        '</div>' +
-                        '</foreignObject>' +
-                        '<rect x="108" y="38" width="30%" height="30%" stroke-width="2" stroke="#000000" fill="#FFFFFF"></rect>' +
-                        '<foreignObject x="105" y="55" width="40%" height="20%">' +
-                        '<div xmlns="http://www.w3.org/1999/xhtml">' +
-                        '<span style="padding-left:20px; color:black; font-size:20px;">' +
-                        '{{host3}}</span>' +
-                        '</div>' +
-                        '</foreignObject>' +
-                        '<rect x="108" y="108" width="30%" height="30%" stroke-width="0" stroke="#000000" fill="#FFFFFF"></rect>' +
-                        '<foreignObject x="105" y="155" width="40%" height="20%">' +
-                        '<div xmlns="http://www.w3.org/1999/xhtml">' +
-                        '<span style="padding-left:20px; color:black; font-size:20px;">' +
-                        '...</span>' +
-                        '</div>' +
-                        '</foreignObject>' +
-                        '</svg>'];
-//function
-function draw(node_count,node_mash_list) {
-
-}
-       function calculatePos(n){
-                       var res = new Array();
-                       if(n <= 0)return res;
-                       var start;
-                       var offset = 2 * Math.PI / n;
-                       if(n % 2 == 1){
-                               start = Math.PI / 2;
-                       }else{
-                               start = Math.PI / 2 + Math.PI / n;
-                       }
-                       res.push(start);
-                       for(var i = 1; i < n; i++){
-                               start += offset;
-                               res.push(start);
-                       }
-                       return res;
-               }
-
-                                               
-                                               
-                                               
-//////////////////////////////////////////zm//////////////////////////////////////////////////
diff --git a/nemo-ui/src/main/resources/nemo/js/Nemo_Main.js b/nemo-ui/src/main/resources/nemo/js/Nemo_Main.js
deleted file mode 100644 (file)
index 67c965c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/// <reference path="_references.js" />\r
-var phy_hosts=[];\r
-\r
-jQuery.noConflict();\r
-jQuery(document).ready(function ($) {\r
-     //localStorage.clear();\r
-    $("#net_ent_init,#ser_poc_init,#advance_query").hide();\r
-   \r
-    $(".btn_item").click(function () {\r
-        index = $(".btn_item").index($(this));\r
-        if (index == 0 || index == 5)\r
-        {\r
-            flag = true;\r
-            $("#net_ent_init,#ser_poc_init,#advance_query").hide();\r
-        }\r
-        if ($(this).hasClass("btn_item_click") == false) {\r
-            $(this).siblings("button").removeClass("btn_item_click").addClass("btn_item_none");\r
-            $(this).removeClass("btn_item_none").addClass("btn_item_click");\r
-\r
-            $(".btn_item_show").hide();\r
-            $(".btn_item_show").eq(index).show();\r
-\r
-        }\r
-        else {\r
-            $(this).removeClass("btn_item_click").addClass("btn_item_none");\r
-            $(".btn_item_show").hide();\r
-        }\r
-               if(index == 5 )\r
-               {\r
-            document.getElementById("service_svg").style.display = "none";\r
-                       document.getElementById("service_svg2").style.display = "none";\r
-            document.getElementById("graph").style.display = "";\r
-               }\r
-               else{\r
-                       jQuery("#service_svg2").empty();\r
-            document.getElementById("service_svg").style.display = "";\r
-                       document.getElementById("service_svg2").style.display = "none";\r
-            document.getElementById("graph").style.display = "none";\r
-               }\r
-        //hide service instance\r
-        $("#ser_init").hide();\r
-    });\r
-    $(".btn_item_show .close_item_show img").click(function () {\r
-        $(".btn_item").removeClass("btn_item_click").addClass("btn_item_none");\r
-        $(".btn_item_show").hide();\r
-    });\r
-\r
-   var flag=true;\r
-    $("#nemo-business-model").click(function(){\r
-     if(flag)\r
-     {\r
-        flag=false;\r
-        $("#net_ent_init,#ser_poc_init,#advance_query").show();\r
-        $(".btn_item_show").hide();\r
-     }   \r
-     else\r
-      {\r
-       flag=true;\r
-       $("#net_ent_init,#ser_poc_init,#advance_query").hide();\r
-       $(".btn_item_show").hide();\r
-      }\r
-      $("#advance_query").hide();//hide advance query\r
-     });\r
-\r
-    $("#nemo-business-model").show();\r
-    $("#tabs").tabs();\r
-    $("#show_status").hide();\r
-    $("#nemo-business-model").hide();\r
-    $("#submit").hide();\r
-\r
-    //get physical topo\r
-    // $("#nemo-business-model").click(function(){\r
-    // $("#query_topo").click();\r
-    // })\r
-});\r
-\r
-\r
diff --git a/nemo-ui/src/main/resources/nemo/js/Nemo_Order.js b/nemo-ui/src/main/resources/nemo/js/Nemo_Order.js
deleted file mode 100644 (file)
index 33775d6..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-jQuery(document).ready(function ($) {\r
-       var policy_set=[];\r
-       var order_html=[];\r
-       var order_doc=[];\r
-$("#submit").click(function(){\r
-       \r
-        // var service_name = $(".NE_up #sel_1").children('option:selected').val();    \r
-        // if(service_name == "news_hotline" || service_name == "s1")\r
-        // {\r
-               //  var entity = service_name + "__" + "policy_"+document.getElementById("policy_name_list").options[0].text;\r
-               //  var policy_json_str=localStorage.getItem(entity);\r
-               //  var policy_json = jQuery.parseJSON(policy_json_str);\r
-               //  var flow_id = policy_json[entity]["apply_entity_id"];\r
-               //  var json_str_temp = localStorage.getItem(entity.substr(0,4)+flow_id.replace(":","_"));\r
-               //  var json_temp = jQuery.parseJSON(json_str_temp);\r
-               //  var vlanid = json_temp[entity.substr(0,4)+flow_id.replace(":","_")]["match_items"]["vlanid"];\r
-               //  vlandata1 = vlanid.toString();\r
-        // }\r
-\r
-       /* var entity_set = new Array();\r
-       var json_data = jQuery.parseJSON(json_str);\r
-\r
-       var service_name = $(".NE_up #sel_1").children('option:selected').val();        \r
-       for(var i = 0;i<document.getElementById("policy_name_list").length;i++)\r
-       {\r
-               var entity = service_name + "__" + "policy_"+document.getElementById("policy_name_list").options[i].text;\r
-               entity_set[i]=entity;\r
-               policy_set[i]=localStorage.getItem(entity);\r
-\r
-       }\r
-       for(var i = 0;i<document.getElementById("policy_name_list").length;i++)\r
-       {\r
-               var json_str_temp,json_temp;\r
-               var policy_json = jQuery.parseJSON(policy_set[i]);\r
-               var flow_id = policy_json[entity_set[i]]["apply_entity_id"];\r
-               json_str_temp = localStorage.getItem(entity_set[i].substr(0,4)+flow_id.replace(":","_"));\r
-               json_temp = jQuery.parseJSON(json_str_temp);\r
-               //alert(entity_set[i].substr(0,4)+flow_id.replace(":","_"));\r
-               var src_id = json_temp[entity_set[i].substr(0,4)+flow_id.replace(":","_")]["match_items"]["src_node"];\r
-               var dest_id = json_temp[entity_set[i].substr(0,4)+flow_id.replace(":","_")]["match_items"]["dest_node"];\r
-               json_str_temp = localStorage.getItem(entity_set[i].substr(0,4)+"node_"+src_id.replace(":","_"));\r
-               json_temp = jQuery.parseJSON(json_str_temp);\r
-               var src_type = json_temp[entity_set[i].substr(0,4)+"node_"+src_id.replace(":","_")]["node_type"];\r
-               var src_location = json_temp[entity_set[i].substr(0,4)+"node_"+src_id.replace(":","_")]["property"]["location"];\r
-               json_str_temp = localStorage.getItem(entity_set[i].substr(0,4)+"node_"+dest_id.replace(":","_"));\r
-               json_temp = jQuery.parseJSON(json_str_temp);\r
-               var dest_type = json_temp[entity_set[i].substr(0,4)+"node_"+dest_id.replace(":","_")]["node_type"];\r
-               var dest_location = json_temp[entity_set[i].substr(0,4)+"node_"+dest_id.replace(":","_")]["property"]["location"];\r
-        for(var s2 =0;s2<json_data["physical-network"]["nodes"]["node"].length;s2++)\r
-               {\r
-                       for(var s3=0;s3<json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"].length;s3++)\r
-                       {                               \r
-                               if(json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"][s3]["location"] == src_location)\r
-                               {\r
-                                       var node_name = json_data["physical-network"]["nodes"]["node"][s2]["node-id"];\r
-                                       order_doc[node_name] = "";\r
-                                       for(var s4=0;s4<json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"].length;s4++)\r
-                                       {\r
-                                               var interface_temp = json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"][s4];\r
-                                               order_doc[node_name] += "interface "+interface_temp["interface-type"]+interface_temp["interface-number"]+"<br>";\r
-                                               if(src_type == "group")\r
-                                               order_doc[node_name] += "undo portswitch<br>";\r
-                                               order_doc[node_name] += "description"+interface_temp["description"]+"<br>";\r
-                                               order_doc[node_name] += "ip address"+interface_temp["ip-address"]+" "+interface_temp["mask"]+"<br><br>";\r
-                                       }                                       \r
-                               }                                                       \r
-                       }       \r
-               }\r
-               for(var s2 =0;s2<json_data["physical-network"]["nodes"]["node"].length;s2++)\r
-               {\r
-                       for(var s3=0;s3<json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"].length;s3++)\r
-                       {                               \r
-                               if(json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"][s3]["location"] == dest_location)\r
-                               {\r
-                                       var node_name = json_data["physical-network"]["nodes"]["node"][s2]["node-id"];\r
-                                       order_doc[node_name] = "";\r
-                                       for(var s4=0;s4<json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"].length;s4++)\r
-                                       {\r
-                                               var interface_temp = json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"][s4];\r
-                                               order_doc[node_name] += "interface "+interface_temp["interface-type"]+interface_temp["interface-number"]+"<br>";\r
-                                               if(dest_type == "group")\r
-                                               order_doc[node_name] += "undo portswitch<br>";\r
-                                               order_doc[node_name] += "description"+interface_temp["description"]+"<br>";\r
-                                               order_doc[node_name] += "ip address"+interface_temp["ip-address"]+" "+interface_temp["mask"]+"<br><br>";\r
-                                       }                                       \r
-                               }                                                       \r
-                       }       \r
-               }\r
-               if(policy_json[entity_set[i]]["action"] == "SFC")\r
-               {\r
-                       var chain_list = policy_json[entity_set[i]]["chain_node_list"];\r
-            if(chain_list !=null && chain_list.length == 1)\r
-                       {\r
-                               var firewall_id = json_data["physical-network"]["nodes"]["firewall-resource"]["firewall-id"];\r
-                               for(var s2 =0;s2<json_data["physical-network"]["nodes"]["node"].length;s2++)\r
-                               {\r
-                                       if(json_data["physical-network"]["nodes"]["node"][s2]["node-id"] == firewall_id)\r
-                                       {\r
-                                               var node_name = json_data["physical-network"]["nodes"]["node"][s2]["node-id"];\r
-                                           order_doc[node_name] = "";\r
-                                           for(var s4=0;s4<json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"].length;s4++)\r
-                                           {\r
-                                                   var interface_temp = json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"][s4];\r
-                                                   order_doc[node_name] += "interface "+interface_temp["interface-type"]+interface_temp["interface-number"]+"<br>";\r
-                                                   order_doc[node_name] += "description"+interface_temp["description"]+"<br>"\r
-                                                   order_doc[node_name] += "ip address"+interface_temp["ip-address"]+" "+interface_temp["mask"]+"<br><br>";\r
-                                           }                           \r
-                                       }                               \r
-                               }                       \r
-                       }\r
-                       else if(chain_list !=null && chain_list.length > 1)\r
-                       {\r
-                               var json_str_temp,json_temp;\r
-                               for(var z=0;z<chain_list.length;z++)\r
-                               {\r
-                                       json_str_temp = localStorage.getItem(entity_set[i].substr(0,4)+"node_"+chain_list[z]);\r
-                           json_temp = jQuery.parseJSON(json_str_temp);\r
-                                       if(json_temp[entity_set[i].substr(0,4)+"node_"+chain_list[z]]["node_type"] == "loadbalance")\r
-                                       {\r
-                                               var loadbalance_id = json_data["physical-network"]["nodes"]["LB-resource"]["LB-id"];\r
-                                       for(var s2 =0;s2<json_data["physical-network"]["nodes"]["node"].length;s2++)\r
-                                       {\r
-                                                if(json_data["physical-network"]["nodes"]["node"][s2]["node-id"] == loadbalance_id)\r
-                                                {\r
-                                                       var node_name = json_data["physical-network"]["nodes"]["node"][s2]["node-id"];\r
-                                                   order_doc[node_name] = "";\r
-                                                   for(var s4=0;s4<json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"].length;s4++)\r
-                                                   {\r
-                                                            var interface_temp = json_data["physical-network"]["nodes"]["node"][s2]["interfaces"]["interface"][s4];\r
-                                                            order_doc[node_name] += "interface "+interface_temp["interface-type"]+interface_temp["interface-number"]+"<br>";\r
-                                                            order_doc[node_name] += "description"+interface_temp["description"]+"<br>"\r
-                                                            order_doc[node_name] += "ip address"+interface_temp["ip-address"]+" "+interface_temp["mask"]+"<br><br>";\r
-                                                    }                          \r
-                                                }                              \r
-                                       }               \r
-                                       }\r
-       \r
-                               }                               \r
-                       }\r
-               }\r
-       }  */\r
-       //alert("Successfully Submitted!");\r
-       \r
-});\r
-  /* $("#display_info").click(function(){\r
-         var json_data = jQuery.parseJSON(json_str);\r
-         for(var y=0;y<json_data["physical-network"]["nodes"]["node"].length;y++)\r
-       {\r
-               var node_id = json_data["physical-network"]["nodes"]["node"][y]["node-id"];\r
-               if(order_doc[node_id] != null)\r
-               {\r
-                       \r
-                       document.getElementById("order").innerHTML += node_id + "  orders: <br>";\r
-                       document.getElementById("order").innerHTML += order_doc[node_id]+"<br><br>";\r
-               }\r
-       }\r
-                policy_set=[];\r
-            order_html=[];\r
-            order_doc=[];\r
-  }); */\r
-  $("#display_info").click(function(){\r
-          var service_name = $(".NE_up #sel_1").children('option:selected').val();     \r
-        if(service_name == "news_hotline" || service_name == "s1")\r
-        {\r
-                var entity = service_name + "__" + "policy_"+document.getElementById("policy_name_list").options[0].text;\r
-                var policy_json_str=localStorage.getItem(entity);\r
-                var policy_json = jQuery.parseJSON(policy_json_str);\r
-                var flow_id = policy_json[entity]["apply_entity_id"];\r
-                var json_str_temp = localStorage.getItem(entity.substr(0,4)+flow_id.replace(":","_"));\r
-                var json_temp = jQuery.parseJSON(json_str_temp);\r
-                var vlanid = json_temp[entity.substr(0,4)+flow_id.replace(":","_")]["match_items"]["vlanid"];\r
-                vlandata1 = vlanid.toString();\r
-                document.getElementById("order").innerHTML = "Command Line Configuration<br><br>\\r
-      Device: E11-CE128-5<br>\\r
-    Command lines:<br>\\r
-       interface GE1/0/46<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.4.1.1 255.255.255.0<br><br>\\r
-       interface 10GE2/0/6<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.1.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/7<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.10.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/6<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.9.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/5<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.8.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/4<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.7.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/3<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.6.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/2<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.5.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/1<br>\\r
-       undo portswitch <br>\\r
-       ip address 192.168.50.10 255.255.255.0<br><br>\\r
-       ospf 100 router-id 101.1.1.2<br>\\r
-       description NEMO-VAS<br>\\r
-       area 0.0.0.0<br>\\r
-       network 101.1.1.0 0.0.0.255<br>\\r
-       network 101.4.1.0 0.0.0.255<br><br>\\r
-       ip route-static 101.10.1.0 255.255.255.0 101.8.1.2<br><br>\\r
-       vlan batch "+vlandata1+"\\r
-       interface Vlanif "+vlandata1+"<br>\\r
-       interface GE1/0/2<br>\\r
-       port default vlan "+vlandata1+"<br><br><br>\\r
-    Device: E-LB1<br>\\r
-    Command lines:<br><br>\\r
-       interface GE2/0/6<br>\\r
-       ip address 101.6.1.2 255.255.255.0<br><br>\\r
-       interface GE2/0/7<br>\\r
-       ip address 101.5.1.2 255.255.255.0<br><br>\\r
-       ip address 192.168.50.1 255.255.255.0<br>\\r
-       ip route-static 0.0.0.0 0.0.0.0 GigabitEthernet2/0/6 101.6.1.1<br><br>\\r
-     Device: E10-Firewall<br> Command lines:<br><br>\\r
-       interface GE2/0/6<br>\\r
-       ip address 101.8.1.2 255.255.255.0<br><br>interface GE2/0/7<br>ip address 101.7.1.2 255.255.255.0<br><br>\\r
-       firewall zone trust<br>set priority 85<br>\\r
-       detect ftp<br>\\r
-       detect rtsp<br>\\r
-       detect pptp<br>\\r
-       add interface GigabitEthernet2/0/7<br><br>\\r
-       firewall zone untrust<br>\\r
-       set priority 5<br>\\r
-       detect ftp<br>\\r
-       detect rtsp<br>\\r
-       detect pptp<br>add interface GigabitEthernet2/0/6<br><br>\\r
-    firewall packet-filter default permit interzone trust untrust direction inbound<br>\\r
-       firewall packet-filter default permit interzone trust untrust direction outbound<br><br>\\r
-       nat address-group 100 101.10.1.0 101.10.1.100<br>\\r
-       nat-policy interzone trust untrust outbound<br>\\r
-       policy 0<br>\\r
-       action source-nat<br>\\r
-       policy source 192.168.50.0 0.0.0.255 <br>address-group 100<br><br>\\r
-       ip route-static 101.10.1.0 255.255.255.0 NULL0<br>ip route-static 0.0.0.0 0.0.0.0 GigabitEthernet2/0/6 101.8.1.1<br><br>\\r
-       Device: E9-NE40E-5<br>Command lines:<br><br>\\r
-       interface GigabitEthernet2/0/15<br>\\r
-       undo shutdown<br>\\r
-       ip address 101.2.1.1 255.255.255.0<br><br>\\r
-       interface GigabitEthernet2/0/19<br>\\r
-       undo shutdown<br>\\r
-       ip address 101.1.1.1 255.255.255.0<br><br>\\r
-       interface GigabitEthernet2/0/1<br>\\r
-       undo shutdown<br>\\r
-       ip address 10.1.1.2 255.255.255.0<br><br>\\r
-       ospf 100 router-id 101.1.1.1<br>\\r
-       description NEMO-VAS<br>\\r
-       area 0.0.0.0<br>\\r
-       network 101.1.1.0 0.0.0.255<br>network 101.2.1.0 0.0.0.255<br><br>\\r
-       ";\r
-        }\r
-        else if(service_name == "s2" || service_name == "mms")\r
-        {\r
-                var vlandata = [];\r
-                for(var i =0 ;i<3;i++)\r
-                {\r
-                         var entity = service_name + "__" + "policy_"+document.getElementById("policy_name_list").options[i].text;\r
-                     var policy_json_str=localStorage.getItem(entity);\r
-                     var policy_json = jQuery.parseJSON(policy_json_str);\r
-                     var flow_id = policy_json[entity]["apply_entity_id"];\r
-                     var json_str_temp = localStorage.getItem(entity.substr(0,4)+flow_id.replace(":","_"));\r
-                     var json_temp = jQuery.parseJSON(json_str_temp);\r
-                     var vlanid = json_temp[entity.substr(0,4)+flow_id.replace(":","_")]["match_items"]["vlanid"];\r
-                         var dest = json_temp[entity.substr(0,4)+flow_id.replace(":","_")]["match_items"]["dest_node"];\r
-                         json_str_temp = localStorage.getItem(entity.substr(0,4)+"node_"+dest);\r
-                         json_temp = jQuery.parseJSON(json_str_temp);            \r
-                     if(json_temp[entity.substr(0,4)+"node_"+dest]["property"]["location"] == "access_port2") \r
-                                 vlandata["access_port2"] = vlanid;\r
-                         else if(json_temp[entity.substr(0,4)+"node_"+dest]["property"]["location"] == "access_port3")\r
-                             vlandata["access_port3"] = vlanid;\r
-                         else\r
-                                 vlandata["loadbalance"] = vlanid;\r
-                }\r
-                document.getElementById("order").innerHTML ="Command Line Configuration<br><br>Command lines:<br>\\r
-       interface GE1/0/46<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.4.1.1 255.255.255.0<br><br>\\r
-       interface 10GE2/0/6<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.1.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/7<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.10.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/6<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.9.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/5<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.8.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/4<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.7.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/3<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.6.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/2<br>\\r
-       undo portswitch<br>\\r
-       ip address 101.5.1.1 255.255.255.0<br><br>\\r
-       interface GE1/0/1<br>\\r
-       undo portswitch <br>\\r
-       ip address 192.168.50.10 255.255.255.0<br><br>\\r
-       ospf 100 router-id 101.1.1.2<br>\\r
-       description NEMO-VAS<br>\\r
-       area 0.0.0.0<br>\\r
-       network 101.1.1.0 0.0.0.255<br>\\r
-       network 101.4.1.0 0.0.0.255<br><br>\\r
-       vlan batch "+vlandata["access_port2"]+" "+vlandata["access_port3"]+" "+vlandata["loadbalance"]+"<br><br>\\r
-       interface Vlanif "+vlandata["access_port2"]+"<br>\\r
-       interface Vlanif "+vlandata["access_port3"]+"<br>\\r
-       interface Vlanif "+vlandata["loadbalance"]+"<br><br>\\r
-       interface GE1/0/2<br>\\r
-       port trunk allow-pass vlan "+vlandata["loadbalance"]+"<br><br>\\r
-       interface GE1/0/4<br>\\r
-       port trunk allow-pass vlan "+vlandata["access_port2"]+" "+vlandata["access_port3"]+" "+vlandata["loadbalance"]+"<br><br>\\r
-       interface GE1/0/6<br>\\r
-       port trunk allow-pass vlan "+vlandata["access_port2"]+"<br><br>\\r
-       interface GE1/0/7<br>\\r
-       port trunk allow-pass vlan "+vlandata["access_port3"]+"<br><br>\\r
-       ip ip-prefix prefix-a index 10 permit 101.9.1.0 24<br>\\r
-       route-policy policy1 permit node 10<br>\\r
-       apply ip-address next-hop 10.9.1.2<br><br>\\r
-       ip ip-prefix prefix-a index 11 permit 101.10.1.0 24<br>\\r
-       route-policy policy1 permit node 11<br>\\r
-       apply ip-address next-hop 10.10.1.2<br><br>\\r
-Device: E-LB1<br>\\r
-Command lines:<br><br>\\r
-       interface GE2/0/6<br>\\r
-       ip address 101.6.1.2 255.255.255.0<br><br>\\r
-       interface GE2/0/7<br>\\r
-       ip address 101.5.1.2 255.255.255.0<br><br>\\r
-       ip address 192.168.50.1 255.255.255.0<br>\\r
-       ip route-static 0.0.0.0 0.0.0.0 GigabitEthernet2/0/6 101.6.1.1<br><br><br>\\r
-Device: E10-Firewall<br>\\r
-Command lines:<br><br>\\r
-       interface GE2/0/6<br>\\r
-       ip address 101.8.1.2 255.255.255.0<br><br>\\r
-       interface GE2/0/7<br>\\r
-       ip address 101.7.1.2 255.255.255.0<br><br>\\r
-       firewall zone trust<br>\\r
-       set priority 85<br>\\r
-       detect ftp<br>\\r
-       detect rtsp<br>\\r
-       detect pptp<br>\\r
-       add interface GigabitEthernet2/0/7<br><br>\\r
-       firewall zone untrust<br>\\r
-       set priority 5<br>\\r
-       detect ftp<br>\\r
-       detect rtsp<br>\\r
-       detect pptp<br>\\r
-       add interface GigabitEthernet2/0/6<br><br>\\r
-       firewall packet-filter default permit interzone trust untrust direction inbound<br>\\r
-       firewall packet-filter default permit interzone trust untrust direction outbound<br><br>\\r
-       nat address-group 100 101.10.1.0 101.10.1.100<br>\\r
-       nat-policy interzone trust untrust outbound<br>\\r
-       policy 0<br>\\r
-       action source-nat<br>\\r
-       policy source 192.168.50.0 0.0.0.255 <br>\\r
-       address-group 100<br><br>\\r
-       ip route-static 101.10.1.0 255.255.255.0 NULL0<br>\\r
-       ip route-static 0.0.0.0 0.0.0.0 GigabitEthernet2/0/6 101.8.1.1<br><br><br>\\r
-Device: E9-NE40E-5<br>\\r
-Command lines:<br><br>\\r
-       interface GigabitEthernet2/0/15<br>\\r
-       undo shutdown<br>\\r
-       ip address 101.2.1.1 255.255.255.0<br><br>\\r
-       interface GigabitEthernet2/0/19<br>\\r
-       undo shutdown<br>\\r
-       ip address 101.1.1.1 255.255.255.0<br><br>\\r
-       interface GigabitEthernet2/0/1<br>\\r
-       undo shutdown<br>\\r
-       ip address 10.1.1.2 255.255.255.0<br><br>\\r
-       ospf 100 router-id 101.1.1.1<br>\\r
-       description NEMO-VAS<br>\\r
-       area 0.0.0.0<br>\\r
-       network 101.1.1.0 0.0.0.255<br>\\r
-       network 101.2.1.0 0.0.0.255<br>"\r
-;\r
-               \r
-                \r
-                \r
-                \r
-                \r
-        }\r
-         \r
-         \r
-         \r
-         });\r
-});
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/Network_Entity.js b/nemo-ui/src/main/resources/nemo/js/Network_Entity.js
deleted file mode 100644 (file)
index 5f99d19..0000000
+++ /dev/null
@@ -1,3794 +0,0 @@
-var lgroup_aviable_node = ["host:h1", "host:h2", "host:h3"];\r
-function update_host(){  \r
-    if(phy_hosts.length>0)\r
- { \r
-        lgroup_aviable_node=[];\r
-    for(var i=0;i<phy_hosts.length;i++)\r
-    {\r
-        lgroup_aviable_node.push("host:"+phy_hosts[i]["host-name"]);\r
-    }\r
-  }\r
-}\r
-\r
-jQuery(document).ready(function ($) {\r
-        var service_name = "";\r
-        service_name = $("#sel_1").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-    localStorage.removeItem(service_name+"_nemo_str");\r
-    //localStorage.clear();\r
-    //getnemo_str();\r
-    //init service_name\r
-    //gloable variable\r
-       \r
-       \r
-function lead_policy(src_group,dest_group,flow_count_temp,color,id,chain_name,src_name,dest_name)\r
-               {\r
-                       var cir_r = parseInt($("#"+src_group+" circle:eq(0)").attr("r"));\r
-                       \r
-                       //get circle cx cy\r
-                       src_cx = parseInt($("#"+src_group+" circle:eq(0)").attr("cx"));\r
-                       src_cy = parseInt($("#"+src_group+" circle:eq(0)").attr("cy"));\r
-                       dest_cx = parseInt($("#"+dest_group+" circle:eq(0)").attr("cx"));\r
-                       dest_cy = parseInt($("#"+dest_group+" circle:eq(0)").attr("cy"));\r
-                       console.log(src_cx+"  "+src_cy+"  "+dest_cx+"   "+dest_cy);\r
-                       \r
-                       //calculate deg\r
-                       var tri_h = dest_cx-src_cx;\r
-                       var tri_l = src_cy-dest_cy;\r
-                       var tri_s = Math.sqrt(tri_l*tri_l + tri_h*tri_h);\r
-                       var deg = Math.asin(tri_l/tri_s);\r
-                       console.log(tri_h+"  "+tri_l+"  "+tri_s);\r
-                       //alert(deg);\r
-                       console.log(deg);\r
-                       \r
-                       \r
-                       //calculate offset\r
-                       var offset = ((20+(15*parseInt(flow_count_temp)))/180)*Math.PI;\r
-                       console.log("temp: "+flow_count_temp+" offset:  "+offset);\r
-                       \r
-                       //calculate path possition\r
-                       var path_src_x,path_src_y,path_dest_x,path_dest_y,mid_x,mid_y,b_x,b_y;\r
-                       if(tri_h >= 0)\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx + cir_r*(Math.cos(offset+deg));\r
-                               path_src_y = src_cy - cir_r*(Math.sin(offset+deg));\r
-                               path_dest_x = dest_cx - (cir_r+14)*(Math.cos(offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));;\r
-                                       b_y = mid_y - (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y - (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       else\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx - cir_r*(Math.cos(offset-deg));\r
-                               path_src_y = src_cy + cir_r*(Math.sin(offset-deg));\r
-                               path_dest_x = dest_cx + (cir_r+14)*(Math.cos(-offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(-offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       //path title\r
-                       var path_title = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       \r
-                       \r
-                       \r
-                       //create path\r
-                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       var path_main = $(path).attr({\r
-                               id: id,\r
-                               node_start:src_name,\r
-                               node_end:dest_name,\r
-                               type:"flow",\r
-                               sx:path_src_x,\r
-                               sy:path_src_y,\r
-                               mx:b_x,\r
-                               my:b_y,\r
-                               ex:path_dest_x,\r
-                               ey:path_dest_y,\r
-                               count:flow_count_temp,\r
-                               via:chain_name,\r
-                               d: 'M'+path_src_x + " " + path_src_y+' Q'+b_x+' '+b_y+' '+path_dest_x+' '+path_dest_y,\r
-                               'stroke':color,\r
-                               'stroke-width':3,\r
-                               fill:"none",\r
-                               'stroke-dasharray':"6,6" ,\r
-                               'marker-end':"url(#idArrow)",\r
-                               'marker-mid':"url(#idtext)"             \r
-                       });\r
-                               $('#service_svg').prepend(path_main);           \r
-\r
-       }       \r
-       function flow_get_end_name()\r
-       {\r
-               var src_ip = $("#src_ip").val().trim();\r
-               var dest_ip = $("#dst_ip").val().trim();\r
-               var host_name = ['',''];\r
-               if(typeof(phy_host_ip[src_ip]) != "undefined")\r
-                       host_name[0] = phy_host_ip[src_ip];\r
-               else\r
-               {\r
-                       for(var find_ip_cursor = 0;find_ip_cursor<$("#service_svg g").length;find_ip_cursor++)\r
-                       {\r
-                               if($("#service_svg g:eq("+find_ip_cursor+")").attr("ip-prefix") == src_ip)\r
-                               {\r
-                                       host_name[0] = $("#service_svg g:eq("+find_ip_cursor+")").attr("id");\r
-                               }       \r
-                               \r
-                       }\r
-               }\r
-               if(typeof(phy_host_ip[dest_ip]) != "undefined")\r
-                       host_name[1] = phy_host_ip[dest_ip];\r
-               else\r
-               {\r
-                       for(var find_ip_cursor = 0;find_ip_cursor<$("#service_svg g").length;find_ip_cursor++)\r
-                       {\r
-                               if($("#service_svg g:eq("+find_ip_cursor+")").attr("ip-prefix") == dest_ip)\r
-                               {\r
-                                       host_name[1] = $("#service_svg g:eq("+find_ip_cursor+")").attr("id");\r
-                               }       \r
-                               \r
-                       }\r
-               }               \r
-               console.log(host_name[0]+" "+host_name[1]);\r
-               return host_name;\r
-               \r
-               \r
-       }\r
-       function flow_get_group()\r
-       {\r
-               var src_host_name = flow_get_end_name()[0];\r
-               var dest_host_name = flow_get_end_name()[1];\r
-               var group_node = ['',''];               \r
-               for(var i = 0;i<$("#service_svg g").length;i++)\r
-               {       \r
-                       host_list = $("#service_svg g:eq("+i+")").attr("sub").split(",");\r
-                       console.log(host_list);\r
-                       if(host_list[0] == '')\r
-                       {\r
-                               continue;\r
-                       }                                       \r
-                       for(var j =0;j<host_list.length;j++)\r
-                       {\r
-                               if(host_list[j] == src_host_name)\r
-                               {\r
-                                       group_node[0] = $("#service_svg g:eq("+i+")").attr("id");\r
-                               }\r
-                               if(host_list[j] == dest_host_name)\r
-                               {\r
-                                       group_node[1] = $("#service_svg g:eq("+i+")").attr("id");\r
-                               }       \r
-                       }\r
-                       if(group_node[0] != '' && group_node[1] != '')\r
-                               break;\r
-               }\r
-               console.log("node: "+group_node[0]+"  "+group_node[1]);\r
-               return group_node;\r
-       }\r
-       function get_connection_node()\r
-       {\r
-               var p2p_con_name1 = $("#p2p_node_group").find("tr").eq(1).find("td").eq(1).find("span").eq(0).text().split(":");\r
-               var p2p_re1 ;\r
-               if(p2p_con_name1.length==1)\r
-                       p2p_re1=p2p_con_name1[0];\r
-               else\r
-                       p2p_re1=p2p_con_name1[1];\r
-               var p2p_con_name2 = $("#p2p_node_group").find("tr").eq(3).find("td").eq(1).find("span").eq(0).text().split(":");\r
-               var p2p_re2 ;\r
-               if(p2p_con_name2.length==1)\r
-                       p2p_re2=p2p_con_name2[0];\r
-               else\r
-                       p2p_re2=p2p_con_name2[1];                               \r
-           var node_name_1 = p2p_re1;\r
-               var node_name_2 = p2p_re2;      \r
-               var end_node = [];\r
-               end_node[0] = node_name_1;\r
-               end_node[1] = node_name_2;\r
-               return end_node;\r
-               \r
-       }\r
-       function get_path_color(){\r
-               while(1)\r
-               {\r
-                  var num1 = Math.floor(Math.random()*256);\r
-                  if(num1>220 )\r
-                          continue;\r
-                  return num1.toString();\r
-               }\r
-       }\r
-       \r
-       function redraw_flow_possition()\r
-       {\r
-               for(var i=0; i<$("#service_svg path").length;i++)\r
-               {\r
-                       if($("#service_svg path:eq("+i+")").attr("type") != "flow")\r
-                               continue;\r
-                       \r
-                       if($("#service_svg path:eq("+i+")").attr("via").split(",")[0] == "none")\r
-                       {\r
-                               \r
-                               var src_group = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                               var dest_group = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                               var flow_count = $("#service_svg path:eq("+i+")").attr("count");\r
-                               var flow_id = $("#service_svg path:eq("+i+")").attr("id");\r
-                               var flow_color = $("#service_svg path:eq("+i+")").attr("stroke");\r
-                               $("#service_svg path:eq("+i+")").remove();\r
-                               lead_policy(src_group,dest_group,flow_count,flow_color,flow_id,"none",src_group,dest_group);            \r
-                       }\r
-                       else\r
-                       {\r
-                               if($("#service_svg path:eq("+i+")").attr("id").split("_")[1] == "1")\r
-                               {\r
-                                       var src_group = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                       var via_group = $("#service_svg path:eq("+i+")").attr("via").split(",")[0];\r
-                                       var dest_group = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                       var flow_count = $("#service_svg path:eq("+i+")").attr("count");\r
-                                       var flow_id = $("#service_svg path:eq("+i+")").attr("id");\r
-                                       var flow_color = $("#service_svg path:eq("+i+")").attr("stroke");\r
-                                       $("#service_svg path:eq("+i+")").remove();\r
-                                       lead_policy(src_group,via_group,flow_count,flow_color,flow_id,via_group,src_group,dest_group);\r
-                               }\r
-                               else if($("#service_svg path:eq("+i+")").attr("id").split("_")[1] == "2")\r
-                               {\r
-                                       var src_group = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                       var via_group = $("#service_svg path:eq("+i+")").attr("via").split(",")[0];\r
-                                       var dest_group = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                       var flow_count = $("#service_svg path:eq("+i+")").attr("count");\r
-                                       var flow_id = $("#service_svg path:eq("+i+")").attr("id");\r
-                                       var flow_color = $("#service_svg path:eq("+i+")").attr("stroke");\r
-                                       $("#service_svg path:eq("+i+")").remove();\r
-                                       lead_policy(via_group,dest_group,flow_count,flow_color,flow_id,via_group,src_group,dest_group);\r
-                               }\r
-                       }\r
-               \r
-               \r
-               }\r
-               \r
-       }\r
-       function redraw_connection_possition()\r
-       {\r
-               for(var i=0; i<$("#service_svg path").length;i++)\r
-               {\r
-                       if($("#service_svg path:eq("+i+")").attr("type") != "connection")\r
-                               continue;\r
-                       var node_name_1 = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                       var node_name_2 = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                       var node_cx_1 = $("#"+node_name_1+"_group").attr("cx");;\r
-                       var node_cy_1 = $("#"+node_name_1+"_group").attr("cy");\r
-                       var node_cx_2 = $("#"+node_name_2+"_group").attr("cx");\r
-                       var node_cy_2 = $("#"+node_name_2+"_group").attr("cy");\r
-                       var conn_id = $("#service_svg path:eq("+i+")").attr("id")\r
-                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       var path_main = $(path).attr({\r
-                               id: conn_id,\r
-                               node_start:node_name_1,\r
-                               node_end:node_name_2,\r
-                               type:"connection",\r
-                               d: 'M'+node_cx_1 + " " + node_cy_1+' L'+node_cx_2+' '+node_cy_2,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"black"\r
-                       });\r
-                       $("#service_svg path:eq("+i+")").remove();\r
-                       $('#service_svg').prepend(path_main);                                   \r
-               }               \r
-       }\r
-       function redraw_node_possition()\r
-       {\r
-               node_count = $("#service_svg g").length;\r
-               if(node_count == 1)\r
-               {\r
-                       var x = 550;\r
-            var y = 450;\r
-                       dis_x = x-$("#service_svg g:eq(0) circle:eq(0)").attr("cx");\r
-                       dis_y = y-$("#service_svg g:eq(0) circle:eq(0)").attr("cy");\r
-                       $("#service_svg g:eq(0) circle:eq(0)").attr("cx",x);\r
-                       $("#service_svg g:eq(0) circle:eq(0)").attr("cy",y);\r
-                       for(var j =0;j<$("#service_svg g:eq(0) rect").length;j++)\r
-                       {\r
-                               var last_x = parseInt($("#service_svg g:eq(0) rect:eq("+j+")").attr("x"));\r
-                               var last_y = parseInt($("#service_svg g:eq(0) rect:eq("+j+")").attr("y"));\r
-                               $("#service_svg g:eq(0) rect:eq("+j+")").attr("x",last_x+dis_x);\r
-                               $("#service_svg g:eq(0) rect:eq("+j+")").attr("y",last_y+dis_y);\r
-                       }\r
-                       for(var j =0;j<$("#service_svg g:eq(0) text").length;j++)\r
-                       {\r
-                               $("#service_svg g:eq(0) text:eq("+j+")").attr("x",parseInt($("#service_svg g:eq(0) text:eq("+j+")").attr("x"))+dis_x);\r
-                               $("#service_svg g:eq(0) text:eq("+j+")").attr("y",parseInt($("#service_svg g:eq(0) text:eq("+j+")").attr("y"))+dis_y);                  \r
-                       }\r
-                       \r
-                        return;\r
-                       \r
-               }\r
-               var res = calculatePos(node_count);\r
-        var r = 300;\r
-               for(var i =0;i<node_count;i++)\r
-               {\r
-                       var deg = res[i];\r
-            var x = 550 + Math.cos(deg) * r;\r
-            var y = 450 - Math.sin(deg) * r;\r
-                       dis_x = x-parseInt($("#service_svg g:eq("+i+") circle:eq(0)").attr("cx"));\r
-                       dis_y = y-parseInt($("#service_svg g:eq("+i+") circle:eq(0)").attr("cy"));\r
-                       $("#service_svg g:eq("+i+") circle:eq(0)").attr("cx",x);\r
-                       $("#service_svg g:eq("+i+") circle:eq(0)").attr("cy",y);\r
-                       for(var j =0;j<$("#service_svg g:eq("+i+") rect").length;j++)\r
-                       {\r
-                               $("#service_svg g:eq("+i+") rect:eq("+j+")").attr("x",parseInt($("#service_svg g:eq("+i+") rect:eq("+j+")").attr("x"))+dis_x);\r
-                               $("#service_svg g:eq("+i+") rect:eq("+j+")").attr("y",parseInt($("#service_svg g:eq("+i+") rect:eq("+j+")").attr("y"))+dis_y);\r
-                       }\r
-                       for(var j =0;j<$("#service_svg g:eq("+i+") text").length;j++)\r
-                       {\r
-                               $("#service_svg g:eq("+i+") text:eq("+j+")").attr("x",parseInt($("#service_svg g:eq("+i+") text:eq("+j+")").attr("x"))+dis_x);\r
-                               $("#service_svg g:eq("+i+") text:eq("+j+")").attr("y",parseInt($("#service_svg g:eq("+i+") text:eq("+j+")").attr("y"))+dis_y);                  \r
-                       }\r
-                       \r
-               }\r
-\r
-       }\r
-       function redraw_specific_node_possition(group_name,x,y)\r
-       {\r
-               dis_x = x-$("#"+group_name+" circle:eq(0)").attr("cx");\r
-               dis_y = y-$("#"+group_name+" circle:eq(0)").attr("cy");\r
-               $("#"+group_name+" circle:eq(0)").attr("cx",x);\r
-               $("#"+group_name+" circle:eq(0)").attr("cy",y);\r
-               for(var j =0;j<$("#"+group_name+" rect").length;j++)\r
-               {\r
-                       var last_x = parseInt($("#"+group_name+" rect:eq("+j+")").attr("x"));\r
-                       var last_y = parseInt($("#"+group_name+" rect:eq("+j+")").attr("y"));\r
-                       $("#"+group_name+" rect:eq("+j+")").attr("x",last_x+dis_x);\r
-                       $("#"+group_name+" rect:eq("+j+")").attr("y",last_y+dis_y);\r
-               }\r
-               for(var j =0;j<$("#"+group_name+" text").length;j++)\r
-               {\r
-                       $("#"+group_name+" text:eq("+j+")").attr("x",parseInt($("#"+group_name+" text:eq("+j+")").attr("x"))+dis_x);\r
-                       $("#"+group_name+" text:eq("+j+")").attr("y",parseInt($("#"+group_name+" text:eq("+j+")").attr("y"))+dis_y);                    \r
-               }\r
-               return;\r
-       }\r
-       function draw_group(node_number,table_name)\r
-       {\r
-               var circle_x = 550;\r
-               var circle_y = 450;\r
-               if(node_number == 0)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = $(circle_main).attr({\r
-                               id: $("#node_name").val().trim() + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = $(text1).attr({\r
-                               id: $("#node_name").val().trim() + "_title1",\r
-                               x: circle_x,\r
-                               y: circle_y-8,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                               \r
-                       });\r
-                       $(text1).text($("#sel_show").children('option:selected').val());\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = $(text2).attr({\r
-                               id: $("#node_name").val().trim() + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y+10,\r
-                               fill:"                       ",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text2).text($("#node_name").val().trim());\r
-                       var g_main = $(g).append(inCircle1_main);\r
-                       $(g).append(text1_main);\r
-                       $(g).append(text2_main);\r
-                       $(g).attr("id",$("#node_name").val().trim());\r
-                       $(g).attr("type",$("#sel_show").children('option:selected').val());\r
-                       if(table_name != "ext")\r
-                               $(g).attr("sub","");\r
-                       else\r
-                       {\r
-                               $(g).attr("sub",$("#node_name").val().trim());\r
-                               $(g).attr("ip-prefix",$("#ext-group_ip-prefix").val().trim());\r
-                               //ext_ip[$("#ext-group_ip-prefix").val().trim()] = $("#node_name").val().trim();\r
-               \r
-                       }\r
-                       if(table_name.indexOf("chain") > -1)\r
-                               $(g).attr("flow",0);\r
-                       $('#service_svg').append(g_main);       \r
-               }\r
-               else if(node_number == 1)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = $(circle_main).attr({\r
-                               id: $("#node_name").val().trim() + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var host1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');\r
-                       var host1_main = $(host1).attr({\r
-                               id: $("#node_name").val().trim() + "_title1",\r
-                               x: circle_x-57,\r
-                               y: circle_y-25,\r
-                               width:114,\r
-                               height:50,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = $(text1).attr({\r
-                               id: $("#node_name").val().trim() + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y-48,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                       });\r
-                       $(text1).text($("#sel_show").children('option:selected').val());\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = $(text2).attr({\r
-                               id: $("#"+table_name+" tr:eq(0) td:eq(0)").text(),\r
-                               x: circle_x,\r
-                               y: circle_y-30,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text2).text($("#node_name").val().trim());\r
-                       var text3 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text3_main = $(text3).attr({\r
-                               id: $("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1] + "_text",\r
-                               x: circle_x,\r
-                               y: circle_y,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text3).text($("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1]);\r
-                       var g_main = $(g).append(inCircle1_main);\r
-                       $(g).append(host1_main);\r
-                       $(g).append(text1_main);\r
-                       $(g).append(text2_main);\r
-                       $(g).append(text3_main);\r
-                       $(g).attr("id",$("#node_name").val().trim());\r
-                       $(g).attr("type",$("#sel_show").children('option:selected').val());\r
-                       $(g).attr("sub",$("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1]);\r
-                       if(table_name.indexOf("chain") > -1)\r
-                               $(g).attr("flow",0);\r
-                       $('#service_svg').append(g_main);                               \r
-               }\r
-               else if(node_number == 2)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = $(circle_main).attr({\r
-                               id: $("#node_name").val().trim() + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var host1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host1_main = $(host1).attr({\r
-                               id:$("#"+table_name+" tr:eq(0) td:eq(0)").text(),\r
-                               x: circle_x-55,\r
-                               y: circle_y-25,\r
-                               width:110,\r
-                               height:34,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var host2 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host2_main = $(host2).attr({\r
-                               id: $("#"+table_name+" tr:eq(1) td:eq(0)").text(),\r
-                               x: circle_x-55,\r
-                               y: circle_y+18,\r
-                               width:110,\r
-                               height:34,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = $(text1).attr({\r
-                               id: $("#node_name").val().trim() + "_title1",\r
-                               x: circle_x,\r
-                               y: circle_y-48,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                       });\r
-                       $(text1).text($("#sel_show").children('option:selected').val());\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = $(text2).attr({\r
-                               id:  $("#node_name").val().trim() + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y-31,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text2).text($("#node_name").val().trim());\r
-                       var text3 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text3_main = $(text3).attr({\r
-                               id: $("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1] + "_text",\r
-                               x: circle_x,\r
-                               y: circle_y-5,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text3).text($("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1]);\r
-                       var text4 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text4_main = $(text4).attr({\r
-                               id: $("#"+table_name+" tr:eq(1) td:eq(0)").text().split(":")[1] + "_text",\r
-                               x: circle_x,\r
-                               y: circle_y+40,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text4).text($("#"+table_name+" tr:eq(1) td:eq(0)").text().split(":")[1]);\r
-                       var g_main = $(g).append(inCircle1_main);\r
-                       $(g).append(host1_main);\r
-                       $(g).append(host2_main);\r
-                       $(g).append(text1_main);\r
-                       $(g).append(text2_main);\r
-                       $(g).append(text3_main);\r
-                       $(g).append(text4_main);\r
-                       $(g).attr("id",$("#node_name").val().trim());\r
-                       $(g).attr("type",$("#sel_show").children('option:selected').val());\r
-                       $(g).attr("sub",$("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1]+","+$("#"+table_name+" tr:eq(1) td:eq(0)").text().split(":")[1]);\r
-                       if(table_name.indexOf("chain") > -1)\r
-                               $(g).attr("flow",0);\r
-                       $('#service_svg').append(g);\r
-                       \r
-               }\r
-               else if(node_number == 3)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = $(circle_main).attr({\r
-                               id: $("#node_name").val().trim() + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var host1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host1_main = $(host1).attr({\r
-                               id: $("#"+table_name+" tr:eq(0) td:eq(0)").text(),\r
-                               x: circle_x-55,\r
-                               y: circle_y-31,\r
-                               width:110,\r
-                               height:25,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var host2 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host2_main = $(host2).attr({\r
-                               id: $("#"+table_name+" tr:eq(1) td:eq(0)").text(),\r
-                               x: circle_x-55,\r
-                               y: circle_y-3,\r
-                               width:110,\r
-                               height:25,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var host3 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host3_main = $(host3).attr({\r
-                               id: $("#"+table_name+" tr:eq(2) td:eq(0)").text(),\r
-                               x: circle_x-55,\r
-                               y: circle_y+27,\r
-                               width:110,\r
-                               height:25,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = $(text1).attr({\r
-                               id: $("#node_name").val().trim() + "_title1",\r
-                               x: circle_x,\r
-                               y: circle_y-51,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                       });\r
-                       $(text1).text($("#sel_show").children('option:selected').val());\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = $(text2).attr({\r
-                               id: $("#node_name").val().trim() + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y-36,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text2).text($("#node_name").val().trim());\r
-                       var text3 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text3_main = $(text3).attr({\r
-                               id: $("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1] + '_text',\r
-                               x: circle_x,\r
-                               y: circle_y-13,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text3).text($("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1]);\r
-                       var text4 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text4_main = $(text4).attr({\r
-                               id: $("#"+table_name+" tr:eq(1) td:eq(0)").text().split(":")[1] + '_text',\r
-                               x: circle_x,\r
-                               y: circle_y+13,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text4).text($("#"+table_name+" tr:eq(1) td:eq(0)").text().split(":")[1]);\r
-                       var text5 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text5_main = $(text5).attr({\r
-                               id: $("#"+table_name+" tr:eq(2) td:eq(0)").text().split(":")[1] + '_text',\r
-                               x: circle_x,\r
-                               y: circle_y+43,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       $(text5).text($("#"+table_name+" tr:eq(2) td:eq(0)").text().split(":")[1]);\r
-                       var g_main = $(g).append(inCircle1_main);\r
-                       $(g).append(host1_main);\r
-                       $(g).append(host2_main);\r
-                       $(g).append(host3_main);\r
-                       $(g).append(text1_main);\r
-                       $(g).append(text2_main);\r
-                       $(g).append(text3_main);\r
-                       $(g).append(text4_main);\r
-                       $(g).append(text5_main);\r
-                       $(g).attr("id",$("#node_name").val().trim());\r
-                       $(g).attr("type",$("#sel_show").children('option:selected').val());\r
-                       $(g).attr("sub",$("#"+table_name+" tr:eq(0) td:eq(0)").text().split(":")[1]+","+$("#"+table_name+" tr:eq(1) td:eq(0)").text().split(":")[1]+","+$("#"+table_name+" tr:eq(2) td:eq(0)").text().split(":")[1]);\r
-                       if(table_name.indexOf("chain") > -1)\r
-                               $(g).attr("flow",0);\r
-                       $('#service_svg').append(g);    \r
-               }               \r
-       }\r
-    var sevice_name_glb = "";\r
-    var entity_name_glb = "";\r
-\r
-    var group_node = new Array();\r
-\r
-    var chain_aviable_node = [];//fw lb cache\r
-    \r
-    var conn_aviable_node = [];//l2-group l3-group ext-group ,useless\r
-    \r
-    var chain_node=[];//all chain group only, useless\r
-    //group_node = get_nodes_array();\r
-    //console.log("group_node:" + group_node);\r
-    var src_ip = "", dest_ip = "", src_port = "", dest_port = "", protocol = "", vlanid = "";\r
-    //function\r
-    function getSevice_names() {\r
-        $(".NE_up #sel_1").find("option").remove();\r
-        var get_service_names = localStorage.getItem("service_names");\r
-        console.log(get_service_names);\r
-        if (!get_service_names || typeof (get_service_names) == "undefined")\r
-            return;\r
-        if (get_service_names != null || get_service_names != "") {\r
-            svc_name = get_service_names.split(",");\r
-            for (var k = 0; k < svc_name.length; k++) {\r
-                if (svc_name[k] != "")\r
-                    $(".NE_up #sel_1").append("<Option value='" + svc_name[k] + "'>" + svc_name[k] + "</Option>");\r
-            }\r
-        }\r
-        $("#sel_1").val(service_select).attr("disabled", true);\r
-    }\r
-    function setnemo_str() {\r
-        var service_name = "";\r
-        service_name = $("#sel_1").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-        str = "";\r
-        //$("#nemo_str_show p").each(function () {\r
-        //    str += $(this).html() + "|";\r
-        //});\r
-        //str = str.substring(0, str.length - 1);\r
-        str = $("#nemo_str_show").html();\r
-        //console.log("set_nemo:"+str);\r
-        localStorage.setItem(service_name + "_nemo_str", str);\r
-    }\r
-    function getnemo_str() {\r
-        $("#nemo_str_show").empty();\r
-        var service_name = "";\r
-        service_name = $("#sel_1").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined")\r
-            return;\r
-        var str = localStorage.getItem(service_name + "_nemo_str");\r
-        //console.log("nemo_str:"+str);\r
-        //if (!str || typeof (str) == "undefined")\r
-        //    return;\r
-        //str = str.split("|");\r
-\r
-        //for (s = 0; s < str.length; s++) {\r
-        //    $("#nemo_str_show").append("<p class='key'>" + str[s] + "</p>");\r
-        //}\r
-        //console.log("get_nemo:" + str);\r
-        $("#nemo_str_show").append(str);\r
-    }\r
-\r
-function get_aviable_node(type){\r
-    var service_name = "";\r
-    service_name = $("#sel_1").children("option:selected").val();\r
-    if (!service_name || typeof (service_name) == "undefined") return;\r
-    if(type=="lgroup"){\r
-    var lgroup_str=localStorage.getItem(service_name+"_lgroup_aviable_node");\r
-    if(!lgroup_str) return;\r
-    var $json_str=JSON.parse(lgroup_str);\r
-    lgroup_aviable_node = $json_str.lgroup_aviable_node;\r
-    console.log($json_str.lgroup_aviable_node);\r
-    }\r
-    else if(type=="chain"){\r
-    var chain_str=localStorage.getItem(service_name+"_chain_aviable_node");\r
-    if(!chain_str) return;\r
-    var $json_str=JSON.parse(chain_str);\r
-    chain_aviable_node = $json_str.chain_aviable_node;\r
-    console.log($json_str.chain_aviable_node);\r
-\r
-    }\r
-}\r
-function set_aviable_node(type){\r
-    var service_name = "";\r
-    service_name = $("#sel_1").children("option:selected").val();\r
-    if (!service_name || typeof (service_name) == "undefined") return;\r
-    if(type=="lgroup"){\r
-    var lgroup_str=localStorage.getItem(service_name+"_lgroup_aviable_node");\r
-    if(!lgroup_str) return;\r
-    var $json_str=JSON.parse(lgroup_str);\r
-    $json_str.lgroup_aviable_node=lgroup_aviable_node;\r
-    localStorage.setItem(service_name+"_lgroup_aviable_node",JSON.stringify($json_str));\r
-    console.log($json_str.lgroup_aviable_node);\r
-    }\r
-    else if(type=="chain"){\r
-    var chain_str=localStorage.getItem(service_name+"_chain_aviable_node");\r
-    if(!chain_str) return;\r
-    var $json_str=JSON.parse(chain_str);\r
-    $json_str.chain_aviable_node=chain_aviable_node;\r
-    localStorage.setItem(service_name+"_lgroup_aviable_node",JSON.stringify($json_str));\r
-    console.log($json_str.chain_aviable_node);\r
-\r
-    }\r
-}\r
-\r
-    function setentity_instance_list() {\r
-\r
-        var sevice_name = "";\r
-        sevice_name = $("#sel_1").children('option:selected').val().trim();\r
-        if (sevice_name == "") return;\r
-        current_entity_instance_list = "";\r
-        $(".NE_up #sel_2 option").each(function () {\r
-            current_entity_instance_list += $(this).val().trim() + ",";\r
-        });\r
-        //console.log("cur_entity_instance_list:" + current_entity_instance_list);\r
-        current_entity_instance_list = current_entity_instance_list.substring(0, (current_entity_instance_list.length - 1));\r
-        console.log("setentity_instance_list now_entity_instance_list: " + current_entity_instance_list);\r
-        localStorage.setItem(sevice_name + "_entity_instance_list", current_entity_instance_list);\r
-    }\r
-\r
-    function setentity_instance_list_() {\r
-        var sevice_name = "";\r
-        sevice_name = $("#sel_1").children('option:selected').val().trim();\r
-        if (sevice_name == "") return;\r
-        current_entity_instance_list = "";\r
-\r
-        localStorage.setItem(sevice_name + "_entity_instance_list_", $(".NE_up #sel_2").html());\r
-        console.log("setentity_instance_list_: " + $(".NE_up #sel_2").html());\r
-\r
-    }\r
-    function getentity_instance_list() {\r
-        var sevice_name = "";\r
-        sevice_name = $("#sel_1").children('option:selected').val();\r
-        if (sevice_name == "")\r
-            return;\r
-        var entity_instance_list = localStorage.getItem(sevice_name + "_entity_instance_list");\r
-        console.log(entity_instance_list);\r
-        if (!entity_instance_list && typeof (entity_instance_list) != "undefined" && entity_instance_list != 0)\r
-            return;\r
-        $("#sel_2").empty();\r
-        if (entity_instance_list != null || entity_instance_list != "") {\r
-            svc_name = entity_instance_list.split(",");\r
-            for (var k = 0; k < svc_name.length; k++) {\r
-                if (svc_name[k] != "")\r
-                    $(".NE_up #sel_2").append("<Option value='" + svc_name[k] + "'>" + svc_name[k] + "</Option>");\r
-            }\r
-        }\r
-    }\r
-    function getentity_instance_list_() {\r
-        var sevice_name = "";\r
-        sevice_name = $("#sel_1").children('option:selected').val();\r
-        if (sevice_name == "") return;\r
-        var entity_instance_list = localStorage.getItem(sevice_name + "_entity_instance_list_");\r
-        console.log(entity_instance_list);\r
-        if (!entity_instance_list || typeof (entity_instance_list) == "undefined") return;\r
-        $("#sel_2").empty().append(entity_instance_list);\r
-    }\r
-    //connection node\r
-    function query_node_show() {\r
-        var service_name = "";\r
-        service_name = $("#sel_1").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-        if ($("#sel_2 option").length == 0) return;\r
-        $("#p2p_select,#p2mp_select,#mesh_select").empty();\r
-        $("#sel_2 option").each(function () {\r
-            if ($(this).val().trim().indexOf("node") >= 0) {\r
-                var j = service_name + "__" + $(this).val().replace(":", "_");\r
-                var entity = localStorage.getItem(j)\r
-                if (!entity || typeof (entity) == "undefined") return true;\r
-                var json = jQuery.parseJSON(entity);\r
-                if (json[j]["node_type"] == "fw" || json[j]["node_type"] == "lb" || json[j]["node_type"] == "cache" ) return true;\r
-                var str = $(this).val().split(":");\r
-                $("#p2p_select,#p2mp_select,#mesh_select").append("<Option value='" + str[1] + "'>" + str[1]+ "</Option>");\r
-            }\r
-        });\r
-    }\r
-    //get nodes include firewall and loadbalance\r
-    function get_nodes(id_) {\r
-        var service_name = "";\r
-        service_name = $("#sel_1").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-        if ($("#sel_2 option").length == 0) return;\r
-        $("#" + id_).empty();\r
-        $("#sel_2 option").each(function () {\r
-            if ($(this).val().trim().indexOf("node") >= 0) {\r
-                var j = service_name + "__" + $(this).val().replace(":", "_");\r
-                var entity = localStorage.getItem(j)\r
-                if (!entity || typeof (entity) == "undefined") return true;\r
-                var json = jQuery.parseJSON(entity);\r
-                if (json[j]["node_type"] == "firewall" || json[j]["node_type"] == "loadbalance")\r
-                    return true;\r
-                var str = $(this).val().split(":");\r
-                $("#" + id_).append("<option value='" + str[1] + "'>" + str[1] + "</option>");\r
-            }\r
-        });\r
-    }\r
-    function set_available_node()\r
-    {\r
-        $("#p2p_select,#p2mp_select,#mesh_select").empty();\r
-        for (var i = 0; i <conn_aviable_node.length; i++) {\r
-            $("#p2p_select,#p2mp_select,#mesh_select").append("<option value=" + conn_aviable_node[i] + ">" + conn_aviable_node[i]+ "</option>");\r
-        }\r
-    }\r
-    function get_nodes_array() {\r
-        var nodes = new Array();\r
-        var service_name = localStorage.getItem("service_names");\r
-        //service_name = $("#sel_1").children("option:selected").val();\r
-        //console.log(service_name);\r
-        if (!service_name || typeof (service_name) == "undefined") return nodes;\r
-        var str = localStorage.getItem(service_name + "_entity_instance_list");\r
-        //console.log("entity_list:" + str);\r
-        if (!str || typeof (str) == "undefined") return nodes;\r
-        str = str.split(",");\r
-\r
-        for (var i = 0; i < str.length; i++) {\r
-            var j = service_name + "__" + str[i].replace(":", "_");\r
-            var json_str = localStorage.getItem(j);\r
-            //console.log(json_str);\r
-            var json = jQuery.parseJSON(json_str);\r
-            if (json[j]["node_type"] == "firewall" || json[j]["node_type"] == "loadbalance")\r
-                continue;\r
-            nodes.push(json[j]["node_name"]);\r
-        }\r
-        //console.log("nodes:"+nodes);\r
-        return nodes;\r
-    }\r
-\r
-    //create table function\r
-    function CreateTable(rowCount, arr) {\r
-        var table = $("<table id='tab' border=\"0\">");\r
-        table.appendTo($("#p2mp_node-name2"));\r
-        for (var i = 0; i < rowCount; i++) {\r
-            var tr = $("<tr></tr>");\r
-            tr.appendTo(table);\r
-            var td = $("<td> <input type='checkbox'> </td><td>" + arr[i] + "</td>");\r
-            td.appendTo(tr);\r
-        }\r
-        $("#p2mp_node-name2").append("</table>");\r
-    }\r
-    function check_policy(entity_name) {\r
-        var sevice_name = "";\r
-        sevice_name = $("#sel_1").children('option:selected').val();\r
-        if (sevice_name == "")\r
-            return;\r
-        //entity = entity.split(":");\r
-        var str = sevice_name + "_policy_list";\r
-\r
-        console.log(str);\r
-        var policy_list = localStorage.getItem(str);\r
-        var last_policy = policy_list;\r
-        console.log(policy_list);\r
-        if (policy_list && typeof (policy_list) != "undefined") {\r
-            policy_list = policy_list.split(",");\r
-            console.log(policy_list);\r
-            for (var i = 0; i < policy_list.length; i++) {\r
-                json_key = sevice_name + "__policy_" + policy_list[i];\r
-                //console.log(json_key);\r
-                var policy = localStorage.getItem(json_key);\r
-                //console.log(policy);\r
-                if (!policy || typeof (policy) == "undefined")\r
-                    return true;\r
-                json = JSON.parse(policy);\r
-                //console.log(entity_name);\r
-                if (json[json_key]["apply_entity_id"] == entity_name) {\r
-                    //console.log("true");\r
-                    localStorage.removeItem(json_key);\r
-                    console.log(policy_list);\r
-                    temp = last_policy.split(",");\r
-                    var ss = "";\r
-                    for (var i = 0; i < temp.length; i++) {\r
-                        if (temp[i] != json[json_key]["policy_name"]) {\r
-                            ss += temp[i] + ",";\r
-                        }\r
-                    }\r
-                    ss = ss.substring(0, ss.length - 1);\r
-                    last_policy = ss;\r
-                    console.log("last_policy:" + last_policy);\r
-                    //console.log(policy_list);\r
-                    $("#nemo_str_show p").each(function () {\r
-                        {\r
-                            console.log("policy_id:" + json[json_key]["policy_id"]);\r
-                            console.log($(this).html());\r
-                            if ($(this).html().indexOf(json[json_key]["policy_id"]) >= 0)\r
-                                $(this).remove();\r
-                        }\r
-                    });\r
-                    setnemo_str();\r
-                }\r
-\r
-            }\r
-        }\r
-        localStorage.setItem(sevice_name + "_policy_list", last_policy);\r
-    }\r
-\r
-    //network_entity_init(service name,Entity Instance list)\r
-    $("#net_ent_init").click(function () {\r
-        getSevice_names();\r
-        $(".NE_up #sel_2").find("option").remove();\r
-        getentity_instance_list_();\r
-        getnemo_str();\r
-        $(".NE_close_show").click();\r
-        update_host();\r
-               //svg recover\r
-        var sevice_name = $("#sel_1").val();\r
-        if(!sevice_name) return;\r
-        $("#service_svg").show();       \r
-        $("#service_svg2").hide();  \r
-        //document.getElementById("service_svg2").style.display="none";     \r
-               var svg_rec = localStorage.getItem(sevice_name+"_svg");\r
-        if(svg_rec)\r
-               $("#service_svg").html(svg_rec);\r
-               \r
-    });\r
-    //servicr_name change event\r
-    $(".NE_up #sel_1").change(function () {\r
-        $(this).children('option:selected').val();\r
-        $(".NE_up #sel_2").find("option").remove();\r
-        getnemo_str();\r
-        getentity_instance_list_();\r
-    });\r
-    //node type change enevt\r
-    $(".NE_middle #sel_show").change(function () {\r
-        var id_ = $(this).children('option:selected').val() + "_type";\r
-        $(".node_type_group").hide();\r
-        $("#" + id_).show();\r
-        $(".node_type_group_group").each(function () {\r
-            $(this).find("select").eq(0).children().remove();\r
-            //$(this).find("select").eq(2).children().remove();\r
-        });\r
-        for (var i = 0; i < lgroup_aviable_node.length; i++) {\r
-            $("#l2_addhost,#l3_addhost").append("<option value='" + lgroup_aviable_node[i] + "'>" + lgroup_aviable_node[i] + "</option>");\r
-        }\r
-        for (var i = 0; i < chain_aviable_node.length; i++) {\r
-            $("#chain_addhost").append("<option value='" + chain_aviable_node[i] + "'>" + chain_aviable_node[i] + "</option>");\r
-        }\r
-    });\r
-    //connection type chang event\r
-    $(".NE_conn_show #con_type").change(function () {\r
-        var id_ = $(this).children('option:selected').val() + "_type";\r
-        $(".conn_type_group").hide();\r
-        $("#" + id_).show();\r
-        //set_available_node();\r
-        query_node_show();\r
-\r
-    });\r
-    //add entity type(node connection flow)\r
-    $("#add_entity").click(function () {\r
-        //check service name\r
-        if ($("#sel_1 option").length == 0) return;\r
-        //content init\r
-        $(".NE_close_show").click();\r
-        //id init\r
-        var class_ = "NE_" + $("#entity_type").children('option:selected').val() + "_show";\r
-        $(".id_").each(function () { $(this).val(guid()).attr("disabled", "true") });\r
-        $(".NE_close_item").hide();\r
-        $("." + class_).show();\r
-        //node host init\r
-        get_aviable_node("lgroup");\r
-        get_aviable_node("chain");\r
-        //connection init\r
-        query_node_show();       \r
-        $("#p2p_node-name2 option:first").remove();\r
-        $("#con_type").get(0).selectedIndex = 0;\r
-        $("#con_type").change();\r
-        //validate init\r
-        $(".alert_").attr("src", "src/app/nemo/images/alert.png");\r
-        $("#mac_icon").attr("src", "");\r
-        $("#src_ip_icon").attr("src", "");\r
-        $("#dest_ip_icon").attr("src", "");\r
-        $("#src_port_icon").attr("src", "");\r
-        $("#dest_port_icon").attr("src", "");\r
-        $("#protocol").attr("src", "");\r
-        $("#vlanid").attr("src", "");\r
-\r
-        // $("#host_mac_address").blur();\r
-        // $("#src_ip").blur();\r
-        // $("#dest_ip").blur();\r
-        // $("#src_port").blur();\r
-        // $("#dest_port").blur();\r
-        // $("#vlanid").blur();\r
-        // $("#protocol").blur();\r
-         $("#node_name").blur();\r
-        $("#connection_name").blur();\r
-        // $("#bandwidth").blur();\r
-         $("#flow_name").blur();\r
-        // $("#host_ip_address").blur();\r
-        // $("#host_location").blur();\r
-        // $("#firewall_location").blur();\r
-        // //$("#forwarding_location").blur();\r
-        // $("#internet_location").blur();\r
-\r
-        //node init\r
-        $("#sel_show").get(0).selectedIndex = 0;\r
-        $("#sel_show").change();\r
-        $("#l2_select_table,#l3_select_table").empty();\r
-        //connection init\r
-        $("#p2p_node_group table,#p2mp_node_group table,#mesh_node_group table,#chain_node_group table").empty();\r
-        $tableContent = $.parseHTML(' <tr> <td colspan="2"><span  class="second_title">One End Point:</span></td> </tr>'+\r
-                                     '<tr> <td width="60px"></td><td></td> </tr>'+ \r
-                                     '<tr> <td colspan="2"><span class="second_title">Other End Point:</span></td> </tr>'+\r
-                                     '<tr><td></td><td></td></tr>');\r
-\r
-        $("#p2p_node_group table,#p2mp_node_group table").append($tableContent);\r
-        $tableContent_ = $.parseHTML(' <tr><td><span  class="second_title">End Point:</span></td><td></td> </tr>' +\r
-                           ' <tr><td></td><td></td></tr>');\r
-        $("#mesh_node_group table,#chain_node_group table").append($tableContent_);\r
-        //chain-group empty\r
-        $("#chain_delgroup #chain_select_table").empty();\r
-        //goback change type and name\r
-        $("#entity_type").attr("disabled", false);\r
-        $("#node_name").attr("disabled", false);\r
-        $("#connection_name").attr("disabled", false);\r
-         $("#con_type").attr("disabled", false);\r
-        $("#flow_name").attr("disabled", false);\r
-        $("#p2p_node-name1").attr("disabled", false);\r
-        $("#p2p_node-name2").attr("disabled", false);\r
-        $("#p2mp_node-name1").attr("disabled", false);\r
-        $("#p2mp_node-name2 table input").attr("disabled", false);\r
-        //flow init\r
-        //get_nodes("src_node");\r
-        //$("#src_node").change();\r
-        //entity list show empty\r
-        if (flag == false)\r
-            $("#sel_2").prepend("<Option value='empty'></Option>").get(0).selectedIndex = 0;\r
-        //edit false\r
-        flag = false;\r
-        ne_flag = 0;\r
-        $(".NE_middle #sel_show").change();\r
-       // $(".node_type_group_group").find("select").children().remove();\r
-    });\r
-\r
-    $("#l2_ok").click(function () {\r
-        var $l2_add_node = $("#l2_addhost option:selected");\r
-        if (!$l2_add_node.html()) return;\r
-        $l2_select_node = $("<tr><td align='center'>" + $l2_add_node.html() + "</td><td><input type='button' class='btn_ del_sub_node' value='delete'/></td></tr>");\r
-        $("#l2_select_table").append($l2_select_node);\r
-        $l2_add_node.remove();\r
-        //addBtnEvent("del_sub_node");\r
-    });\r
-    $("#l3_ok").click(function () {\r
-        var $l3_add_node = $("#l3_addhost option:selected");\r
-        if (!$l3_add_node.html()) return;\r
-        $l3_select_node = $("<tr><td align='center'>" + $l3_add_node.html() + "</td><td><input type='button' class='btn_ del_sub_node' value='delete'/></td></tr>");\r
-        $("#l3_select_table").append($l3_select_node);\r
-        $l3_add_node.remove();\r
-        //addBtnEvent("del_sub_node");\r
-    });\r
-    var onBtnClick = function () {\r
-        var node_name = $(this).parent().prev().html();\r
-        $(this).parents("div.delgroup").parent().parent().prev().children().children("select").prepend("<option value=" + node_name + ">" + node_name + "</option>");\r
-        $(this).parent().parent().remove();\r
-    }\r
-    $(".select_table").on('click', " .del_sub_node",onBtnClick);\r
-    \r
-    $("#chain_ok").click(function () {\r
-        var $chain_add_node = $("#chain_addhost option:selected");\r
-        if (!$chain_add_node.html()) return;\r
-        $chain_select_node = $("<tr><td align='center'>" + $chain_add_node.html() + "</td><td><input type='button' class='btn_ del_sub_node' value='delete'/></td></tr>");\r
-        $("#chain_select_table").append($chain_select_node);\r
-        $chain_add_node.remove();\r
-        //addBtnEvent("del_sub_node");\r
-    });\r
-    // var chain_onBtnClick = function () {\r
-    //     var node_name = $(this).parent().prev().html();\r
-    //     $(this).parents("div.delgroup").parent().parent().prev().children().children("select").prepend("<option value=" + node_name + ">" + node_name + "</option>");\r
-    //     $(this).parent().parent().remove();\r
-    // }\r
-    $("#p2p_select_ok").click(function () {\r
-        var $p2p_add_node = $("#p2p_select option:selected");\r
-        if (!$p2p_add_node.html()) return;\r
-       \r
-        if ($("#p2p_node_group").find("tr").eq(1).find("td").eq(1).children().length==0) {\r
-            $("#p2p_node_group").find("tr").eq(1).find("td").eq(1).html("<span>" + $p2p_add_node.html() + "</span>" + "<input type='button' class='btn_ del_node' value='Delete'/>");\r
-            $p2p_add_node.remove();\r
-        }\r
-    });\r
-    $("#p2p_select_ok2").click(function () {\r
-        var $p2p_add_node = $("#p2p_select option:selected");\r
-        if (!$p2p_add_node.html()) return;\r
-        if ($("#p2p_node_group").find("tr").eq(3).find("td").eq(1).children().length == 0) {\r
-            $("#p2p_node_group").find("tr").eq(3).find("td").eq(1).html("<span>" + $p2p_add_node.html() + "</span>" + "<input type='button' class='btn_ del_node' value='Delete'/>");\r
-            //$("#p2p_node_group").append("<tr><td></td><td></td></tr>");\r
-            $p2p_add_node.remove();\r
-        }\r
-    });\r
-    var onBtnClick_p2p = function () {\r
-        var node_name = $(this).prev().html();\r
-        if ($("#p2p_node_group tr").index($(this)) == 1)\r
-        {\r
-            $(this).prev().remove(); $(this).remove();\r
-        }\r
-        else {\r
-            $(this).prev().remove(); $(this).remove();\r
-        }\r
-        $("#p2p_select").prepend("<option value=" + node_name + ">" + node_name + "</option>");\r
-        $("#p2p_select").get(0).selectedIndex = 0;\r
-        \r
-    }\r
-    $("#p2p_node_group").on('click',".del_node", onBtnClick_p2p);\r
-\r
-\r
-    $("#p2mp_select_ok").click(function () {\r
-        var $p2mp_add_node = $("#p2mp_select option:selected");\r
-        if (!$p2mp_add_node.html()) return;\r
-\r
-        if ($("#p2mp_node_group").find("tr").eq(1).find("td").eq(1).children().length == 0) {\r
-            $("#p2mp_node_group").find("tr").eq(1).find("td").eq(1).html("<span>" + $p2mp_add_node.html() + "</span>" + "<input type='button' class='btn_ del_p2mp_node' value='Delete'/>");\r
-            //console.log($("#p2mp_node_group").find("tr").eq(1).find("td").html());\r
-             $p2mp_add_node.remove();\r
-        }\r
-    });\r
-    $("#p2mp_select_ok2").click(function () {\r
-        var $p2mp_add_node = $("#p2mp_select option:selected");\r
-        if (!$p2mp_add_node.html()) return;\r
-   \r
-            $("#p2mp_node_group").find("tr:last").find("td").eq(1).html("<span>" + $p2mp_add_node.html() + "</span>" + "<input type='button' class='btn_ del_p2mp_node' value='Delete'/>");\r
-            $tr = $("<tr><td></td><td></td></tr>");\r
-            $("#p2mp_node_group table").append($tr);\r
-            $p2mp_add_node.remove();\r
-    });\r
-    var onBtnClick_p2mp = function () {\r
-        var node_name = $(this).prev().html();\r
-        //console.log($("#p2mp_node_group tr").index($(this).parent().parent()));\r
-        if ($("#p2mp_node_group tr").index($(this).parent().parent()) == 1) {\r
-            $(this).prev().remove(); $(this).remove();\r
-        }\r
-        else {\r
-            $(this).parent().parent().remove();\r
-        }\r
-        $("#p2mp_select").prepend("<option value=" + node_name + ">" + node_name + "</option>");\r
-        $("#p2mp_select").get(0).selectedIndex = 0;\r
-\r
-    }\r
-    $("#p2mp_node_group").on('click', ".del_p2mp_node",onBtnClick_p2mp);\r
-\r
-    $("#mesh_select_ok").click(function () {\r
-        var $add_node = $("#mesh_select option:selected");\r
-        if (!$add_node.html()) return;\r
-\r
-        $("#mesh_node_group").find("tr:last").find("td").eq(1).html("<span>" + $add_node.html() + "</span>" + "<input type='button' class='btn_ del_mesh_node' value='Delete'/>");\r
-        $tr = $("<tr><td></td><td></td></tr>");\r
-        $("#mesh_node_group table").append($tr);\r
-        $add_node.remove();\r
-    });\r
-    var onBtnClick_mesh = function () {\r
-        var node_name = $(this).prev().html();\r
-        //console.log($("#p2mp_node_group tr").index($(this).parent().parent()));\r
-        if ($("#mesh_node_group tr").index($(this).parent().parent()) == 1) {\r
-            $(this).prev().remove(); $(this).remove();\r
-        }\r
-        else {\r
-            $(this).parent().parent().remove();\r
-        }\r
-        $("#mesh_select").prepend("<option value=" + node_name + ">" + node_name + "</option>");\r
-        $("#mesh_select").get(0).selectedIndex = 0;\r
-\r
-    }\r
-    $("#mesh_node_group").on('click', ".del_mesh_node",onBtnClick_mesh);\r
-\r
-    $("#chain_select_ok").click(function () {\r
-        var $add_node = $("#chain_select option:selected");\r
-        if (!$add_node.html()) return;\r
-\r
-        $("#chain_node_group").find("tr:last").find("td").eq(1).html("<span>" + $add_node.html() + "</span>" + "<input type='button' class='btn_ del_chain_node' value='Delete'/>");\r
-        $tr = $("<tr><td></td><td></td></tr>");\r
-        $("#chain_node_group table").append($tr);\r
-        $add_node.remove();\r
-    });\r
-    var onBtnClick_chain = function () {\r
-        var node_name = $(this).prev().html();\r
-        //console.log($("#p2mp_node_group tr").index($(this).parent().parent()));\r
-        if ($("#chain_node_group tr").index($(this).parent().parent()) == 1) {\r
-            $(this).parent().parent().remove();\r
-        }\r
-        else {\r
-            $(this).parent().parent().remove();\r
-        }\r
-        $("#chain_select").prepend("<option value=" + node_name + ">" + node_name + "</option>");\r
-        $("#chain_select").get(0).selectedIndex = 0;\r
-    }\r
-    //$(".del_chain_node").live('click', onBtnClick_chain);\r
-\r
-    //host group add and delete button,is useless now!\r
-    /*\r
-    $(".add_node").click(function () {\r
-        var index = $(".select_table").index($(this).parents("table"));\r
-        var $host_ = $(".select_table").eq(index).find("tr").eq(1).find("td").children().eq(0).children("option:selected");\r
-        $(".select_table").eq(index).find("select").eq(1).append($host_);\r
-        var lc = lgroup_aviable_node.indexOf($host_.val());\r
-        lgroup_aviable_node.splice(lc, 1);\r
-    });\r
-    $(".del_node").click(function () {\r
-        var index = $(".select_table").index($(this).parents("table"));\r
-        var $host_ = $(".select_table").eq(index).find("select").eq(1).children("option:selected");\r
-        $(".select_table").eq(index).find("select").eq(0).append($host_);\r
-        lgroup_aviable_node.push($host_.val());\r
-    });\r
-    $(".add_group").click(function () {\r
-        var index = $(".select_table").index($(this).parents("table"));\r
-        var $group_ = $(".select_table").eq(index).find("select").eq(2).children("option:selected");\r
-        //console.log($group_.val());\r
-        $(".select_table").eq(index).find("select").eq(3).append($group_);\r
-        var lc = group_node.indexOf($group_.val());\r
-        group_node.splice(lc, 1);\r
-    });\r
-    $(".del_group").click(function () {\r
-        var index = $(".select_table").index($(this).parents("table"));\r
-        var $group_ = $(".select_table").eq(index).find("select").eq(3).children("option:selected");\r
-        console.log($group_.val());\r
-        $(".select_table").eq(index).find("select").eq(2).append($group_);\r
-        group_node.push($group_.val());\r
-    }); */\r
-\r
-    //close entity type\r
-    $(".NE_close_show").click(function () {\r
-        $(".NE_close_item").hide();\r
-        $(".NE_close_item input[type=text]").val("");\r
-        //able change node type\r
-        $("#sel_show").attr("disabled", false);\r
-        //able change connection type \r
-        $("#con_type").attr("disabled", false);\r
-        //remove empty entity \r
-\r
-        $("#sel_2 option").each(function () {\r
-            if ($(this).val() == "empty")\r
-                $(this).remove();\r
-        });\r
-        //$("#sel_2").get(0).selectedIndex = 0;\r
-    });\r
-    //delete_event\r
-    $("#NE_Delete").click(function () {\r
-        if ($("#sel_2 option:selected").val() == 'empty') return;\r
-        //trigger entity_type close event\r
-        $(".NE_close_show").click();\r
-\r
-        $("#entity_type").attr("disabled", false);\r
-        var sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-        var entity_name = $(".NE_up #sel_2").children('option:selected').val();\r
-        var position;\r
-        if (sevice_name == "" || entity_name == "") return;\r
-        //alert(entity_name);\r
-        if (!entity_name || typeof (entity_name) == "undefined") return;\r
-        //////////////////////////////////////////zm/////////////////////////////////////////////////////////////\r
-        //delete node\r
-      if (entity_name.indexOf('node:') >= 0) {\r
-            var str = new Array();\r
-            var flag_group = 0;\r
-            str = entity_name.split(':');\r
-\r
-                       var node_name_delete = entity_name.split(':')[1];\r
-            // flag_group = 1 found in the list  flag_group = 0 not found in the list\r
-            try {\r
-\r
-                               for(var chain_cursor = 0;chain_cursor<$("#service_svg g").length;chain_cursor++)\r
-                               {\r
-                                       if($("#service_svg g:eq("+chain_cursor+")").attr("type")!="chain-group")\r
-                                               continue;\r
-                                       if($("#service_svg g:eq("+chain_cursor+")").attr("sub").indexOf(node_name_delete)>-1)\r
-                                       {\r
-                                               alert("Please delete the chain-group:"+$("#service_svg g:eq("+chain_cursor+")").attr("id")+" firstly!");\r
-                                               return;\r
-                                       }                                               \r
-                               }                                       \r
-                               for(var conn_cursor = 0;conn_cursor<$("#service_svg path").length;conn_cursor++)\r
-                               {\r
-                                       console.log($("#service_svg path:eq("+conn_cursor+")").attr("id"));\r
-                                       if($("#service_svg path:eq("+conn_cursor+")").attr("type")=="connection")\r
-                                       {\r
-                                               if($("#service_svg path:eq("+conn_cursor+")").attr("node_start") == node_name_delete ||$("#service_svg path:eq("+conn_cursor+")").attr("node_end") == node_name_delete)\r
-                                               {\r
-                                                       alert("Please delete the connection "+$("#service_svg path:eq("+conn_cursor+")").attr("id")+" firstly!");\r
-                                                       return;\r
-                                               }\r
-                                               \r
-                                       }\r
-                               }\r
-                               $("#"+node_name_delete).remove();\r
-                               redraw_node_possition();\r
-                               redraw_connection_possition();\r
-                               redraw_flow_possition();\r
-            }\r
-            catch (err) {\r
-                alert(err);\r
-            }\r
-        }\r
-            //delete connection\r
-        else if (entity_name.indexOf('connection:') >= 0) {\r
-            //alert('delete connection');\r
-            try \r
-                       {\r
-                               var conn_name_delete =  entity_name.split(':')[1];\r
-                               var src_group = $("#"+conn_name_delete).attr("node_start");\r
-                               var dest_group = $("#"+conn_name_delete).attr("node_end");\r
-                               for(var i=0; i<$("#service_svg path").length;i++)\r
-                               {\r
-                                       if($("#service_svg path:eq("+i+")").attr("type") == "flow")\r
-                                       {\r
-                                               var flow_start = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                               var flow_end = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                               var flow_via = $("#service_svg path:eq("+i+")").attr("via").split(",")[0];\r
-                                               if(((src_group == flow_start)&&(dest_group == flow_end))||((src_group == flow_end)&&(dest_group == flow_start)))\r
-                                               {\r
-                                                       alert("Please delete the flow "+$("#service_svg path:eq("+i+")").attr("id").split("_")[0]+" firstly!");\r
-                                                       return;\r
-                                               }\r
-                                               if(((src_group == flow_start)&&(dest_group == flow_via))||((src_group == flow_via)&&(dest_group == flow_start)))\r
-                                               {\r
-                                                       alert("Please delete the flow "+$("#service_svg path:eq("+i+")").attr("id").split("_")[0]+" firstly!");\r
-                                                       return;\r
-                                               }\r
-                                               if(((src_group == flow_via)&&(dest_group == flow_end))||((src_group == flow_end)&&(dest_group == flow_via)))\r
-                                               {\r
-                                                       alert("Please delete the flow "+$("#service_svg path:eq("+i+")").attr("id").split("_")[0]+" firstly!");\r
-                                                       return;\r
-                                               }\r
-                                       }       \r
-                               }       \r
-                               $("#"+conn_name_delete).remove();\r
-            }\r
-\r
-            catch (err) {\r
-                alert(err);\r
-            }\r
-        }\r
-               \r
-               else if (entity_name.indexOf('flow:') >= 0) {\r
-                       var flow_name_delete =  entity_name.split(':')[1];\r
-                       for(var i=0;i<$("#service_svg path").length;i++)\r
-                       {\r
-                               if($("#service_svg path:eq("+i+")").attr("type") != "flow")\r
-                                       continue;\r
-                               console.log(i);\r
-                               console.log("#service_svg path:eq("+i+")");\r
-                               console.log($("#service_svg path:eq("+i+")"));\r
-                               console.log($("#service_svg path:eq("+i+")").attr("id"));\r
-                               if($("#service_svg path:eq("+i+")").attr("id").indexOf(flow_name_delete)>-1)\r
-                               {\r
-                                       if($("#service_svg path:eq("+i+")").attr("via").split(",")[0]!="none")\r
-                                       {\r
-                                               alert("please delete the operation firstly!");\r
-                                               return;\r
-                                       }\r
-                               }       \r
-                       }\r
-                       $("#"+flow_name_delete).remove();\r
-                       \r
-               }\r
-               var svg_str = $("#service_svg").html();\r
-               localStorage.setItem(sevice_name+"_svg",svg_str);\r
-        //////////////////////////////////////////zm/////////////////////////////////////////////////////////////\r
-\r
-        var $currentEntity = $("#sel_2 option:selected").val();\r
-        var entity = entity_name.split(":");\r
-        var cur_ent_info_key = sevice_name + "__" + entity_name.replace(':', '_');\r
-\r
-        //check the entity that the policy applied to\r
-        $("#nemo_str_show p").each(function () {\r
-            check_policy($(".NE_up #sel_2 option:selected").val());\r
-        });\r
-\r
-        //if delete the node , the sub node be free , the node must be removed from the group ,useless\r
-        var node_name=$("#sel_2").val();\r
-        var j = sevice_name + "__" + $("#sel_2").val().replace(':', '_');\r
-        var json_str = localStorage.getItem(j);\r
-        var json = jQuery.parseJSON(json_str);\r
-\r
-        if (json[j]["Entity_Type"] == "node") {\r
-            if (json[j]["node_type"] == "l2-group" || json[j]["node_type"] == "l3-group")\r
-            {\r
-                 var lc = lgroup_aviable_node.indexOf(node_name.replace("node","l2-group"));\r
-                 if(lc>=0)\r
-                 lgroup_aviable_node.splice(lc, 1); \r
-\r
-                 var lc2 = lgroup_aviable_node.indexOf(node_name.replace("node","l3-group"));\r
-                 if(lc2>=0)\r
-                 lgroup_aviable_node.splice(lc2, 1);   \r
-\r
-                 console.log(lgroup_aviable_node);\r
-                for (i in json[j]["sub-node"]["sub-node"]) {\r
-                    lgroup_aviable_node.push(json[j]["sub-node"]["sub-node"][i]);\r
-                    $("#nemo_str_show p").each(function () {\r
-                      if($(this).html().indexOf("IMPORT") >=0 && $(this).html().indexOf(json[j]["sub-node"]["sub-node"][i].split(":")[1]) >0)\r
-                      {\r
-                        $(this).remove();\r
-                      }\r
-                     });\r
-                } \r
-\r
-            }\r
-            if (json[j]["node_type"] == "fw" || json[j]["node_type"] == "lb" || json[j]["node_type"] == "cache" )\r
-            {\r
-                   var lc = chain_aviable_node.indexOf(node_name.replace("node","fw"));\r
-                   if(lc>=0)\r
-                   chain_aviable_node.splice(lc, 1);    \r
-                   var lc2 = chain_aviable_node.indexOf(node_name.replace("node","lb"));\r
-                   if(lc2>=0)\r
-                   chain_aviable_node.splice(lc2, 1);    \r
-                  var lc3 = chain_aviable_node.indexOf(node_name.replace("node","cache"));\r
-                   if(lc3>=0)\r
-                   chain_aviable_node.splice(lc3, 1);    \r
-            } \r
-            if(json[j]["node_type"] == "chain-group"){\r
-               for(var subIndex in json[j]["sub-node"]["sub-node"]){\r
-                       chain_aviable_node.push(json[j]["sub-node"]["sub-node"][subIndex]);\r
-               }\r
-            }\r
-        var lgroup = {};\r
-        lgroup.lgroup_aviable_node=lgroup_aviable_node;\r
-        localStorage.setItem(sevice_name+"_lgroup_aviable_node",JSON.stringify(lgroup));\r
-         console.log(localStorage.getItem(sevice_name+"_lgroup_aviable_node"));\r
-        var chain_node = {};\r
-        chain_node.chain_aviable_node=chain_aviable_node;\r
-        localStorage.setItem(sevice_name+"_chain_aviable_node",JSON.stringify(chain_node));\r
-                    \r
-        }\r
-\r
-        //console.log(lgroup_aviable_node);\r
-        //if delete node the connection delete also. caution edit and delete!      \r
-        if (entity[0] == "node") {\r
-            $(".NE_up #sel_2 option").each(function () {\r
-                var ent_name = $(this).val();\r
-                //console.log(ent_name);\r
-                if (ent_name == "" || typeof (ent_name) == "undefined") return;\r
-                var type = $(this).val().split(":");\r
-                //console.log("type:"+type);\r
-                if (type[0] == "node")\r
-                    return true;\r
-                var j = sevice_name + "__" + $(this).val().replace(':', '_');\r
-                         \r
-                var json_str = localStorage.getItem(j);\r
-                var json = jQuery.parseJSON(json_str);\r
-                if (json[j]["Entity_Type"] != "connection") return true;\r
-                var del = false;\r
-                console.log("connection json:" + json);\r
-                if (json[j]["connection_type"] == "p2p") {\r
-                    if (json[j]["End-nodes"]["one_node_name"] == entity[1] || json[j]["End-nodes"]["other_node_name"] == entity[1]) {\r
-                        del = true;\r
-                    }\r
-                }\r
-                if (json[j]["connection_type"] == "p2mp") {\r
-                    if (json[j]["End-nodes"]["one_node_name"] == entity[1]) {\r
-                        del = true;\r
-                    }\r
-                    for (d in json[j]["End-nodes"]["other_node_name"]) {\r
-                        if (json[j]["End-nodes"]["other_node_name"][d] == entity[1]) {\r
-                            if (json[j]["End-nodes"]["other_node_name"].length == 1) {\r
-                                del = true;\r
-                            }\r
-                            else {\r
-                                json[j]["End-nodes"]["other_node_name"].splice(d, 1);\r
-                                console.log(json[j]["End-nodes"]["other_node_name"]);\r
-                                console.log(json[j]);\r
-                                localStorage.removeItem(sevice_name + "__" + $(this).val().replace(':', '_'));\r
-\r
-                                localStorage.setItem(sevice_name + "__" + $(this).val().replace(':', '_'), '{"' + sevice_name + '__' + $(this).val().replace(":", "_") + '":' + JSON.stringify(json[j]) + "}");\r
-                                console.log("current_json:" + JSON.stringify(json[j]));\r
-                            }\r
-                        }\r
-                    }\r
-\r
-                }\r
-                if (del == true) {\r
-                    var cur_connection_id = json[j]["connection_id"];\r
-  \r
-                    var en = $(this).val();\r
-                    $("#nemo_str_show p").each(function () {\r
-                        console.log($(this).html());\r
-                        vali_str = en.split(":");\r
-\r
-                        if ($(this).html().indexOf("Connection") >= 0 && $(this).html().indexOf(vali_str[1]) >= 0) {\r
-                            if ($(this).hasClass("grey_background")) {\r
-                               var nemoSet = $(this).html().split(" ");\r
-                               var deleSet = $currentEntity.split(":");\r
-                                //$("#nemo_str_show").append("<p><span class='key'>DELETE </span>" +deleSet[0]+" "+deleSet[1]+ "</p>");\r
-                            }\r
-                            else {\r
-                                $(this).remove();\r
-                            }\r
-                             return false;\r
-                        }\r
-                    });\r
-\r
-                    $obj=$(this);\r
-\r
-                    if ($(this).hasClass("grey_background")) {\r
-                        str = localStorage.getItem(sevice_name + "__" + $(this).val().replace(':', '_'));;\r
-                        localStorage.setItem(evice_name + "__delete_" + $(this).val().replace(':', '_'), str);\r
-                        console.log();\r
-                    }\r
-\r
-                    //$obj.remove();\r
-\r
-                    //localStorage.removeItem(sevice_name + "__" + $(this).val().replace(':', '_'));\r
-                }\r
-            });\r
-        }\r
-\r
-        var $select_entity = $(".NE_up #sel_2 option:selected");\r
-        $(".NE_up #sel_2 option:selected").remove();\r
-        $(".NE_up #sel_2").get(0).selectedIndex = 0;\r
-        var $op_ob;\r
-        $("#nemo_str_show p").each(function () {\r
-            // console.log($(this).html());\r
-            vali_str = entity_name.split(":");\r
-            //console.log(entity_name);\r
-            var entity_type_ = "";\r
-            if (vali_str[0] == "node")\r
-                entity_type_ = "Node";\r
-            else if (vali_str[0] == "connection")\r
-                entity_type_ = "Connection";\r
-            else\r
-                entity_type_ = "Flow";\r
-            console.log(entity_type_);\r
-            console.log(vali_str[1]);\r
-            if ($(this).html().indexOf(entity_type_) > 0 && $(this).html().indexOf(vali_str[1]) >= 0) {\r
-                {\r
-                    $op_ob = $(this);\r
-                    //$(this).remove();\r
-                    return false;\r
-                }\r
-            }\r
-        });\r
-\r
-        if ($select_entity.hasClass("grey_background")) {\r
-               //var nemoSet = $op_ob.html().split(" ");\r
-            //$("#nemo_str_show").append("<p><span class='key'>Delete </span>" + nemoSet[2] + "</p>");\r
-            var deleSet=$select_entity.val().split(":");\r
-            console.log(deleSet);\r
-            if(deleSet[0]=="node")\r
-            $("#nemo_str_show").append("<p><span class='key'>DELETE Node </span>" + deleSet[1]+ "</p>");\r
-            if(deleSet[0]=="connection")\r
-            $("#nemo_str_show").append("<p><span class='key'>DELETE Connection </span>" + deleSet[1]+ "</p>");\r
-            if(deleSet[0]=="flow")\r
-            $("#nemo_str_show").append("<p><span class='key'>DELETE Flow </span>" + deleSet[1]+ "</p>");\r
-            str = localStorage.getItem(cur_ent_info_key);\r
-            localStorage.setItem(sevice_name + "__delete_" + entity_name.replace(':', '_'), str);\r
-            console.log(sevice_name + "__delete_" + entity_name.replace(':', '_')+":"+str);\r
-        }\r
-        else {\r
-            $op_ob.remove();\r
-        }\r
-        localStorage.removeItem(cur_ent_info_key);\r
-        //update nemo string\r
-        setnemo_str();\r
-        //update instance list\r
-        setentity_instance_list();\r
-        setentity_instance_list_();\r
-    });\r
-    //query nodes ,show in select\r
-    $("#p2p_node-name1").change(function () {\r
-        get_nodes("p2p_node-name2");\r
-        $("#p2p_node-name2 option[value=" + $('#p2p_node-name1').children('option:selected').val() + "]").remove();\r
-\r
-    });\r
-\r
-    //edit_event\r
-    var flag = false;//edit flag\r
-    $("#NE_Edit").click(function () {\r
-        //validate service and entity name \r
-        var sevice_name = "";\r
-        var entity_name = "";\r
-        sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-        entity_name = $(".NE_up #sel_2").children('option:selected').text();\r
-        if (sevice_name == "" || entity_name == "") return;\r
-        if (!entity_name || typeof (entity_name) == "undefined") return;\r
-\r
-        //get json string\r
-        var entity = sevice_name + "__" + entity_name.replace(':', '_');\r
-        var json_str = localStorage.getItem(entity);\r
-        if (!json_str || typeof (json_str) == "undefined") return;\r
-        console.log(json_str);\r
-        //set Entity type\r
-        var val = $("#sel_2").children("option:selected").val();\r
-        if (!val || typeof (val) == "undefined" ) return;\r
-        //trigger close event\r
-        $(".NE_close_show").click();//clear content\r
-        var s = val.split(":");\r
-        $("#entity_type option[value=" + s[0] + "]").attr("selected", true);\r
-        flag = true;//add event use this flag\r
-        //trigger add entity  event\r
-        $("#add_entity").click();\r
-        flag = true;//save event use this flag\r
-        //can't change entity type and node name\r
-        $("#entity_type").attr("disabled", true);\r
-        $("#node_name").attr("disabled", true);\r
-        $("#sel_show").attr("disabled", true);\r
-        $("#connection_name").attr("disabled", true);\r
-        $("#con_type").attr("disabled", true);\r
-        $("#flow_name").attr("disabled", true);\r
-        $("#p2p_node-name1").attr("disabled", true);\r
-        $("#p2p_node-name2").attr("disabled", true);\r
-        $("#p2mp_node-name1").attr("disabled", true);\r
-        $("#p2mp_node-name2 table input").attr("disabled", true);\r
-        //var json = eval('(' + json_str + ')');\r
-        var json = jQuery.parseJSON(json_str);\r
-        if (json[entity]["Entity_Type"] == "node") {\r
-            $("#node_id").val(json[entity]["node_id"]);\r
-            $("#node_name").val(json[entity]["node_name"]);\r
-            if (json[entity]["node_type"] == "fw") {\r
-                $("#sel_show").get(0).selectedIndex = 4;\r
-                $("#fw_location").val(json[entity]["property"]["location"]);\r
-                $("#fw_operating-mode").val(json[entity]["property"]["operating-mode"]);\r
-            }\r
-            else if (json[entity]["node_type"] == "lb") {\r
-                $("#sel_show").get(0).selectedIndex = 5;\r
-                $("#lb_location").val(json[entity]["property"]["location"]);\r
-                $("#lb_operating-mode").val(json[entity]["property"]["operating-mode"]);\r
-            }\r
-            else if (json[entity]["node_type"] == "cache") {\r
-                $("#sel_show").get(0).selectedIndex = 6;\r
-                $("#cache_location").val(json[entity]["property"]["location"]);\r
-                $("#cache_operating-mode").val(json[entity]["property"]["operating-mode"]);\r
-            }\r
-            else if (json[entity]["node_type"] == "l2-group") {\r
-                $("#sel_show").get(0).selectedIndex = 0;\r
-                /*\r
-                for (var i in json[entity]["sub-node"]["sub-node_host"]) {\r
-                    var host = json[entity]["sub-node"]["sub-node_host"][i];\r
-                    //console.log(host);\r
-                    $("#l2_delhost").append("<option value=" + host + ">" + host + "</option>");\r
-                    var lc = lgroup_aviable_node.indexOf(host);\r
-                    lgroup_aviable_node.splice(lc, 1);\r
-                }\r
-                for (var i in json[entity]["sub-node"]["sub-node_group"]) {\r
-                    var group = json[entity]["sub-node"]["sub-node_group"][i];\r
-                    //console.log(group);\r
-                    $("#l2_delgroup").append("<option value=" + group + ">" + group + "</option>");\r
-                    var lc = group_node.indexOf(group);\r
-                    group_node.splice(lc, 1);\r
-                }\r
-                */\r
-                for (var i in json[entity]["sub-node"]["sub-node"]) {\r
-                    $l2_select_node = $("<tr><td align='center'>" + json[entity]["sub-node"]["sub-node"][i] + "</td><td><input type='button' class='btn_ del_sub_node' value='delete'/></td></tr>");\r
-                    $("#l2_select_table").append($l2_select_node);\r
-                }\r
-                $("#l2-group_ip-prefix").val(json[entity]["property"]["ip-prefix"]);\r
-                $("#l2-group_gateway-ip").val(json[entity]["property"]["gateway-ip"]);\r
-                $("#l2-group_location").val(json[entity]["property"]["location"]);\r
-            }\r
-            else if (json[entity]["node_type"] == "l3-group") {\r
-                $("#sel_show").get(0).selectedIndex = 1;\r
-                /*\r
-                for (var i in json[entity]["sub-node"]["sub-node_host"]) {\r
-                    var host = json[entity]["sub-node"]["sub-node_host"][i];\r
-                    //console.log(host);\r
-                    $("#l3_delhost").append("<option value=" + host + ">" + host + "</option>");\r
-                    var lc = lgroup_aviable_node.indexOf(host);\r
-                    lgroup_aviable_node.splice(lc, 1);\r
-                }\r
-                for (var i in json[entity]["sub-node"]["sub-node_group"]) {\r
-                    var group = json[entity]["sub-node"]["sub-node_group"][i];\r
-                    //console.log(group);\r
-                    $("#l3_delgroup").append("<option value=" + group + ">" + group + "</option>");\r
-                    var lc = group_node.indexOf(group);\r
-                    group_node.splice(lc, 1);\r
-                }\r
-                */\r
-                for (var i in json[entity]["sub-node"]["sub-node"]) {\r
-                    $l3_select_node = $("<tr><td align='center'>" + json[entity]["sub-node"]["sub-node"][i] + "</td><td><input type='button' class='btn_ del_sub_node' value='delete'/></td></tr>");\r
-                    $("#l3_select_table").append($l3_select_node);\r
-                }\r
-                $("#l3-group_ip-prefix").val(json[entity]["property"]["ip-prefix"]);\r
-                //$("#l3-group_capacity").val(json[entity]["property"]["capacity"]);\r
-            }\r
-            else if (json[entity]["node_type"] == "ext-group") {\r
-                $("#sel_show").get(0).selectedIndex = 2;\r
-                \r
-                $("#ext-group_location").val(json[entity]["property"]["location"]);\r
-                $("#ext-group_ac-info-network").val(json[entity]["property"]["ac-info-network"]);\r
-                $("#ext-group_ac-info-protocol").val(json[entity]["property"]["ac-info-protocol"]);\r
-                $("#ext-group_ip-prefix").val(json[entity]["property"]["ip-prefix"]);\r
-            }\r
-              else if (json[entity]["node_type"] == "chain-group") {\r
-                $("#sel_show").get(0).selectedIndex = 3;\r
-                $("#chain_select_table").empty();\r
-                for (var i in json[entity]["sub-node"]["sub-node"]) {\r
-                    $chain_select_node = $("<tr><td align='center'>" + json[entity]["sub-node"]["sub-node"][i] + "</td><td><input type='button' class='btn_ del_sub_node' value='Delete'/></td></tr>");\r
-                    $("#chain_select_table").append($chain_select_node);\r
-                }\r
-                //$("#chain-group_ip-prefix").val(json[entity]["property"]["ip-prefix"]);\r
-                //$("#l3-group_capacity").val(json[entity]["property"]["capacity"]);\r
-            }\r
-\r
-        }\r
-        else if (json[entity]["Entity_Type"] == "connection") {\r
-            $("#connection_id").val(json[entity]["connection_id"]);\r
-            $("#connection_name").val(json[entity]["connection_name"]);\r
-            if (json[entity]["connection_type"] == "p2p") {\r
-                $("#con_type").get(0).selectedIndex = 0;\r
-                //$("#p2p_node-name1 option[value=" + json[entity]["End-nodes"]["one_node_name"] + "]").attr("selected", true);\r
-               // $("#p2p_node-name2 option[value=" + json[entity]["End-nodes"]["other_node_name"] + "]").attr("selected", true);\r
-                $("#p2p_node_group table tr:eq(1) td:eq(1)").append("<span>"+json[entity]["End-nodes"]["one_node_name"]+"</span>");\r
-                $("#p2p_node_group table tr:eq(3) td:eq(1)").append("<span>" + json[entity]["End-nodes"]["other_node_name"] + "</span>");\r
-            }\r
-            else if (json[entity]["connection_type"] == "p2mp") {\r
-                $("#con_type").get(0).selectedIndex = 1;\r
-                // $("#p2mp_node-name1 option[value=" + json[entity]["End-nodes"]["one_node_name"] + "]").attr("selected", true);\r
-\r
-                //$("#p2mp_node-name2 table tr").children("input").attr("selected", false);\r
-                $("#con_type").change();\r
-                // for (var d in json[entity]["End-nodes"]["other_node_name"]) {\r
-                //     $("#p2mp_node-name2 table").find("tr").each(function () {\r
-                //         //alert($(this).html());\r
-                //         if ($(this).children('td').eq(1).text() == json[entity]["End-nodes"]["other_node_name"][d]) {\r
-                //             $(this).children('td').eq(0).children('input').attr("checked", true);\r
-                //         }\r
-                //     });\r
-                // }\r
-                $("#p2mp_node_group table tr:eq(1) td:eq(1)").append("<span>"+json[entity]["End-nodes"]["one_node_name"]+"</span>");\r
-                $("#p2mp_node_group table tr:last").remove();\r
-                for (var i in json[entity]["End-nodes"]["other_node_name"]) {\r
-                    $tr=$("<tr><td></td><td><span>" + json[entity]["End-nodes"]["other_node_name"][i] + "</span></td></tr>");\r
-                    $("#p2mp_node_group table").append($tr);\r
-                }\r
-\r
-            }\r
-            else if (json[entity]["connection_type"] == "mesh") {\r
-                $("#con_type").get(0).selectedIndex = 2;\r
-                $("#con_type").change();\r
-                $("#mesh_node_group table tr:last").remove();\r
-                for (var i in json[entity]["node"]) {\r
-                    $tr = $("<tr><td></td><td>" + json[entity]["node"][i] + "</td></tr>");\r
-                    $("#mesh_node_group table").append($tr);\r
-                }\r
-            }\r
-            else {\r
-                $("#con_type").get(0).selectedIndex = 3;\r
-                $("#con_type").change();\r
-                $("#chain_node_group table tr:last").remove();\r
-                for (var i in json[entity]["node"]) {\r
-                    $tr = $("<tr><td></td><td>" + json[entity]["node"][i] + "</td></tr>");\r
-                    $("#chain_node_group table").append($tr);\r
-                }\r
-            }\r
-            $("#bandwidth").val(json[entity]["property"]["bandwidth"]);\r
-            $("#latency").val(json[entity]["property"]["latency"]);\r
-            $("#Jitter").val(json[entity]["property"]["Jitter"]);\r
-\r
-        }\r
-        else {\r
-            $("#flow_id").val(json[entity]["flow_id"]);\r
-            $("#flow_name").val(json[entity]["flow_name"]);\r
-            /*src_ip = json[entity]["match_items"]["src_ip"];\r
-            dest_ip = json[entity]["match_items"]["dest_ip"];\r
-            src_port = json[entity]["match_items"]["src_port"];\r
-            dest_port = json[entity]["match_items"]["dest_port"];\r
-            protocol = json[entity]["match_items"]["protocol"];\r
-            vlanid = json[entity]["match_items"]["vlanid"];\r
-            bidirect = json[entity]["match_items"]["bidirect"];*/\r
-            $("#eth_type").val(json[entity]["match_items"]["eth-type"]);\r
-            $("#src_mac").val(json[entity]["match_items"]["src-mac"]);\r
-            $("#dst_mac").val(json[entity]["match_items"]["dst-mac"]);\r
-            $("#protocol").val(json[entity]["match_items"]["protocol"]);\r
-            $("#src_ip").val(json[entity]["match_items"]["src-ip"]);\r
-            $("#dst_ip").val(json[entity]["match_items"]["dst-ip"]);\r
-            $("#src_port").val(json[entity]["match_items"]["src-port"]);\r
-            $("#dst_port").val(json[entity]["match_items"]["dst-port"]);\r
-        }\r
-\r
-        //trigger change event\r
-        $("#sel_show").change();\r
-        //validate trigger\r
-        $(".alert_").attr("src", "src/app/nemo/images/alert.png");\r
-        $("#mac_icon").attr("src", "");\r
-        $("#host_mac_address").blur();\r
-        $("#node_name").blur();\r
-        $("#flow_name").blur();\r
-        $("#host_ip_address").blur();\r
-        $("#host_location").blur();\r
-        $("#firewall_location").blur();\r
-        //$("#forwarding_location").blur();\r
-        $("#internet_location").blur();\r
-\r
-        $("#loadBlance_location").blur();\r
-        $("#group_location").blur();\r
-\r
-        //connection property\r
-        $("#connection_name").blur();\r
-        //bandwidth\r
-        //$("#bandwidth").blur();\r
-\r
-        //flow property\r
-        // $("#src_ip").blur();\r
-        // $("#dest_ip").blur();\r
-        // $("#src_port").blur();\r
-        // $("#dest_port").blur();\r
-        // $("#vlanid").blur();\r
-        // $("#protocol").blur();\r
-        // //disable node type\r
-        // $("#sel_show").attr("disabled", true);\r
-        // //disable connection type \r
-        // $("#con_type").attr("disabled", true);\r
-        ne_flag = 1;\r
-    });\r
-\r
-    var node_match_flag = false;\r
-    var connection_match_flag = false;\r
-    var flow_match_flag = false;\r
-    var ip_match_flag = false;\r
-    var host_location_match_flag = false;\r
-    var firewall_location_match_flag = false;\r
-    // var forwarding_location_match_flag = false;\r
-    var internet_location_match_flag = false;\r
-    var mac_match_flag = true;\r
-\r
-    var match_null = /^[\s ]*$/;\r
-    var match_underflow_ip_pattern = /^\s*(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\s*$/;\r
-\r
-    var match_underflow_port_pattern = /^([1-5]\d{0,4}|6[0-5]{2}[0-3][0-5]|[6-9]\d{0,3})$/;\r
-\r
-    var bandwidth_flag = true;\r
-    var bandwidth_null_flag = false;\r
-\r
-    var flow_src_ip_flag = true;\r
-    var flow_dest_ip_flag = true;\r
-    var flow_src_port_flag = true;\r
-    var flow_dest_port_flag = true;\r
-    var flow_protocol_flag = true;\r
-    var flow_vlanid_flag = true;\r
-    var flow_src_ip_null_flag = false;\r
-    var flow_dest_ip_null_flag = false;\r
-    var flow_src_port_null_flag = false;\r
-    var flow_dest_port_null_flag = false;\r
-    var flow_protocol_null_flag = false;\r
-    var flow_vlanid_null_flag = false;\r
-    //node_name\r
-    $("#node_name").blur(function () {\r
-        var node_name_val = $("#node_name").val();\r
-        //var node_match_flag = false;\r
-        var match_null = /^[\s ]*$/;\r
-        if (match_null.test(node_name_val)) {\r
-            node_match_flag = false;\r
-            $("#node_icon")[0].src = "src/app/nemo/images/alert.png";\r
-        }\r
-        else {\r
-            node_match_flag = true;\r
-            $("#node_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-    });\r
-\r
-    //connection_name\r
-    $("#connection_name").blur(function () {\r
-        var connection_name_val = $("#connection_name").val();\r
-        //var node_match_flag = false;\r
-        var match_null = /^[\s ]*$/;\r
-        if (match_null.test(connection_name_val)) {\r
-            connection_match_flag = false;\r
-            $("#connection_icon")[0].src = "src/app/nemo/images/alert.png";\r
-        }\r
-        else {\r
-            connection_match_flag = true;\r
-            $("#connection_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-    });\r
-\r
-    //flow_name\r
-    $("#flow_name").blur(function () {\r
-        var flow_name_val = $("#flow_name").val();\r
-        //var node_match_flag = false;\r
-        var match_null = /^[\s ]*$/;\r
-        if (match_null.test(flow_name_val)) {\r
-            flow_match_flag = false;\r
-            $("#flow_icon")[0].src = "src/app/nemo/images/alert.png";\r
-        }\r
-        else {\r
-            flow_match_flag = true;\r
-            $("#flow_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-    });\r
-\r
-    //host_ip_address\r
-    $("#host_ip_address").blur(function () {\r
-        //var ip_match_flag = false;\r
-        var host_ip = $("#host_ip_address").val();\r
-        //var match_ip_pattern = /^\s*(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\s*$/;\r
-        var match_ip_pattern = /^\s*(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])(?:\/[1-9]|\/1[0-9]|\/2[0-4]){0,1}\s*$/;\r
-        var match_null = /^[\s]*$/;\r
-        if (match_ip_pattern.test(host_ip)) {\r
-            ip_match_flag = true;\r
-            $("#ip_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(host_ip)) {\r
-            ip_match_flag = false;\r
-            $("#ip_icon")[0].src = "src/app/nemo/images/alert.png";\r
-            //$("#host_ip_address").val("please input ip addresa");\r
-        }\r
-        else {\r
-            ip_match_flag = false;\r
-            $("#ip_icon")[0].src = "src/app/nemo/images/error.png";\r
-\r
-        }\r
-    });\r
-\r
-    //host_location\r
-    $("#host_location").blur(function () {\r
-        var host_loc = $("#host_location").val();\r
-        //var location_match_flag = false;\r
-        var match_null = /^[\s]*$/;\r
-        if (match_null.test(host_loc)) {\r
-            host_location_match_flag = false;\r
-            $("#host_loc_icon")[0].src = "src/app/nemo/images/alert.png";\r
-            //$("#host_ip_address").val("please input ip addresa");\r
-        }\r
-        else {\r
-            host_location_match_flag = true;\r
-            $("#host_loc_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-    });\r
-\r
-    //host_mac_address\r
-    $("#host_mac_address").blur(function () {\r
-        //var mac_match_flag = false;\r
-        var host_mac = $("#host_mac_address").val();\r
-        var match_mac_pattern = /^\s*(?:(?:\d{2}):){5}(?:\d{2})\s*$/;\r
-        var match_null = /^[\s]*$/;\r
-        if (match_mac_pattern.test(host_mac)) {\r
-            mac_match_flag = true;\r
-            $("#mac_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(host_mac)) {\r
-            mac_match_flag = true;\r
-            $("#mac_icon")[0].src = "";\r
-            //$("#host_ip_address").val("please input ip addresa");\r
-        }\r
-        else {\r
-            mac_match_flag = false;\r
-            $("#mac_icon")[0].src = "src/app/nemo/images/error.png";\r
-        }\r
-    });\r
-\r
-    //firewall_location\r
-    $("#firewall_location").blur(function () {\r
-        var firewall_loc = $("#firewall_location").val();\r
-        //var location_match_flag = false;\r
-        var match_null = /^[\s]*$/;\r
-        if (match_null.test(firewall_loc)) {\r
-            firewall_location_match_flag = false;\r
-            $("#firewall_loc_icon")[0].src = "src/app/nemo/images/alert.png";\r
-            //$("#host_ip_address").val("please input ip addresa");\r
-        }\r
-        else {\r
-            firewall_location_match_flag = true;\r
-            $("#firewall_loc_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-    });\r
-\r
-    //forwarding_location\r
-    //$("#forwarding_location").blur(function () {\r
-    //    var forwarding_loc = $("#forwarding_location").val().trim();\r
-    //    //var location_match_flag = false;\r
-    //    var match_null = /^[\s]*$/;\r
-    //    if (match_null.test(forwarding_loc)) {\r
-    //        forwarding_location_match_flag = false;\r
-    //        $("#forwarding_loc_icon")[0].src = "src/app/nemo/images/alert.png";\r
-    //        //$("#host_ip_address").val("please input ip addresa");\r
-    //    }\r
-    //    else {\r
-    //        forwarding_location_match_flag = true;\r
-    //        $("#forwarding_loc_icon")[0].src = "src/app/nemo/images/ok.png";\r
-    //    }\r
-    //});\r
-\r
-    //internet_location\r
-    $("#internet_location").blur(function () {\r
-        var internet_loc = $("#internet_location").val();\r
-        var match_null = /^[\s]*$/;\r
-        if (match_null.test(internet_loc)) {\r
-            internet_location_match_flag = false;\r
-            $("#internet_loc_icon")[0].src = "src/app/nemo/images/alert.png";\r
-        }\r
-        else {\r
-            internet_location_match_flag = true;\r
-            $("#internet_loc_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-    });\r
-\r
-    //bandwidth\r
-    $("#bandwidth").blur(function () {\r
-        var bandwidth = $("#bandwidth").val();\r
-        var match_bandwidth = /^\+?[1-9][0-9]*$/;\r
-        if (match_bandwidth.test(bandwidth)) {\r
-            bandwidth_flag = true;\r
-            bandwidth_null_flag = true;\r
-            //$("#bandwidth_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(bandwidth)) {\r
-            bandwidth_flag = true;\r
-            bandwidth_null_flag = false;\r
-           // $("#bandwidth_icon")[0].src = "src/app/nemo/images/null.gif";\r
-        }\r
-        else {\r
-            bandwidth_flag = false;\r
-            bandwidth_null_flag = true;\r
-            //$("#bandwidth_icon")[0].src = "src/app/nemo/images/error.png";\r
-        }\r
-    });\r
-    //validate data under flow\r
-    //flow_src_ip\r
-    $("#src_ip").blur(function () {\r
-        var src_ip = $("#src_ip").val();\r
-        //if (match_underflow_ip_pattern.test(src_ip)) {\r
-           // flow_src_ip_flag = true;\r
-           // flow_src_ip_null_flag = true;\r
-            //$("#src_ip_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        //}\r
-        //else if (match_null.test(src_ip)) {\r
-          //  flow_src_ip_flag = true;\r
-            //flow_src_ip_null_flag = false;\r
-            //$("#src_ip_icon")[0].src = "src/app/nemo/images/null.gif";\r
-       // }\r
-        //else {\r
-            //flow_src_ip_flag = false;\r
-           // flow_src_ip_null_flag = true;\r
-           // $("#src_ip_icon")[0].src = "src/app/nemo/images/error.png";\r
-        //}\r
-    });\r
-\r
-    //flow_dest_ip\r
-    $("#dest_ip").blur(function () {\r
-        var dest_ip = $("#dest_ip").val();\r
-        if (match_underflow_ip_pattern.test(dest_ip)) {\r
-            flow_dest_ip_flag = true;\r
-            flow_dest_ip_null_flag = true;\r
-            //$("#dest_ip_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(dest_ip)) {\r
-            flow_dest_ip_flag = true;\r
-            flow_dest_ip_null_flag = false;\r
-            //$("#dest_ip_icon")[0].src = "src/app/nemo/images/null.gif";\r
-        }\r
-        else {\r
-            flow_dest_ip_flag = false;\r
-            flow_dest_ip_null_flag = true;\r
-            //$("#dest_ip_icon")[0].src = "src/app/nemo/images/error.png";\r
-        }\r
-    });\r
-\r
-    //flow_src_port_flag\r
-    $("#src_port").blur(function () {\r
-        var src_port = $("#src_port").val();\r
-        if (match_underflow_port_pattern.test(src_port)) {\r
-            flow_src_port_flag = true;\r
-            flow_src_port_null_flag = true;\r
-            //$("#src_port_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(src_port)) {\r
-            flow_src_port_flag = true;\r
-            flow_src_port_null_flag = false;\r
-            //$("#src_port_icon")[0].src = "src/app/nemo/images/null.gif";\r
-        }\r
-        else {\r
-            flow_src_port_flag = false;\r
-            flow_src_port_null_flag = true;\r
-            //$("#src_port_icon")[0].src = "src/app/nemo/images/error.png";\r
-        }\r
-    });\r
-\r
-    //flow_dest_port_flag\r
-    $("#dest_port").blur(function () {\r
-        var dest_port = $("#dest_port").val();\r
-        if (match_underflow_port_pattern.test(dest_port)) {\r
-            flow_dest_port_flag = true;\r
-            flow_dest_port_null_flag = true;\r
-            //$("#dest_port_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(dest_port)) {\r
-            flow_dest_port_flag = true;\r
-            flow_dest_port_null_flag = false;\r
-            //$("#dest_port_icon")[0].src = "src/app/nemo/images/null.gif";\r
-        }\r
-        else {\r
-            flow_dest_port_flag = false;\r
-            flow_dest_port_null_flag = true;\r
-            //$("#dest_port_icon")[0].src = "src/app/nemo/images/error.png";\r
-        }\r
-    });\r
-\r
-    //protocol\r
-    $("#protocol").blur(function () {\r
-        var protocol_val = $("#protocol").val();\r
-        var match_protocol_pattern = /^[\s\S]*$/;\r
-        if (match_protocol_pattern.test(protocol_val)) {\r
-            flow_protocol_flag = true;\r
-            flow_protocol_null_flag = true;\r
-            //$("#protocol_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(protocol_val)) {\r
-            flow_protocol_flag = true;\r
-            flow_protocol_null_flag = false;\r
-            //$("#protocol_icon")[0].src = "src/app/nemo/images/null.gif";\r
-        }\r
-        else {\r
-            flow_protocol_flag = false;\r
-            flow_protocol_null_flag = true;\r
-            //$("#protocol_icon")[0].src = "src/app/nemo/images/error.png";\r
-        }\r
-    });\r
-\r
-    //vlanid\r
-    $("#vlanid").blur(function () {\r
-        var vlanid_val = $("#vlanid").val();\r
-        var match_vlanid_pattern = /^[1-9]\d*$/;\r
-        if (match_vlanid_pattern.test(vlanid_val)) {\r
-            flow_vlanid_flag = true;\r
-            flow_vlanid_null_flag = true;\r
-            //$("#vlanid_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-        else if (match_null.test(vlanid_val)) {\r
-            flow_vlanid_flag = true;\r
-            flow_vlanid_null_flag = false;\r
-            //$("#vlanid_icon")[0].src = "src/app/nemo/images/null.gif";\r
-        }\r
-        else {\r
-            flow_vlanid_flag = false;\r
-            flow_vlanid_null_flag = true;\r
-            //$("#vlanid_icon")[0].src = "src/app/nemo/images/error.png";\r
-        }\r
-    });\r
-    ///////////////////////////////////////////zm/////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-\r
-    function Edge_Judgment(z, m) {\r
-        //alert('begin to judge');\r
-        for (var i = 1; i <= Edge_Id; i++) {\r
-            var edg = edges.get(i);\r
-            if (edg == null)\r
-                continue;\r
-            if (edg.from == z && edg.to == m)\r
-                return 1;\r
-            else if (edg.from == m && edg.to == z)\r
-                return 1;\r
-            else\r
-                continue;\r
-        }\r
-        //alert('not exist!');\r
-        return 0;\r
-    }\r
-\r
-    ///////////////////////////////////////////zm/////////////////////////////////////////////////////////////\r
-\r
-    //save event\r
-    $(".net_entity_save").click(function () {\r
-         sevice_name_glb = $(".NE_up #sel_1").children('option:selected').val();\r
-         entity_name_glb = $(".NE_up #sel_2").children('option:selected').text();\r
-        var entity_col = sevice_name_glb + "__" + entity_name_glb.replace(':', '_');\r
-        var json_str_col = localStorage.getItem(entity_col);\r
-        console.log(json_str_col);\r
-        \r
-        var nemo_str = "";\r
-        //validate data type\r
-        var data_flag = false;\r
-        var selected_entity_type = $("#entity_type").children('option:selected').val();\r
-        var selected_node_type = $("#sel_show").children('option:selected').val();\r
-\r
-        /********************************* CN/EN *************************************************/\r
-\r
-        if (selected_entity_type == "node") {\r
-            if (!node_match_flag) {\r
-                alert("请输入一个正确的结点名称");\r
-                return;\r
-            }\r
-            else if (selected_node_type == "host") {\r
-                if (!ip_match_flag) {\r
-                    alert("请输入一个正确的IP地址,形如:1.1.1.1");\r
-                    return;\r
-                } else if (!host_location_match_flag) {\r
-                    alert("请输入一个正确的资源名称");\r
-                    return;\r
-                } else if (!mac_match_flag) {\r
-                    alert("请输入一个正确的MAC地址");\r
-                    return;\r
-                }\r
-            } else if (selected_node_type == "firewall") {\r
-                if (!firewall_location_match_flag) {\r
-                    alert("请输入一个正确的资源名称");\r
-                    return;\r
-                }\r
-            } else if (selected_node_type == "forwarding") {\r
-                //alert(forwarding_location_match_flag);\r
-\r
-            } else if (selected_node_type == "internet") {\r
-                if (!internet_location_match_flag) {\r
-                    alert("请输入一个正确的资源名称");\r
-                    return;\r
-                    //alert("please input a correct internet location");\r
-                }\r
-            }\r
-\r
-        } else if (selected_entity_type == "connection") {\r
-            if (!connection_match_flag) {\r
-                alert("请输入一个正确的连接名称");\r
-                return;\r
-            }\r
-            else if (!bandwidth_flag) {\r
-                alert("请输入一个带宽,为大于0的整数");\r
-                return;\r
-            }\r
-        } else {\r
-            if (!flow_match_flag) {\r
-                alert("请输入一个正确的业务流名称");\r
-                return;\r
-            }\r
-            else if (!flow_src_ip_flag) {\r
-                alert("请输入一个正确的源IP地址,形如:1.1.1.1");\r
-                return;\r
-            }\r
-            else if (!flow_dest_ip_flag) {\r
-                alert("请输入一个正确的目的IP地址,形如:1.1.1.1");\r
-                return;\r
-            }\r
-            else if (!flow_src_port_flag) {\r
-                alert("请输入一个正确的源端口号:1-65535");\r
-                return;\r
-            }\r
-            else if (!flow_dest_port_flag) {\r
-                alert("请输入一个正确的目的端口号:1-65535");\r
-                return;\r
-            }\r
-            else if (!flow_protocol_flag) {\r
-                alert("请输入一个正确的协议类型");\r
-                return;\r
-            }\r
-            else if (!flow_vlanid_flag) {\r
-                alert("请输入一个正确的VLAN ID");\r
-                return;\r
-            }\r
-        }\r
-               if (selected_entity_type == "flow") \r
-               {\r
-                       var src_group=flow_get_group()[0];\r
-                       var dest_group=flow_get_group()[1];                     \r
-                       if(src_group == '' || dest_group == '')\r
-                       {\r
-                               alert("Wrong ip address");\r
-                               return;\r
-                       }\r
-                       \r
-                               //no conn no flow (validate)\r
-                       var exist_flag = 0;\r
-                       for(var i=0; i<$("#service_svg path").length;i++)\r
-                       {\r
-                               if($("#service_svg path:eq("+i+")").attr("type") == "connection")\r
-                               {\r
-                                       var node_name_old_1 = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                       var node_name_old_2 = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                       console.log("old:"+node_name_old_1+"  "+node_name_old_2);\r
-                                       if(((src_group == node_name_old_1)&&(dest_group == node_name_old_2))||((src_group == node_name_old_2)&&(dest_group == node_name_old_1)))\r
-                                       {\r
-                                               exist_flag = 1;\r
-                                       }               \r
-                               }       \r
-                       }\r
-                       if(exist_flag == 0)\r
-                       {\r
-                               alert("No connection!");\r
-                               return;\r
-                       }               \r
-                       \r
-               }\r
-               if(flag==false)\r
-               {\r
-                       if(selected_entity_type == "node") \r
-                       {\r
-                       if($("#sel_show").children('option:selected').val()=="chain-group"){\r
-                               if($("#chain_select_table tr").length == 0){\r
-                                       alert("Cannot create chain-group with zero subnode");\r
-                                       return;\r
-                               }\r
-                       }\r
-                       \r
-                       }\r
-                       if (selected_entity_type == "connection") \r
-                       {\r
-                               for(var i=0; i<$("#service_svg path").length;i++)\r
-                               {\r
-                                       if($("#service_svg path").attr("type") == "connection")\r
-                                       {\r
-                                               var exist_flag = 0;\r
-                                               var node_name_1 = get_connection_node()[0];\r
-                                               var node_name_2 = get_connection_node()[1];\r
-                                               var node_name_old_1 = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                               var node_name_old_2 = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                               if(((node_name_1 == node_name_old_1)&&(node_name_2 == node_name_old_2))||((node_name_1 == node_name_old_2)&&(node_name_2 == node_name_old_1)))\r
-                                               {\r
-                                                       alert("A connection has existed!");\r
-                                                       exist_flag = 1;\r
-                                                       return;\r
-                                               }\r
-                                                       \r
-                                       }\r
-                                               \r
-                               }\r
-                       \r
-                       }\r
-                       \r
-                       \r
-               }\r
-               else if(flag==true)\r
-               {\r
-                       var Net_Operation = $("#entity_type").children('option:selected').val();\r
-                       var Node_Type = $("#sel_show").children('option:selected').val();\r
-                       if(Net_Operation == "node")\r
-                       {\r
-                               var node_name_del_validate = $("#node_name").val().trim();\r
-                               if(Node_Type == "l2-group" || Node_Type == "l3-group")\r
-                               {\r
-                                       for(var flow_cursor = 0;flow_cursor<$("#service_svg path").length;flow_cursor++)\r
-                                       {\r
-                                               if($("#service_svg path:eq("+flow_cursor+")").attr("type")!="flow")\r
-                                                       continue;\r
-                                               if($("#service_svg path:eq("+flow_cursor+")").attr("node_start") == node_name_del_validate ||$("#service_svg path:eq("+flow_cursor+")").attr("node_end") == node_name_del_validate)\r
-                                               {\r
-                                                       alert("There has been a flow related to this group,please delete the flow "+$("#service_svg path:eq("+flow_cursor+")").attr("id")+" firstly!");\r
-                                                       return;\r
-                                               }\r
-                                       }\r
-                               }\r
-                               else if(Node_Type == "chain-group" )\r
-                               {\r
-                                       if($("#chain_select_table tr").length == 0)\r
-                                       {\r
-                                               alert("The chain-group will be deleted due to the delete of the last vas point of this chain!");        \r
-                                               for(var connection_cursor = 0;connection_cursor<$("#service_svg path").length;connection_cursor++)\r
-                                               {\r
-                                                       if($("#service_svg path:eq("+connection_cursor+")").attr("type")!="connection")\r
-                                                               continue;\r
-                                                       if($("#service_svg path:eq("+connection_cursor+")").attr("node_start") == node_name_del_validate ||$("#service_svg path:eq("+connection_cursor+")").attr("node_end") == node_name_del_validate)\r
-                                                       {\r
-                                                               alert("There has been a flow or a connection related to this group,please delete it firstly!");\r
-                                                               return;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       \r
-                               }\r
-                               \r
-                       }\r
-                       else if(Net_Operation == "connection")\r
-                       {\r
-                               \r
-                       }\r
-                       else if(Net_Operation == "flow")\r
-                       {\r
-                               var flow_name_validate =  $("#flow_name").val().trim();\r
-                               for(var i=0;i<$("#service_svg path").length;i++)\r
-                               {\r
-                                       if($("#service_svg path:eq("+i+")").attr("type") != "flow")\r
-                                               continue;\r
-                                       if($("#service_svg path:eq("+i+")").attr("id").indexOf(flow_name_validate)>-1)\r
-                                       {\r
-                                               if($("#service_svg path:eq("+i+")").attr("via").split(",")[0]!="none")\r
-                                               {\r
-                                                       alert("The flow can't be edited,please delete the operation firstly!");\r
-                                                       return;\r
-                                               }\r
-                                       }       \r
-                               }\r
-                       }\r
-\r
-               }\r
-        sevice_name = $("#sel_1").children('option:selected').val();\r
-        if (sevice_name == "") return;\r
-        var entity_instance_list = localStorage.getItem(sevice_name + "_entity_instance_list");\r
-        console.log(entity_instance_list);\r
-\r
-        //create node\r
-\r
-\r
-        //create entity list\r
-        instance_name = "";\r
-        if ($("#entity_type").children('option:selected').val() == "node") {\r
-\r
-            instance_name = "node:" + $("#node_name").val().trim();\r
-        }\r
-        else if ($("#entity_type").children('option:selected').val() == "connection") {\r
-            instance_name = "connection:" + $("#connection_name").val().trim();\r
-        }\r
-        else {\r
-            instance_name = "flow:" + $("#flow_name").val().trim();\r
-        }\r
-        //validate name\r
-        if (entity_instance_list && typeof (entity_instance_list) != "undefined" && entity_instance_list != 0) {\r
-            entity_list = entity_instance_list.split(",");\r
-            var validate = 0;\r
-            if (flag == false) {\r
-                for (var v = 0; v < entity_list.length; v++) {\r
-                    if (entity_list[v] == instance_name) {\r
-                        $("#ety_dialog").dialog({\r
-                            height: 240,\r
-                            width: 400,\r
-                            modal: true,\r
-                            open: function (event, ui) { $(".ui-dialog-titlebar-close").hide(); },\r
-                            buttons: {\r
-                                "Ok": function () { $(this).dialog("close"); }\r
-                            }\r
-                        });\r
-                        validate = 1;\r
-                        return false;\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        /********************************* CN/EN *************************************************/\r
-\r
-        var $edit_option=$(".NE_up #sel_2 option:selected");\r
-        //edit hande\r
-        //console.log(flag);\r
-        if (flag == true) {\r
-            //trigger delete event\r
-            //$('#NE_Delete').click();\r
-\r
-            //trigger entity_type close event  \r
-            var sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-            var entity_name = $(".NE_up #sel_2").children('option:selected').val();\r
-            var position;\r
-             //console.log(sevice_name+" "+entity_name);\r
-            if (sevice_name == "" || entity_name == "") return;\r
-\r
-            //alert(entity_name);\r
-            if (!entity_name || typeof (entity_name) == "undefined") return;\r
-            localStorage.removeItem(sevice_name + "__" + entity_name.replace(':', '_'));\r
-            $(".NE_up #sel_2 option:selected").remove();\r
-            //disable node type\r
-            $("#sel_show").attr("disabled", true);\r
-            //disable connection type \r
-            $("#con_type").attr("disabled", true);\r
-\r
-        }\r
-\r
-        if (validate == 1)\r
-            return;\r
-        if ($edit_option.hasClass("grey_background"))\r
-            $(".NE_up #sel_2").prepend("<Option class='grey_background' value='" + instance_name + "'>" + instance_name + "</Option>");\r
-        else\r
-            $(".NE_up #sel_2").prepend("<Option value='" + instance_name + "'>" + instance_name + "</Option>");\r
-\r
-        $(".NE_up #sel_2").get(0).selectedIndex = 0;\r
-\r
-        //create json string\r
-        json_str = '{';\r
-        service_name = $(".NE_up #sel_1").children('option:selected').val();\r
-        if (service_name == null) return;\r
-        json_str += '"' + service_name + "__" + instance_name.replace(':', '_') + '":{';\r
-        if ($("#entity_type").children('option:selected').val() == "node") {\r
-           var node_type = $("#sel_show").children('option:selected').val();\r
-            json_str += '"Entity_Type":"node",';\r
-            if (node_type == 'l2-group'){\r
-               console.log("1");\r
-               if($("#node_name").val().trim().toLowerCase()=="dmz"){\r
-                        json_str += '"node_id":"b46cfa7f-93a3-43f4-ac20-09307c75feca",';                       \r
-                       }\r
-               else if($("#node_name").val().trim().toLowerCase()=="interior"){\r
-                        json_str += '"node_id":"175425f7-c9c9-474a-962c-70cb6c180d4d",';         \r
-                       }\r
-               else\r
-                       json_str += '"node_id":"' + $("#node_id").val().trim() + '",';\r
-           }\r
-           else{\r
-            json_str += '"node_id":"' + $("#node_id").val().trim() + '",';\r
-        }\r
-\r
-            json_str += '"node_name":"' + $("#node_name").val().trim() + '",';\r
-           \r
-            if (node_type == 'fw') {\r
-                chain_aviable_node.push("fw:" + $("#node_name").val().trim());\r
-                \r
-                nemo_str += "<span class='key'>IMPORT Node </span>";\r
-                nemo_str += $("#node_name").val().trim() + " ";\r
-                nemo_str += "<span class='key'>Type</span> fw "\r
-                nemo_str += "<span class='key'>Property </span>";\r
-                if ($('#fw_location').val().trim() != "")\r
-                    nemo_str += "location:" + '"'+$('#fw_location').val().trim() + '",';\r
-                if ($('#fw_operating-mode').val().trim() != "")\r
-                    nemo_str += "" + "operating-mode:" +'"'+ $('#fw_operating-mode').val().trim() + '",';\r
-                nemo_str = nemo_str.substring(0,nemo_str.length-1);\r
-\r
-                json_str += '"node_type":"fw",';\r
-                json_str += '"property":{';\r
-                json_str += '"location":"' + $('#fw_location').val().trim() + '",';\r
-                json_str += '"operating-mode":"' + $('#fw_operating-mode').val().trim() + '"}';\r
-                json_str += '}';\r
-            }\r
-            else if (node_type == 'lb') {\r
-\r
-                chain_aviable_node.push("lb:" + $("#node_name").val().trim());\r
-\r
-                nemo_str += "<span class='key'>IMPORT Node </span>";\r
-                nemo_str += $("#node_name").val().trim() + " ";\r
-                nemo_str += "<span class='key'>Type </span>lb "\r
-                nemo_str += "<span class='key'>Property </span>";\r
-                if ($('#lb_location').val().trim() != "")\r
-                    nemo_str += "location:" + '"'+$('#lb_location').val().trim() + '",';\r
-                if ($('#lb_operating-mode').val().trim() != "")\r
-                    nemo_str += "" + "operating-mode:" +'"'+ $('#lb_operating-mode').val().trim() + '",';\r
-                nemo_str = nemo_str.substring(0,nemo_str.length-1);\r
-\r
-                json_str += '"node_type":"lb",';\r
-                json_str += '"property":{';\r
-                json_str += '"location":"' + $('#lb_location').val().trim() + '",';\r
-                json_str += '"operating-mode":"' + $('#lb_operating-mode').val().trim() + '"}';\r
-                json_str += '}';\r
-            }\r
-            else if (node_type == 'l2-group') {\r
-\r
-                lgroup_aviable_node.push("l2-group:" + $("#node_name").val().trim());\r
-                //conn_aviable_node.push("l2-group:" + $("#node_name").val().trim());\r
-\r
-                nemo_str += "<span class='key'>CREATE Node </span>";\r
-                nemo_str += $("#node_name").val().trim() + " ";\r
-                nemo_str += "<span class='key'>Type </span>l2-group ";\r
-                var use_node = new Array();\r
-                //var use_group = new Array();              \r
-               // console.log(lgroup_aviable_node)\r
-                 lgroup_aviable_node = [];\r
-                    $("#l2_addhost option").each(function(){\r
-                       lgroup_aviable_node.push($(this).val());\r
-                    });\r
-\r
-                $("#l2_select_table").find("tr").each(function () {\r
-                    var node_name = $(this).find("td").eq(0).html();\r
-                    use_node.push($(this).find("td").eq(0).html());\r
-                    for (i in lgroup_aviable_node)\r
-                    {\r
-                        if (lgroup_aviable_node[i] == node_name){}\r
-                            //lgroup_aviable_node.splice(i,1);\r
-                    }\r
-                });\r
-                //console.log(lgroup_aviable_node);\r
-                \r
-                if (use_node.length > 0) {\r
-                    nemo_str += "<span class='key'>Contain </span>";\r
-                    for (var i = 0; i < use_node.length; i++) {                      \r
-                        //nemo import host \r
-                    if(use_node[i].indexOf("host")>=0)\r
-                    {\r
-                        if (flag == false)\r
-                        $("#nemo_str_show").append("<p><span class='key'>IMPORT Node </span>" + use_node[i].split(":")[1] + " <span class='key'>Type</span> host</p>");\r
-                        nemo_str += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    else\r
-                    {\r
-                         nemo_str += use_node[i].split(":")[1] + ",";\r
-                    }\r
-\r
-                    }\r
-                    nemo_str = nemo_str.substring(0, nemo_str.length - 1);\r
-                    nemo_str += "";\r
-                }\r
-                \r
-               \r
-                nemo_str += "<span class='key'> Property </span>";\r
-                if ($('#l2-group_ip-prefix').val().trim() != "")\r
-                    nemo_str += "ip-prefix:" + '"'+$('#l2-group_ip-prefix').val().trim() + '",';\r
-                if ($('#l2-group_gateway-ip').val().trim() != "")\r
-                    nemo_str += "" + "gateway-ip:" +'"'+$('#l2-group_gateway-ip').val().trim() + '",';\r
-                if ($('#l2-group_location').val().trim() != "")\r
-                    nemo_str += "" + "location:" +'"'+$('#l2-group_location').val().trim() + '",';\r
-               nemo_str = nemo_str.substring(0,nemo_str.length-1);\r
-\r
-                json_str += '"node_type":"l2-group",';\r
-                json_str += '"sub-node":{';\r
-                json_str += '"sub-node":[';\r
-                if (use_node.length > 0) {\r
-                    for (var i = 0; i < use_node.length; i++) {\r
-                        json_str += '"' + use_node[i] + '"' + ",";\r
-                    }\r
-                    json_str = json_str.substring(0, json_str.length - 1);\r
-                }\r
-                json_str += ']';\r
-               \r
-                json_str += '},';\r
-                json_str += '"property":{';\r
-                json_str += '"ip-prefix":"' + $('#l2-group_ip-prefix').val().trim() + '",';\r
-                json_str += '"gateway-ip":"' + $('#l2-group_gateway-ip').val().trim() + '",';\r
-                json_str += '"location":"' + $('#l2-group_location').val().trim() + '"}';\r
-                json_str += '}';\r
-            }\r
-            else if (node_type == 'l3-group') {\r
-\r
-                lgroup_aviable_node.push("l3-group:" + $("#node_name").val().trim());\r
-                //conn_aviable_node.push("l3-group:" + $("#node_name").val().trim());\r
-\r
-                nemo_str += "<span class='key'>CREATE Node </span>";\r
-                nemo_str += $("#node_name").val().trim() + " ";\r
-                nemo_str += "<span class='key'>Type </span>l3-group "\r
-                var use_node = new Array();\r
-                var use_group = new Array();\r
-                lgroup_aviable_node = [];\r
-                    $("#l3_addhost option").each(function(){\r
-                       lgroup_aviable_node.push($(this).val());\r
-                    });\r
-\r
-                $("#l3_select_table").find("tr").each(function () {\r
-                    var node_name = $(this).find("td").eq(0).html();\r
-                    use_node.push($(this).find("td").eq(0).html());\r
-                    for (i in lgroup_aviable_node) {\r
-                        if (lgroup_aviable_node[i] == node_name){}\r
-                            //lgroup_aviable_node.splice(i, 1);\r
-                    }\r
-                });\r
-\r
-                if (use_node.length > 0) {\r
-                    nemo_str += "<span class='key'>Contain </span>";\r
-                    for (var i = 0; i < use_node.length; i++) {\r
-                        if(use_node[i].indexOf("host")>=0)\r
-                    {\r
-                        if (flag == false)\r
-                        $("#nemo_str_show").append("<p><span class='key'>IMPORT Node </span>" + use_node[i].split(":")[1] + " <span class='key'>Type</span> host</p>");\r
-                        nemo_str += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    else\r
-                    {\r
-                         nemo_str += use_node[i] + ",";\r
-                    }\r
-                    \r
-                    }\r
-                    nemo_str = nemo_str.substring(0, nemo_str.length - 1);\r
-                    nemo_str += "";\r
-                }\r
-                \r
-                nemo_str += "<span class='key'> Property </span>";\r
-                if ($('#l3-group_ip-prefix').val().trim() != "")\r
-                    nemo_str += "ip-prefix:" +'"'+$('#l3-group_ip-prefix').val().trim() + '"';\r
-                //if ($('#l3-group_capacity').val().trim() != "")\r
-                    //nemo_str += "," + "capacity:" + $('#l3-group_capacity').val().trim() + '';\r
-                nemo_str += "";\r
-\r
-                json_str += '"node_type":"l3-group",';\r
-                json_str += '"sub-node":{';\r
-                json_str += '"sub-node":[';\r
-                if (use_node.length > 0) {\r
-                    for (var i = 0; i < use_node.length; i++) {\r
-                        json_str += '"' + use_node[i] + '"' + ",";\r
-                    }\r
-                    json_str = json_str.substring(0, json_str.length - 1);\r
-                }\r
-                json_str += ']';\r
-                \r
-                json_str += '},';\r
-                json_str += '"property":{';\r
-                json_str += '"ip-prefix":"' + $('#l3-group_ip-prefix').val().trim() + '"';\r
-               // json_str += '"capacity":"' + $('#l3-group_capacity').val().trim() + '"}';\r
-                json_str += '}}';\r
-            }\r
-            else if (node_type == 'ext-group') {\r
-                //conn_aviable_node.push("ext-group:" + $("#node_name").val().trim());\r
-\r
-                nemo_str += "<span class='key'>IMPORT Node </span>";\r
-                nemo_str += $("#node_name").val().trim() + " ";\r
-                nemo_str += "<span class='key'>Type </span>ext-group ";\r
-                nemo_str += "<span class='key'> Property </span>";\r
-               if ($('#ext-group_location').val().trim() != "")\r
-                    nemo_str += "location:" + '"'+$('#ext-group_location').val().trim() + '",';\r
-               if ($('#ext-group_ac-info-network').val().trim() != "")\r
-                   nemo_str += "" + "ac-info-network:" +'"'+$('#ext-group_ac-info-network').val().trim() + '",';\r
-               if ($('#ext-group_ac-info-protocol').val().trim() != "")\r
-                   nemo_str += "" + "ac-info-protocol:" +'"'+ $('#ext-group_ac-info-protocol').val().trim() + '",';\r
-               if ($('#ext-group_ip-prefix').val().trim() != "")\r
-                   nemo_str += "" + "ip-prefix:" +'"'+ $('#ext-group_ip-prefix').val().trim() + '",';\r
-                nemo_str += "";\r
-                nemo_str = nemo_str.substring(0,nemo_str.length-1);\r
-\r
-                json_str += '"node_type":"ext-group",';\r
-     \r
-                json_str += '"property":{';\r
-                json_str += '"location":"' + $('#ext-group_location').val().trim() + '",';\r
-                json_str += '"ac-info-network":"' + $('#ext-group_ac-info-network').val().trim() + '",';\r
-                json_str += '"ac-info-protocol":"' + $('#ext-group_ac-info-protocol').val().trim() + '",';\r
-                json_str += '"ip-prefix":"' + $('#ext-group_ip-prefix').val().trim() + '"}';\r
-                json_str += '}';\r
-            }\r
-             else if (node_type == 'chain-group') {\r
-               // chain_node.push("chain-group:" + $("#node_name").val().trim());\r
-\r
-                nemo_str += "<span class='key'>CREATE Node </span>";\r
-                nemo_str += $("#node_name").val().trim() + " ";\r
-                nemo_str += "<span class='key'>Type </span>chain-group "\r
-                var use_node = new Array();\r
-                var use_group = new Array();\r
-                chain_aviable_node = [];\r
-                    $("#chain_addhost option").each(function(){\r
-                       chain_aviable_node.push($(this).val());\r
-                    });\r
-                    console.log(chain_aviable_node);\r
-                $("#chain_select_table").find("tr").each(function () {\r
-                    var node_name = $(this).find("td").eq(0).html();\r
-                    use_node.push($(this).find("td").eq(0).html());\r
-                    for (i in chain_aviable_node) {\r
-                        if (chain_aviable_node[i] == node_name){}\r
-                            //chain_aviable_node.splice(i, 1);\r
-                    }\r
-                });\r
-\r
-                if (use_node.length > 0) {\r
-                    nemo_str += "<span class='key'>Contain </span>";\r
-                    for (var i = 0; i < use_node.length; i++) {\r
-                        if(use_node[i].indexOf("host")>=0)\r
-                    {\r
-                        $("#nemo_str_show").append("<p><span class='key'>IMPORT Node </span>" + use_node[i].split(":")[1] + " <span class='key'>Type</span> host</p>");\r
-                        nemo_str += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    else\r
-                    {\r
-                         nemo_str += use_node[i].split(":")[1]+ ",";\r
-                    }\r
-                    \r
-                    }\r
-                    nemo_str = nemo_str.substring(0, nemo_str.length - 1);\r
-                    nemo_str += "";\r
-                }\r
-                \r
-               \r
-                json_str += '"node_type":"chain-group",';\r
-                json_str += '"sub-node":{';\r
-                json_str += '"sub-node":[';\r
-                if (use_node.length > 0) {\r
-                    for (var i = 0; i < use_node.length; i++) {\r
-                        json_str += '"' + use_node[i] + '"' + ",";\r
-                    }\r
-                    json_str = json_str.substring(0, json_str.length - 1);\r
-                }\r
-                json_str += ']';\r
-                \r
-                json_str += '},';\r
-                json_str += '"property":{';\r
-               //json_str += '"ip-prefix":"' + $('#chain-group_ip-prefix').val().trim() + '"';\r
-               // json_str += '"capacity":"' + $('#chain-group_capacity').val().trim() + '"}';\r
-                json_str += '}}';\r
-\r
-            } else if (node_type == 'cache') {\r
-                chain_aviable_node.push("cache:" + $("#node_name").val().trim());\r
-\r
-                nemo_str += "<span class='key'>IMPORT Node </span>";\r
-                nemo_str += $("#node_name").val().trim() + " ";\r
-                nemo_str += "<span class='key'>Type </span>cache ";\r
-                nemo_str += "<span class='key'> Property </span>";\r
-                if ($('#cache_location').val().trim() != "")\r
-                    nemo_str += "location:" + '"' +$('#cache_location').val().trim() + '",';\r
-               if ($('#cache_operating-mode').val().trim() != "")\r
-                    nemo_str += "" + "operating-mode:" +'"'+$('#cache_operating-mode').val().trim() + '",';\r
-                nemo_str = nemo_str.substring(0,nemo_str.length-1);\r
-\r
-                json_str += '"node_type":"cache",';\r
-     \r
-                json_str += '"property":{';\r
-                json_str += '"location":"' + $('#cache_location').val().trim() + '",';\r
-                json_str += '"operating-mode":"' + $('#cache_operating-mode').val().trim() + '"}';\r
-                json_str += '}';\r
-            }\r
-\r
-        }\r
-        else if ($('#entity_type').children("option:selected").val() == 'connection') {\r
-            nemo_str += "<span class='key'>CREATE Connection </span>";\r
-            //nemo_str += $('#connection_id').val().trim() + " ";\r
-            //nemo_str += "<span class='key'>Name </span>";\r
-            nemo_str += $("#connection_name").val().trim() + " ";\r
-\r
-            json_str += '"Entity_Type":"connection",'\r
-            json_str += '"connection_id":"' + $('#connection_id').val().trim() + '",';\r
-            json_str += '"connection_name":"' + $('#connection_name').val().trim() + '",';\r
-            var conn_type = $('#con_type').children("option:selected").val();\r
-            if (conn_type == 'p2p') {\r
-                nemo_str += "<span class='key'>Type </span>";\r
-                nemo_str += "p2p ";\r
-                nemo_str += "<span class='key'>Endnodes </span>";\r
-                var one_node_name = $("#p2p_node_group").find("tr").eq(1).find("td").eq(1).find("span").html();\r
-                var other_node_name = $("#p2p_node_group").find("tr").eq(3).find("td").eq(1).find("span").html();\r
-                nemo_str += "" + one_node_name + ",";\r
-                nemo_str += "" + other_node_name + "";\r
-\r
-                json_str += '"connection_type":"p2p",';\r
-                json_str += '"End-nodes":{';\r
-                json_str += '"one_node_name":"' + one_node_name + '",';\r
-                json_str += '"other_node_name":"' + other_node_name + '"';\r
-                json_str += '},';\r
-                //json_str += '"property":{}'\r
-                //json_str += '}';\r
-\r
-            }\r
-            else if (conn_type == 'p2mp') {\r
-                nemo_str += "<span class='key'>Type </span>";\r
-                nemo_str += "p2mp ";\r
-                nemo_str += "<span class='key'>End-nodes </span>[";\r
-                var one_node_name = $("#p2mp_node_group").find("tr").eq(1).find("td").eq(1).find("span").html();\r
-                nemo_str += "one_node_name:" + one_node_name + " ";\r
-\r
-                json_str += '"connection_type":"p2mp",';\r
-                json_str += '"End-nodes":{';\r
-                json_str += '"one_node_name":"' + one_node_name + '",';\r
-                var data = [];\r
-                $("#p2mp_node_group table").find("tr:gt(2)").each(function () {\r
-                    if ($(this).find("span").length>0) {\r
-                        data.push($(this).find("span").html());\r
-                    }\r
-                });\r
-                //$("#p2mp_node-name2 table").find(":checkbox:checked").each(function () {\r
-                //    var val = $(this).parent().next().text();\r
-                //    data.push(val);\r
-                //});\r
-                json_str += '"other_node_name":';\r
-                json_str += '[';\r
-                var node_list = "";\r
-                for (var k = 0; k < data.length; k++) {\r
-                    node_list += '"' + data[k] + '",';\r
-                }\r
-                node_list = node_list.substring(0, node_list.length - 1);\r
-                json_str += node_list;\r
-                json_str += ']';\r
-\r
-                json_str += '},';\r
-                //json_str += '"property":{}'\r
-                //json_str += '}';\r
-                nemo_str += "other_node_name:" + data + "]";\r
-            }\r
-            else if (conn_type == 'mesh') {\r
-                var data = [];\r
-                $("#mesh_node_group table").find("tr:gt(0)").each(function () {\r
-                    if ($(this).find("span").length > 0) {\r
-                        data.push($(this).find("span").html());\r
-                    }\r
-                });\r
-                nemo_str += "<span class='key'>Type</span> mesh ";\r
-                nemo_str += "<span class='key'>Nodes </span>"\r
-                nemo_str +=  data + " ";\r
-       \r
-                json_str += '"connection_type":"mesh",';\r
-\r
-                var node_list = "";\r
-                for (var k = 0; k < data.length; k++) {\r
-                    node_list += '"' + data[k] + '",';\r
-                }\r
-                node_list = node_list.substring(0, node_list.length - 1);\r
-                json_str += '"node":';\r
-                json_str += '[';\r
-                json_str += node_list;\r
-                json_str += ']';\r
-                json_str += ',';\r
-\r
-                //json_str += '"property":{}'\r
-                //json_str += '}';\r
-            }\r
-            else {//chain-group,useless\r
-                var data = [];\r
-                $("#chain_node_group table").find("tr:gt(0)").each(function () {\r
-                    if ($(this).find("span").length > 0) {\r
-                        data.push($(this).find("span").html());\r
-                    }\r
-                });\r
-                nemo_str += "<span class='key'>Type</span> chain ";\r
-                nemo_str += "<span class='key'>node</span>["\r
-                nemo_str +=  data + "]";\r
-\r
-                json_str += '"connection_type":"chain",';\r
-\r
-                var node_list = "";\r
-                for (var k = 0; k < data.length; k++) {\r
-                    node_list += '"' + data[k] + '",';\r
-                }\r
-                node_list = node_list.substring(0, node_list.length - 1);\r
-                json_str += '"node":';\r
-                json_str += '[';\r
-                json_str += node_list;\r
-                json_str += ']';\r
-                json_str += ',';\r
-\r
-            }\r
-           \r
-            if ($("#bandwidth").val().trim() != "")\r
-            {\r
-                nemo_str += "<span class='key'>  Property </span>";\r
-                nemo_str += "bandwidth:" + '"'+$("#bandwidth").val().trim()+'"';\r
-            }\r
-            if ($("#latency").val().trim() != "")\r
-            {\r
-               \r
-                nemo_str += ",latency:" + $("#latency").val().trim();\r
-            }\r
-            if ($("#Jitter").val().trim() != "")\r
-            {\r
-                nemo_str += ",Jitter:" + $("#Jitter").val().trim();\r
-            }\r
-            nemo_str += "";\r
-\r
-            json_str += '"property":{';\r
-            json_str += '"bandwidth":"' + $("#bandwidth").val().trim() + '",';\r
-            json_str += '"latency":"' + $("#latency").val().trim() + '",';\r
-            json_str += '"Jitter":"' + $("#Jitter").val().trim() + '"}';\r
-            json_str += '}';\r
-        }\r
-        else {\r
-             eth_type = $("#eth_type").val().trim();\r
-             src_mac = $("#src_mac").val().trim();\r
-             dst_mac = $("#dst_mac").val().trim();\r
-             protocol = $("#protocol").val().trim();\r
-             src_ip = $("#src_ip").val().trim();\r
-             dst_ip = $("#dst_ip").val().trim();\r
-             src_port = $("#src_port").val().trim();\r
-             dst_port = $("#dst_port").val().trim();\r
-\r
-            nemo_str += "<span class='key'>CREATE Flow </span>"\r
-            //nemo_str += $('#flow_id').val().trim() + ' ';\r
-            //nemo_str += "<span class='key'>Name </span>" ;\r
-            nemo_str += $('#flow_name').val().trim() + ' ';\r
-            nemo_str += "<span class='key'>Match </span>";\r
-            //nemo_str += "src_node:" + $("#src_node option:selected").text() + ",";\r
-            //nemo_str += "dest_node:" + $("#dest_node option:selected").text();\r
-            if (eth_type != "")\r
-                nemo_str += "eth-type:" + '"'+eth_type +'",';\r
-            if (src_mac != "")\r
-                nemo_str += "src-mac:" +'"'+ src_mac +'",';\r
-            if (dst_mac != "")\r
-                nemo_str += "dst-mac:" +'"'+ dst_mac +'",';\r
-            if (protocol != "")\r
-                nemo_str += "protocol:" + '"'+protocol +'",';\r
-            if (src_ip != "")\r
-                nemo_str += "src-ip:" + '"'+src_ip +'",';\r
-            if (dst_ip != "")\r
-                nemo_str += "dst-ip:" +'"'+ dst_ip +'",';\r
-            if (src_port != "")\r
-                nemo_str += "src-port:" +'"'+ src_port +'",';\r
-            if (dst_port != "")\r
-                nemo_str += "dst-port:" +'"'+ dst_port +'",';\r
-\r
-            nemo_str = nemo_str.substring(0,nemo_str.length-1);\r
-\r
-            json_str += '"Entity_Type":"flow",'\r
-            json_str += '"flow_id":"' + $('#flow_id').val().trim() + '",';\r
-            json_str += '"flow_name":"' + $('#flow_name').val().trim() + '",';\r
-            json_str += '"match_items":';\r
-            json_str += '{';\r
-            json_str += '"eth-type":"' + eth_type + '",';\r
-            json_str += '"src-mac":"' + src_mac + '",';\r
-            json_str += '"dst-mac":"' + dst_mac + '",';\r
-            json_str += '"protocol":"' + protocol + '",';\r
-            json_str += '"src-ip":"' + src_ip + '",';\r
-            json_str += '"dst-ip":"' + dst_ip + '",';\r
-            json_str += '"src-port":"' + src_port + '",';\r
-            json_str += '"dst-port":"' + dst_port + '"';\r
-            json_str += '}';\r
-            json_str += '}';\r
-        }\r
-        json_str += '}';\r
-        \r
-\r
-        var lgroup = {};\r
-        lgroup.lgroup_aviable_node=lgroup_aviable_node;\r
-        localStorage.setItem(service_name+"_lgroup_aviable_node",JSON.stringify(lgroup));\r
-\r
-        var chain_node = {};\r
-        chain_node.chain_aviable_node=chain_aviable_node;\r
-        //console.log(chain_node);\r
-        localStorage.setItem(service_name+"_chain_aviable_node",JSON.stringify(chain_node));\r
-\r
-        if (flag == true) {\r
-            //the entity has been created,and this is edit\r
-            //console.log("submited:" + $("#sel_2").children("option:selected").attr("class"));\r
-        console.log("submited:" + $("#sel_2").html());\r
-        \r
-        if ($("#sel_2").children("option:selected").hasClass("grey_background")) {\r
-            //nemo show the change property only\r
-           var nemo_str_update="<span class='key'>UPDATE </span>";\r
-            //var json_str = localStorage.getItem(entity);\r
-        \r
-           //if (!sevice_name || !entity_name ) return;\r
-           //console.log(sevice_name+entity_name);\r
-           //get json string\r
-            var entity = sevice_name + "__" + instance_name.replace(':', '_');\r
-            //var json_str = localStorage.getItem(entity);\r
-            // console.log(entity);\r
-            //console.log(json_str);\r
-            if (!json_str_col || typeof (json_str_col) == "undefined") return;\r
-            console.log(json_str_col);\r
-            var $json =JSON.parse(json_str_col);\r
-\r
-            if ($("#entity_type").children('option:selected').val() == "node") {\r
-                    nemo_str_update+="<span class='key'>Node</span> "+$("#node_name").val().trim();\r
-                    var node_type = $("#sel_show").children('option:selected').val();\r
-                 if (node_type == 'fw') {\r
-                   //nemo_str_update += "<span class='key'>Type</span> fw "\r
-                    nemo_str_update += "<span class='key'> Property </span>";\r
-                    if ($('#fw_location').val().trim() != "")\r
-                    nemo_str_update += "location:" + '"'+$('#fw_location').val().trim() + '"';\r
-                     if ($('#fw_operating-mode').val().trim() != "")\r
-                    nemo_str_update += "" + "operating-mode:" +'"'+ $('#fw_operating-mode').val().trim() + '",';\r
-                    nemo_str_update =  nemo_str_update.substring(0, nemo_str_update.length-1);                                 \r
-                    }\r
-                else if(node_type == 'lb'){\r
-                   // nemo_str_update += "<span class='key'>Type </span>lb "\r
-                    nemo_str_update += "<span class='key'> Property </span>";\r
-                    if ($('#lb_location').val().trim() != "")\r
-                    nemo_str_update += "location:" + '"'+$('#lb_location').val().trim() + '",';\r
-                    if ($('#lb_operating-mode').val().trim() != "")\r
-                    nemo_str_update += "" + "operating-mode:" +'"'+ $('#lb_operating-mode').val().trim() + '",';\r
-                     nemo_str_update =  nemo_str_update.substring(0, nemo_str_update.length-1);        \r
-\r
-                    }\r
-                 else if(node_type == 'cache'){\r
-\r
-                                //nemo_str_update += "<span class='key'>Type </span>cache ";\r
-                        nemo_str_update += "<span class='key'> Property </span>";\r
-                        if ($('#cache_location').val().trim() != "")\r
-                     nemo_str_update += "location:" + '"' +$('#cache_location').val().trim() + '",';\r
-                    if ($('#cache_operating-mode').val().trim() != "")\r
-                     nemo_str_update += "" + "operating-mode:" +'"'+$('#cache_operating-mode').val().trim() + '",';\r
-                        nemo_str_update =  nemo_str_update.substring(0, nemo_str_update.length-1);     \r
-\r
-                    }\r
-                 else if(node_type == 'ext-group'){\r
-\r
-                    //nemo_str_update += "<span class='key'>Type </span>ext-group ";\r
-                       nemo_str_update += "<span class='key'> Property </span>";\r
-                       if ($('#ext-group_location').val().trim() != "")\r
-                   nemo_str_update += "location:" + '"'+$('#ext-group_location').val().trim() + '",';\r
-                       if ($('#ext-group_ac-info-network').val().trim() != "")\r
-                    nemo_str_update += "" + "ac-info-network:" +'"'+$('#ext-group_ac-info-network').val().trim() + '",';\r
-                        if ($('#ext-group_ac-info-protocol').val().trim() != "")\r
-                        nemo_str_update += "" + "ac-info-protocol:" +'"'+ $('#ext-group_ac-info-protocol').val().trim() + '",';\r
-                        if ($('#ext-group_ip-prefix').val().trim() != "")\r
-                        nemo_str_update += "" + "ip-prefix:" +'"'+ $('#ext-group_ip-prefix').val().trim() + '",';\r
-                         nemo_str_update =  nemo_str_update.substring(0, nemo_str_update.length-1);    \r
-\r
-                    }\r
-                else if(node_type == 'l2-group'){\r
-\r
-                     //nemo_str_update += "<span class='key'>Type </span>l2-group ";\r
-                     var use_node = new Array();\r
-                    //var use_group = new Array();              \r
-                    // console.log(lgroup_aviable_node)\r
-                    $("#l2_select_table").find("tr").each(function () {\r
-                    var node_name = $(this).find("td").eq(0).html();\r
-                    use_node.push($(this).find("td").eq(0).html());\r
-                    for (i in lgroup_aviable_node)\r
-                    {\r
-                        if (lgroup_aviable_node[i] == node_name)\r
-                            lgroup_aviable_node.splice(i,1);\r
-                    }\r
-\r
-                });\r
-                    if (use_node.length > 0) {\r
-                    nemo_str_update += "<span class='key'> Contain </span>";\r
-                    for (var i = 0; i < use_node.length; i++) {                      \r
-                        \r
-                    if(use_node[i].indexOf("host")>=0)\r
-                    {\r
-                        //$("#nemo_str_show").append("<p><span class='key'>IMPORT Node </span>" + use_node[i].split(":")[1] + " <span class='key'>Type</span> host</p>");\r
-                        nemo_str_update += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    else\r
-                    {\r
-                         nemo_str_update += use_node[i].split(":")[1] + ",";\r
-                    }\r
-         \r
-                    }\r
-                    nemo_str_update = nemo_str_update.substring(0, nemo_str_update.length - 1);\r
-                    nemo_str_update += "";\r
-                   }\r
-\r
-                      if($json[entity_col]["property"]["ip-prefix"]!=$("#l2-group_ip-prefix").val()||$json[entity_col]["property"]["gateway-ip"]!=$("#l2-group_gateway-ip").val())\r
-                       {\r
-                        nemo_str_update+="<span class='key'> Property</span> ";\r
-                        if($json[entity_col]["property"]["ip-prefix"]!=$("#l2-group_ip-prefix").val()){\r
-                            nemo_str_update+="ip-prefix:" + '"'+$("#l2-group_ip-prefix").val()+'"';\r
-                            if($json[entity_col]["property"]["gateway-ip"]!=$("#l2-group_gateway-ip").val())\r
-                                nemo_str_update+=",gateway-ip:" + '"'+$("#l2-group_gateway-ip").val()+'"';\r
-                        }\r
-                        else{\r
-                             nemo_str_update+="gateway-ip:" +'"'+ $("#l2-group_gateway-ip").val()+'"';\r
-                        }              \r
-                       }\r
-                    }\r
-                else if(node_type == 'l3-group'){\r
-                       //nemo_str_update += "<span class='key'>Type </span>l3-group "\r
-                       var use_node = new Array();\r
-                       var use_group = new Array();\r
-\r
-                                $("#l3_select_table").find("tr").each(function () {\r
-                     var node_name = $(this).find("td").eq(0).html();\r
-                     use_node.push($(this).find("td").eq(0).html());\r
-                     for (i in lgroup_aviable_node) {\r
-                        if (lgroup_aviable_node[i] == node_name)\r
-                            lgroup_aviable_node.splice(i, 1);\r
-                    }\r
-                });\r
-\r
-                if (use_node.length > 0) {\r
-                    nemo_str_update += "<span class='key'> Contain </span>";\r
-                    for (var i = 0; i < use_node.length; i++) {\r
-                        if(use_node[i].indexOf("host")>=0)\r
-                    {\r
-                        //$("#nemo_str_show").append("<p><span class='key'>IMPORT Node </span>" + use_node[i].split(":")[1] + " <span class='key'>Type</span> host</p>");\r
-                        nemo_str_update += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    else\r
-                    {\r
-                         nemo_str_update += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    \r
-                    }\r
-                    nemo_str_update = nemo_str_update.substring(0, nemo_str_update.length - 1);\r
-                    nemo_str_update += "";\r
-                   }\r
-                        if($json[entity_col]["property"]["ip-prefix"]!=$("#l3-group_ip-prefix").val())\r
-                       {\r
-                            nemo_str_update+="<span class='key'> Property</span> ";                        \r
-                            nemo_str_update+="ip-prefix:" + '"' +$("#l3-group_ip-prefix").val()+'"';                          \r
-                        }\r
-\r
-                    }else if(node_type == 'chain-group'){\r
-                        //nemo_str_update += "<span class='key'>Type </span>chain-group "\r
-                    var use_node = new Array();\r
-                    var use_group = new Array();\r
-\r
-                    chain_aviable_node = [];\r
-                    $("#chain_addhost option").each(function(){\r
-                       chain_aviable_node.push($(this).val());\r
-                    });\r
-                    console.log(chain_aviable_node);\r
-                    $("#chain_select_table").find("tr").each(function () {\r
-                    var node_name = $(this).find("td").eq(0).html();\r
-                    use_node.push($(this).find("td").eq(0).html());\r
-                    for (i in chain_aviable_node) {\r
-                        if (chain_aviable_node[i] == node_name){}\r
-                            //chain_aviable_node.splice(i, 1);\r
-                    }\r
-                });\r
-\r
-                if (use_node.length > 0) {\r
-                    nemo_str_update += "<span class='key'> Contain </span>";\r
-                    for (var i = 0; i < use_node.length; i++) {\r
-                        if(use_node[i].indexOf("host")>=0)\r
-                    {\r
-                        //$("#nemo_str_show").append("<p><span class='key'>IMPORT Node </span>" + use_node[i].split(":")[1] + " <span class='key'>Type</span> host</p>");\r
-                        //nemo_str_update += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    else\r
-                    {\r
-                         nemo_str_update += use_node[i].split(":")[1] + ",";\r
-                    }\r
-                    \r
-                    }\r
-                    nemo_str_update = nemo_str_update.substring(0, nemo_str_update.length - 1);\r
-                    nemo_str_update += "";\r
-                     }\r
-\r
-                    }\r
-\r
-            }\r
-            else if($("#entity_type").children('option:selected').val() == "connection") {\r
-                nemo_str_update+=" <span class='key'>Connection</span> "+$("#connection_name").val().trim();\r
-                var conn_type = $('#con_type').children("option:selected").val();\r
-                if (conn_type == 'p2p') {\r
-                                       //graph edit \r
-                                       $("#"+$("#connection_name").val().trim()).remove();\r
-                                  nemo_str_update += "<span class='key'> Endnodes </span>";\r
-                   var one_node_name = $("#p2p_node_group").find("tr").eq(1).find("td").eq(1).find("span").html();\r
-                   var other_node_name = $("#p2p_node_group").find("tr").eq(3).find("td").eq(1).find("span").html();\r
-                   nemo_str_update += "" + one_node_name + ",";\r
-                   nemo_str_update += "" + other_node_name + "";\r
-                    if($json[entity_col]["property"]["bandwidth"] != $("#bandwidth").val().trim())\r
-                    {\r
-                        nemo_str_update+="<span class='key'> Property</span> ";\r
-                        nemo_str_update+="bandwidth:" + $("#bandwidth").val();\r
-                    }\r
-\r
-                }\r
-                else if (conn_type == 'p2mp') {\r
-                       \r
-                     if($json[entity_col]["property"]["bandwidth"]!=$("#bandwidth").val())\r
-                    {\r
-                        nemo_str_update+="<span class='key'>Property</span> ";\r
-                        nemo_str_update+="bandwidth:" + $("#bandwidth").val();\r
-                    }\r
-                }\r
-                else{//mesh\r
-                     if($json[entity_col]["property"]["bandwidth"]!=$("#bandwidth").val())\r
-                    {\r
-                        nemo_str_update+="<span class='key'>Property</span> ";\r
-                        nemo_str_update+="bandwidth:" + $("#bandwidth").val();\r
-                    }\r
-\r
-                }\r
-\r
-            }\r
-            else{//flow\r
-             var eth_type_ = $("#eth_type").val().trim();\r
-             var src_mac_ = $("#src_mac").val().trim();\r
-             var dst_mac_ = $("#dst_mac").val().trim();\r
-             var protocol_ = $("#protocol").val().trim();\r
-             var src_ip_ = $("#src_ip").val().trim();\r
-             var dst_ip_ = $("#dst_ip").val().trim();\r
-             var src_port_ = $("#src_port").val().trim();\r
-             var dst_port_ = $("#dst_port").val().trim();\r
-\r
-            nemo_str_update += "<span class='key'>Flow </span>"+$('#flow_name').val().trim() + ' ';\r
-            nemo_str_update += "<span class='key'>Match </span>";\r
-            if (eth_type != "")\r
-                nemo_str_update += "eth-type:" +'"'+ eth_type_ +'",';\r
-            if (src_mac != "")\r
-                nemo_str_update += "src-mac:" + '"'+src_mac_ +'",';\r
-            if (dst_mac != "")\r
-                nemo_str_update += "dst-mac:" + '"'+dst_mac_ +'",';\r
-            if (protocol != "")\r
-                nemo_str_update += "protocol:" + '"'+protocol_ +'",';\r
-            if (src_ip != "")\r
-                nemo_str_update += "src-ip:" + '"'+src_ip_ +'",';\r
-            if (dst_ip != "")\r
-                nemo_str_update += "dst-ip:" + '"'+dst_ip_ +'",';\r
-            if (src_port != "")\r
-                nemo_str_update += "src-port:" + '"'+src_port_ +'",';\r
-            if (dst_port != "")\r
-                nemo_str_update += "dst-port:" + '"'+dst_port_ +'",';\r
-\r
-            nemo_str_update = nemo_str_update.substring(0,nemo_str_update.length-1);\r
-            }\r
-\r
-            var f=0;\r
-             $("#nemo_str_show p").each(function () {\r
-                if($(this).hasClass('grey_background')) return true;\r
-\r
-                if (($(this).text().indexOf($("#node_name").val() + " ") >= 0 && $(this).text().indexOf("Node") >= 0)\r
-                      || ($(this).text().indexOf($("#connection_name").val() + " ") >= 0 && $(this).text().indexOf("Connection") >= 0)\r
-                      || ($(this).text().indexOf($("#flow_name").val() + " ") >= 0 && $(this).text().indexOf("Flow") >= 0)) \r
-                        {\r
-                            $(this).html(nemo_str_update);\r
-                            f=1;\r
-                            return false;\r
-                        }\r
-             });\r
-\r
-             if(f==0){\r
-                $("#nemo_str_show").append("<p>" + nemo_str_update + "</p>");\r
-             }\r
-                \r
-            }\r
-            else {\r
-                $("#nemo_str_show p").each(function () {\r
-                    if (($(this).text().indexOf($("#node_name").val() + " ") >= 0 && $(this).text().indexOf("Node") >= 0)\r
-                      || ($(this).text().indexOf($("#connection_name").val() + " ") >= 0 && $(this).text().indexOf("Connection") >= 0)\r
-                      || ($(this).text().indexOf($("#flow_name").val() + " ") >= 0 && $(this).text().indexOf("Flow") >= 0)) {\r
-                        {\r
-                            $(this).html(nemo_str);\r
-                            return false;\r
-                        }\r
-                    }\r
-                });\r
-            }\r
-        }\r
-        else {\r
-            $("#nemo_str_show").append("<p>" + nemo_str + "</p>");\r
-            //put node into group_node\r
-            if ($("#entity_type").val() == "node") {\r
-                console.log($("#node_name").val());\r
-                //group_node.push($("#node_name").val());\r
-            }\r
-        }\r
-        flag = false;\r
-        //set localstorsge\r
-        console.log(nemo_str);\r
-        console.log(json_str);\r
-        //chain-group delete use \r
-        var chain_str = localStorage.getItem(sevice_name + "__" + instance_name.replace(':', '_'));\r
-        localStorage.removeItem(sevice_name + "__" + instance_name.replace(':', '_'));\r
-        localStorage.setItem(service_name + "__" + instance_name.replace(':', '_'), json_str);\r
-        //clear match data\r
-             eth_type = "";\r
-             src_mac = "";\r
-             dst_mac = "";\r
-             protocol = "";\r
-             src_ip = "";\r
-             dst_ip = "";\r
-             src_port = "";\r
-             dst_port = "";\r
-        ///////////////////////////////////////////zm/////////////////////////////////////////////////////////////\r
-        var Net_Operation = $("#entity_type").children('option:selected').val();\r
-        var Node_Type = $("#sel_show").children('option:selected').val();\r
-           if (Net_Operation == 'node' && flag == false) {\r
-                       try{\r
-                               if(ne_flag == 0){\r
-                                       \r
-                                       if(Node_Type == "l2-group"){\r
-                                               var node_count_list = $("#l2_select_table tr").length;\r
-                                               draw_group(node_count_list,"l2_select_table");\r
-                                               node_count++;\r
-                                               redraw_node_possition();        \r
-                                               redraw_connection_possition();\r
-                                               redraw_flow_possition();\r
-                                       }\r
-                                       else if(Node_Type == "l3-group"){\r
-                                               var node_count_list = $("#l3_select_table tr").length;\r
-                                               draw_group(node_count_list,"l3_select_table");\r
-                                               node_count++;\r
-                                               redraw_node_possition();        \r
-                                               redraw_connection_possition();  \r
-                                               redraw_flow_possition();\r
-                                       }\r
-                                       else if(Node_Type == "chain-group"){\r
-                                               var node_count_list = $("#chain_select_table tr").length;\r
-                                               draw_group(node_count_list,"chain_select_table");\r
-                                               node_count++;\r
-                                               redraw_node_possition();        \r
-                                               redraw_connection_possition();  \r
-                                               redraw_flow_possition();\r
-                                       }\r
-                                       else if(Node_Type == "ext-group"){\r
-                                               draw_group(0,"ext");\r
-                                               node_count++;\r
-                                               redraw_node_possition();        \r
-                                               redraw_connection_possition();\r
-                                               redraw_flow_possition();\r
-                                       }\r
-                               }\r
-                               else if(ne_flag == 1)\r
-                               {\r
-                                       var node_del_name = $("#node_name").val().trim();\r
-                                       var tx = $("#"+node_del_name+"_group").attr("cx");\r
-                                       var ty = $("#"+node_del_name+"_group").attr("cy");\r
-                                       $("#"+node_del_name).remove();\r
-                                       if(Node_Type == "l2-group"){\r
-                                               var node_count_list = $("#l2_select_table tr").length;\r
-                                               draw_group(node_count_list,"l2_select_table");\r
-                                               redraw_specific_node_possition(node_del_name,tx,ty);\r
-                                       }\r
-                                       else if(Node_Type == "l3-group"){\r
-                                               var node_count_list = $("#l3_select_table tr").length;\r
-                                               draw_group(node_count_list,"l3_select_table");\r
-                                               redraw_specific_node_possition(node_del_name,tx,ty);\r
-                                       }\r
-                                       else if(Node_Type == "chain-group")\r
-                                       {\r
-                                               if($("#chain_select_table tr").length > 0)\r
-                                               {\r
-                                                       var node_count_list = $("#chain_select_table tr").length;\r
-                                                       draw_group(node_count_list,"chain_select_table");\r
-                                                       redraw_specific_node_possition(node_del_name,tx,ty);    \r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       //delete chain-group info\r
-                                                       redraw_node_possition();        \r
-                                                       redraw_connection_possition();\r
-                                                       redraw_flow_possition();\r
-                                                       //delete chain-group \r
-                                                       var $dele_obj = $("#sel_2 option:selected");\r
-                                                       if($dele_obj.hasClass('grey_background')){\r
-                                                               $("#nemo_str_show p").append("<p><span class='key'>DELETE Node</span> "+$dele_obj.val().split(":")[1]+"</p>");\r
-                                                               \r
-                                localStorage.setItem(sevice_name + "__delete_" + entity_name.replace(':', '_'), chain_str);\r
-                                                       }\r
-                                                       else{   \r
-                                              $("#nemo_str_show p").each(function () {\r
-                            if ($(this).text().indexOf($("#node_name").val() + " ") >= 0 && $(this).text().indexOf("Node") >= 0 ) {                       \r
-                            $(this).remove();\r
-                            return false;\r
-                        }\r
-                    \r
-                });                                    \r
-                                                       }\r
-\r
-                                                       localStorage.removeItem(sevice_name_glb+"__"+$dele_obj.val().replace(":","_"));\r
-                                                       $dele_obj.remove();\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-            catch (err) {\r
-                               alert(err);\r
-            }\r
-            /* var data = {\r
-                nodes: nodes,\r
-                edges: edges\r
-            };\r
-\r
-            var container = document.getElementById('graph');\r
-            graph = new vis.Graph(container, data, options); */\r
-\r
-        }                       \r
-                      //connection\r
-        else if (Net_Operation == 'connection') {\r
-            //p2p\r
-            if ($('#con_type').children("option:selected").val() == 'p2p') {\r
-                //alert('p2p');\r
-                               var conn_name = $("#connection_name").val();\r
-                if(conn_name!=null && typeof(conn_name)!="undefined")\r
-                $("#"+conn_name).remove();\r
-                try \r
-                               {\r
-                                       var node_name_1 = get_connection_node()[0];\r
-                                       var node_name_2 = get_connection_node()[1];\r
-                                       var node_cx_1 = $("#"+node_name_1+"_group").attr("cx");\r
-                                       var node_cy_1 = $("#"+node_name_1+"_group").attr("cy");\r
-                                       var node_cx_2 = $("#"+node_name_2+"_group").attr("cx");\r
-                                       var node_cy_2 = $("#"+node_name_2+"_group").attr("cy");\r
-                                       //var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                                       var path_main = $(path).attr({\r
-                                               id: $("#connection_name").val().trim(),\r
-                                               node_start:node_name_1,\r
-                                               node_end:node_name_2,\r
-                                               type:"connection",\r
-                                               d: 'M'+node_cx_1 + " " + node_cy_1+' L'+node_cx_2+' '+node_cy_2,\r
-                                               'stroke':"black",\r
-                                               'stroke-width':parseInt($("#bandwidth").val().trim())/100,\r
-                                               fill:"black"\r
-                                       });\r
-                                       $('#service_svg').prepend(path_main);                                           \r
-                }\r
-\r
-                catch (err) {\r
-                    alert(err);\r
-                }\r
-            }\r
-\r
-                //p2mp\r
-\r
-            else if ($('#con_type').children("option:selected").val() == 'p2mp') {\r
-                       }\r
-            \r
-                // mesh\r
-            else {\r
-                       }\r
-           \r
-        }      \r
-               \r
-                       else if (Net_Operation == 'flow' )\r
-               {\r
-                       var flow_delete_name_temp = $("#flow_name").val().trim();\r
-                       var old_color;\r
-                       if(ne_flag == 1)\r
-                       {\r
-                               old_color = $("#"+flow_delete_name_temp).attr("stroke");\r
-                               $("#"+flow_delete_name_temp).remove();\r
-\r
-                       }\r
-                       var src_group=flow_get_group()[0];\r
-                       var dest_group=flow_get_group()[1];\r
-                       //get flow count\r
-                       var flow_count_temp = 0;\r
-                       while(1)\r
-                       {\r
-                               var end_flag = 0;\r
-                               for(var find_count = 0;find_count<$("#service_svg path").length;find_count++)\r
-                               {\r
-                                       if($("#service_svg path:eq("+find_count+")").attr("type") != "flow")\r
-                                               continue;\r
-                                       if($("#service_svg path:eq("+find_count+")").attr("node_start") == src_group && $("#service_svg path:eq("+find_count+")").attr("node_end") == dest_group)\r
-                                       {\r
-                                               if(flow_count_temp == $("#service_svg path:eq("+find_count+")").attr("count"))\r
-                                               {\r
-                                                       end_flag = 1;\r
-                                                       flow_count_temp++;\r
-                                                       break;\r
-                                               }\r
-               \r
-                                       }\r
-                               }\r
-                               if(end_flag != 1)\r
-                                       break;  \r
-                       }\r
-               \r
-                       \r
-                               \r
-                       \r
-                       //get Radio\r
-                       var cir_r = parseInt($("#"+src_group+" circle:eq(0)").attr("r"));\r
-                       \r
-                       \r
-                       //get circle cx cy\r
-                       src_cx = parseInt($("#"+src_group+" circle:eq(0)").attr("cx"));\r
-                       src_cy = parseInt($("#"+src_group+" circle:eq(0)").attr("cy"));\r
-                       dest_cx = parseInt($("#"+dest_group+" circle:eq(0)").attr("cx"));\r
-                       dest_cy = parseInt($("#"+dest_group+" circle:eq(0)").attr("cy"));\r
-                       console.log(src_cx+"  "+src_cy+"  "+dest_cx+"   "+dest_cy);\r
-                       \r
-                       //calculate deg\r
-                       var tri_h = dest_cx-src_cx;\r
-                       var tri_l = src_cy-dest_cy;\r
-                       var tri_s = Math.sqrt(tri_l*tri_l + tri_h*tri_h);\r
-                       var deg = Math.asin(tri_l/tri_s);\r
-                       console.log(tri_h+"  "+tri_l+"  "+tri_s);\r
-                       //alert(deg);\r
-                       console.log(deg);\r
-                       \r
-                       \r
-                       //calculate offset\r
-                       var offset = ((20+(15*flow_count_temp))/180)*Math.PI;\r
-                       console.log("offset:  "+offset);\r
-                       \r
-                       //calculate path possition\r
-                       var path_src_x,path_src_y,path_dest_x,path_dest_y,mid_x,mid_y,b_x,b_y;\r
-                       if(tri_h >= 0)\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx + cir_r*(Math.cos(offset+deg));\r
-                               path_src_y = src_cy - cir_r*(Math.sin(offset+deg));\r
-                               path_dest_x = dest_cx - (cir_r+14)*(Math.cos(offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*flow_count_temp)*Math.abs(Math.sin(deg));;\r
-                                       b_y = mid_y - (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*flow_count_temp)*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y - (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       else\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx - cir_r*(Math.cos(offset-deg));\r
-                               path_src_y = src_cy + cir_r*(Math.sin(offset-deg));\r
-                               path_dest_x = dest_cx + (cir_r+14)*(Math.cos(-offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(-offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*flow_count_temp)*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*flow_count_temp)*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       //path title\r
-                       var path_title = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       \r
-                       \r
-                       \r
-                       //create path\r
-                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       var path_main = $(path).attr({\r
-                               id: $("#flow_name").val().trim(),\r
-                               node_start:src_group,\r
-                               node_end:dest_group,\r
-                               type:"flow",\r
-                               sx:path_src_x,\r
-                               sy:path_src_y,\r
-                               mx:b_x,\r
-                               my:b_y,\r
-                               ex:path_dest_x,\r
-                               ey:path_dest_y,\r
-                               via:"none",\r
-                               count:flow_count_temp,\r
-                               d: 'M'+path_src_x + " " + path_src_y+' Q'+b_x+' '+b_y+' '+path_dest_x+' '+path_dest_y,\r
-                               'stroke':"rgb("+get_path_color()+","+get_path_color()+","+get_path_color()+")",\r
-                               'stroke-width':3,\r
-                               fill:"none",\r
-                               'stroke-dasharray':"6,6" ,\r
-                               'marker-end':"url(#idArrow)",\r
-                               'marker-mid':"url(#idtext)"             \r
-                       });\r
-                       if(ne_flag == 0)\r
-                               $(path).attr("stroke","rgb("+get_path_color()+","+get_path_color()+","+get_path_color()+")");\r
-                       else if(ne_flag == 1)\r
-                               $(path).attr("stroke",old_color);\r
-                       $('#service_svg').prepend(path_main);   \r
-\r
-               }\r
-                                        \r
-                                        \r
-               //save svg \r
-                       var svg_str = $("#service_svg").html();\r
-                       localStorage.setItem(sevice_name+"_svg",svg_str);\r
-\r
-        /////////////////////////////////////////zm/////////////////////////////////////////////////////////////               \r
-        //trigger close click\r
-        $(".NE_close_show").click();\r
-        setentity_instance_list();\r
-        setentity_instance_list_();\r
-         //create nemo sentence\r
-        setnemo_str();\r
-\r
-        //goback change type and name\r
-        $("#entity_type").attr("disabled", false);\r
-\r
-        $("#sel_show").attr("disabled", true);\r
-        $("#node_name").attr("disabled", false);\r
-\r
-        $("#con_type").attr("disabled", false);\r
-        $("#connection_name").attr("disabled", false);\r
-\r
-        $("#flow_name").attr("disabled", false);\r
-\r
-        $("#p2p_node-name1").attr("disabled", false);\r
-        $("#p2p_node-name2").attr("disabled", false);\r
-        $("#p2mp_node-name1").attr("disabled", false);\r
-        $("#p2mp_node-name2 table input").attr("disabled", false);\r
-\r
-    });\r
-\r
-    //change event\r
-    $(".match_items").change(function () {\r
-        str = $(".match_items").children('option:selected').val();\r
-        if ($(".match_items").get(0).selectedIndex == 0) {\r
-            $(".match_value").val(src_ip);\r
-        }\r
-        if ($(".match_items").get(0).selectedIndex == 1) {\r
-            $(".match_value").val(dest_ip);\r
-        }\r
-        if ($(".match_items").get(0).selectedIndex == 2) {\r
-            $(".match_value").val(src_port);\r
-        }\r
-        if ($(".match_items").get(0).selectedIndex == 3) {\r
-            $(".match_value").val(dest_port);\r
-        }\r
-        if ($(".match_items").get(0).selectedIndex == 4) {\r
-            $(".match_value").val(protocol);\r
-        }\r
-        if ($(".match_items").get(0).selectedIndex == 5) {\r
-            $(".match_value").val(vlanid);\r
-        }\r
-\r
-        $(".match_value").val();\r
-\r
-    });\r
-    $(".match_value").blur(function () {\r
-        str = $(".match_items").children('option:selected').val();\r
-        if (str == "src_ip") {\r
-            src_ip = $(this).val().trim();\r
-        }\r
-        if (str == "dest_ip") {\r
-            dest_ip = $(this).val().trim();\r
-        }\r
-        if (str == "src_port") {\r
-            src_port = $(this).val().trim();\r
-        }\r
-        if (str == "dest_port") {\r
-            dest_port = $(this).val().trim();\r
-        }\r
-        if (str == "protocol") {\r
-            protocol = $(this).val().trim();\r
-        }\r
-        if (str == "vlanid") {\r
-            vlanid = $(this).val().trim();\r
-        }\r
-    });\r
-    var node_select = [];\r
-\r
-    $("#con_type").change(function () {\r
-        //$("#p2mp_node-name1,#p2mp_node-name2 ").empty();\r
-      \r
-        //if ($(this).get(0).selectedIndex == 1) {\r
-        //    var service_name = $("#sel_1").children("option:selected").val();\r
-        //    if (!service_name || typeof (service_name) == "undefined") return;\r
-        //    var arr = new Array();\r
-        //    var c = 0;\r
-        //    if ($("#sel_2 option").length == 0)\r
-        //        return;\r
-        //    // $("p2mp_node-name1").empty();\r
-        //    node_select.length = 0;\r
-        //    $("#sel_2 option").each(function () {\r
-        //        if ($(this).val().trim().indexOf("node") >= 0) {\r
-        //            var j = service_name + "__" + $(this).val().replace(":", "_");\r
-        //            var entity = localStorage.getItem(j)\r
-        //            if (!entity || typeof (entity) == "undefined") return true;\r
-        //            var json = jQuery.parseJSON(entity);\r
-        //            if (json[j]["node_type"] == "firewall" || json[j]["node_type"] == "loadbalance" || json[j]["node_type"] == "group")\r
-        //                return true;\r
-        //            var str = $(this).val().split(":");\r
-        //            $("#p2mp_node-name1").prepend("<Option value='" + str[1] + "'>" + str[1] + "</Option>");\r
-        //            node_select.push(str[1]);\r
-        //            arr[c] = str[1];\r
-        //            c++;\r
-        //        }\r
-        //    });\r
-        //    //CreateTable(c - 1, arr);\r
-        //    console.log(" node_select:" + node_select);\r
-        //}\r
-    });\r
-\r
-    //$("#p2mp_node-name1").change(function () {\r
-    //    $("#p2mp_node-name2").empty();\r
-    //    var st = $("#p2mp_node-name1").children("option:selected").val();\r
-    //    var arr = new Array();\r
-    //    var count = 0;\r
-    //    for (var i = 0; i < node_select.length; i++) {\r
-    //        if (node_select[i] == st)\r
-    //            continue;\r
-    //        arr[count] = node_select[i];\r
-    //        count++;\r
-    //        //alert(node_select[i]);\r
-    //    }\r
-    //    //$("#sel_2 option").each(function () {\r
-    //    //    if ($(this).val().trim().indexOf("node") >= 0) {\r
-\r
-    //    //        var str = $(this).val().split(":");\r
-    //    //        if (str[1] == st)\r
-    //    //            return true;\r
-    //    //        arr[count] = str[1];\r
-    //    //        count++;\r
-    //    //    }\r
-    //    //});\r
-    //    CreateTable(count, arr);\r
-    //});\r
-    //$("#src_node").change(function () {\r
-    //    get_nodes("dest_node");\r
-    //    $("#dest_node option[value=" + $("#src_node").val() + "]").remove();\r
-    //});\r
-});\r
diff --git a/nemo-ui/src/main/resources/nemo/js/Service_Instance.js b/nemo-ui/src/main/resources/nemo/js/Service_Instance.js
deleted file mode 100644 (file)
index 64dc6f1..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-function guid() {\r
-    function S4() {\r
-        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\r
-    }\r
-    return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());\r
-}\r
-jQuery(document).ready(function ($) {\r
-    //init service Info\r
-    function init_serviceMsg(){\r
-    var user_log_info = localStorage.getItem("useinfo");\r
-    if(!user_log_info) return;\r
-    var user_name = user_log_info.split(",")[1];\r
-    user_name =user_name+"_service1";\r
-    $(".select_btn .select_item").empty();\r
-    $(".select_btn .select_item").append("<option value='"+user_name+"'>"+user_name+"</option>");\r
-    $("#SI_Add,#SI_Edit,#SI_Delete").attr("disabled","true");\r
-    localStorage.setItem("service_names",user_name);\r
-    \r
-    var local_nemo=localStorage.getItem(user_name+"_nemo_str");\r
-    if(local_nemo !=null && typeof(local_nemo) !="undefined"){\r
-         var $e = $("<div>"+local_nemo+"</div>");\r
-         $e.find("p").each(function(){\r
-         $(this).removeClass('grey_background');\r
-         $(this).find("span").addClass('key');\r
-        });\r
-          //localStorage.setItem(user_name+"_nemo_str", $e.html());\r
-    }\r
-   \r
-    var local_entity_list =  localStorage.getItem(user_name+"_entity_instance_list_");\r
-    if(local_entity_list !=null && typeof(local_entity_list) !="undefined"){\r
-        //console.log(local_entity_list);\r
-    var $e = $("<div>"+local_entity_list+"</div>>");\r
-    $e.find("option").removeClass('grey_background');\r
-    //localStorage.setItem(user_name+"_entity_instance_list_",$e.html())\r
-    console.log($e.html());\r
-}\r
-    var local_policy_list =  localStorage.getItem(user_name+"_policy_list_");\r
-    if(local_policy_list !=null && typeof(local_policy_list) !="undefined"){\r
-        //console.log(local_policy_list);\r
-    var $e = $("<div>"+local_policy_list+"</div>>");\r
-    $e.find("option").removeClass('grey_background');\r
-    //localStorage.setItem(user_name+"_policy_list_",$e.html())\r
-    console.log($e.html());\r
-}\r
-\r
-}\r
-\r
-    var service_name;\r
-    //get nodes\r
-    function get_entity_nodes() {\r
-        service_name = $(".Si_group .select_item option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return null;\r
-        var service_entities = localStorage.getItem(service_name + "_entity_instance_list");\r
-       // console.log(service_entities);\r
-        var nodes = new Array();\r
-        if (!service_entities || typeof (service_entities) == "undefined") return nodes;\r
-        var entities = service_entities.split(",");\r
-        var count = 0;\r
-        for (var i = 0; i < entities.length; i++) {\r
-            var entity = service_name + "__" + entities[i].replace(":", "_");\r
-            //console.log(entity);\r
-            var json_str = localStorage.getItem(entity);\r
-            var json = jQuery.parseJSON(json_str);\r
-            //console.log(json_str);\r
-            if (json[entity]["Entity_Type"] != "node")\r
-                continue;\r
-            // var entity_name = entity.split(":");        \r
-            //console.log(json[entity]["node_name"]); \r
-            var str = "id:" + json[entity]["node_id"] + "<br/>";\r
-            str += "name:" + json[entity]["node_name"] + "<br/>";\r
-            if (json[entity]["node_type"] == "host") {\r
-                str += "property:<br/>"\r
-                str += "ip_address:" + json[entity]["property"]["ip_address"]+"<br/>";\r
-                str += "location:" + json[entity]["property"]["location"]+"<br/>";\r
-                str += "mac_address:" + json[entity]["property"]["mac_address"]+"<br/>";\r
-            }\r
-            else if (json[entity]["node_type"] == "firewall") {\r
-                str += "property:<br/>"\r
-                str += "location:" + json[entity]["property"]["location"] + "<br/>";\r
-                str += "working_mode:"+json[entity]["property"]["working_mode"] + "<br/>";\r
-            }\r
-            else if (json[entity]["node_type"] == "forwarding") {\r
-                str += "property:<br/>"\r
-                str += "ipprefix:"+json[entity]["property"]["ipprefix"] + "<br/>";\r
-            }\r
-            else if (json[entity]["node_type"] == "internet") {\r
-                str += "property:<br/>"\r
-                str += "location:" + json[entity]["property"]["location"] + "<br/>";\r
-                str += "ipprefix:" + json[entity]["property"]["ipprefix"] + "<br/>";\r
-            }\r
-            else {\r
-                str += "property:<br/>"\r
-                str += "location:" + json[entity]["property"]["location"] + "<br/>";\r
-            }\r
-            nodes[count] = [json[entity]["node_name"], json[entity]["node_type"],str];\r
-            count++;\r
-        }\r
-        return nodes;\r
-    }\r
-    //get connection\r
-    function get_entity_connections() {\r
-        service_name = $(".Si_group .select_item option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return null;\r
-        var service_entities = localStorage.getItem(service_name + "_entity_instance_list");\r
-        // console.log(service_entities);\r
-        var connections = new Array();\r
-        if (!service_entities || typeof (service_entities) == "undefined") return null;\r
-        var entities = service_entities.split(",");\r
-        var count = 0;\r
-        for (var i = 0; i < entities.length; i++) {\r
-            var entity = service_name + "__" + entities[i].replace(":", "_");\r
-            //console.log(entity);\r
-            var json_str = localStorage.getItem(entity);\r
-            var json = jQuery.parseJSON(json_str);\r
-            //console.log(json_str);\r
-            if (json[entity]["Entity_Type"] != "connection")\r
-                continue;     \r
-            if (json[entity]["connection_type"] == "p2p") {\r
-                connections[count] = [json[entity]["connection_name"], json[entity]["End-nodes"]["one_node_name"], json[entity]["End-nodes"]["other_node_name"]];\r
-            }\r
-            else if (json[entity]["connection_type"] == "p2mp") {\r
-                connections[count] = [json[entity]["connection_name"], json[entity]["End-nodes"]["one_node_name"], json[entity]["End-nodes"]["other_node_name"]];\r
-            }\r
-           \r
-            count++;\r
-        }\r
-        return connections;\r
-    }\r
-    //get policy chain\r
-    function get_policy_chain() {\r
-        service_name = $(".Si_group .select_item option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return null;\r
-        var policy_list = localStorage.getItem(service_name + "_policy_list");\r
-        if (!policy_list || typeof (policy_list) == "undefined") return null;\r
-        policy = policy_list.split(",");\r
-        var data = [];\r
-        for (var i = 0; i < policy.length; i++) {\r
-            var j = service_name + "__policy_" + policy[i];\r
-            var json_str = localStorage.getItem(j);\r
-            if (!json_str) continue;\r
-            var json = jQuery.parseJSON(json_str);\r
-           \r
-            var entity_name=json[j]["apply_entity_id"];\r
-            if (entity_name.indexOf("flow") >= 0) {\r
-                var js = service_name + "__" + entity_name.replace(":", "_");\r
-                var flow_info = localStorage.getItem(js);\r
-                var jsonflow = jQuery.parseJSON(flow_info);\r
-                var nodes = [];\r
-                nodes.push(jsonflow[js]["match_items"]["src_node"]);\r
-               \r
-                if (json[j]["data"] == "chain") {\r
-                    if (typeof (json[j]["chain_node_list"]) != "undefined") {\r
-                        for (d in json[j]["chain_node_list"])\r
-                            nodes.push(json[j]["chain_node_list"][d]);\r
-                    }\r
-                    nodes.push(jsonflow[js]["match_items"]["dest_node"]);\r
-                    data.push(nodes);\r
-                }\r
-                else {\r
-\r
-                    continue;\r
-                }\r
-            }\r
-\r
-        }\r
-        return data;\r
-\r
-    }\r
-    //clear localStorage\r
-    function clear_storage() {\r
-        var ser_name = "";\r
-        ser_name = $(".Si_group .select_item option:selected").val();\r
-\r
-        if (ser_name == "" || typeof (ser_name) == "undefined") {\r
-            //localStorage.clear();\r
-        }\r
-    }\r
-    function setSevice_names() {\r
-        current_service_names = "";\r
-        $(".Si_group .select_item option").each(function () {\r
-            current_service_names += $(this).text().trim() + ",";\r
-        });\r
-        //console.log(current_service_names);\r
-        current_service_names = current_service_names.substring(0, current_service_names.length - 1);\r
-        //console.log(current_service_names);\r
-        localStorage.setItem("service_names", current_service_names);\r
-        //alert(localStorage.getItem("service_names"));\r
-    }\r
-    function getSevice_names() {\r
-        var get_service_names = localStorage.getItem("service_names");\r
-        console.log(get_service_names);\r
-        if (!get_service_names) return;\r
-        $(".Si_group .select_item").empty();\r
-        if (get_service_names) {       \r
-            var svc_name = get_service_names.split(",");\r
-            for (var j = 0; j < svc_name.length; j++) {\r
-                console.log(svc_name[j]);\r
-                if (svc_name[j] != "")\r
-                    $(".Si_group .select_item").append("<Option value='" + svc_name[j] + "'>" + svc_name[j] + "</Option>");\r
-            }\r
-        }\r
-    }\r
-    function getnemo_str() {\r
-        $("#nemo_str_show").empty();\r
-        var service_name = "";\r
-        service_name = $(".select_item").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined")\r
-            return;\r
-        var str = localStorage.getItem(service_name + "_nemo_str");\r
-        //if (!str || typeof (str) == "undefined")\r
-        //    return;\r
-        //str = str.split("|");\r
-\r
-        //for (s = 0; s < str.length; s++) {\r
-        //    $("#nemo_str_show").append("<p class='key'>" + str[s] + "</p>");\r
-        //}\r
-        console.log("get_nemo:" + str);\r
-        $("#nemo_str_show").append(str);\r
-    }\r
-       \r
-       function clear_topo() {\r
-           nodes.clear();\r
-               edges.clear();\r
-               Node_Id=0;\r
-               Edge_Id=0;\r
-           var data = {\r
-                       nodes: nodes,\r
-                       edges: edges\r
-               };\r
-               container = document.getElementById('graph');\r
-               graph = new vis.Graph(container, data, options);\r
-       }\r
-\r
-    //init\r
-       $("#ser_init").click(function () {\r
-           $("#tabs ul li").eq(0).children().trigger("click");\r
-        getSevice_names();\r
-        clear_storage();\r
-        //$("#ser_inst_show").show();\r
-        init_serviceMsg();\r
-        $(".Si_group .select_item").change();\r
-        getnemo_str();\r
-        $("#Add_show").hide();\r
-        //var nodes = get_entity_nodes();\r
-        //var connections = get_entity_connections();\r
-        //console.log("<SI>nodes:" + nodes);\r
-        //console.log("<SI>connections:" + connections);\r
-        //var test = get_policy_chain();\r
-        //console.log(test);\r
-\r
-    });\r
-\r
-    var flag = true;\r
-    $("#SI_Add").click(function () {\r
-        flag = true;\r
-        $("#Add_show").hide();\r
-        $("#Add_show .text_item").val("");\r
-\r
-        $("#Add_show").show();\r
-        //alert($(".Si_group .select_item option:first").val());\r
-        if ($(".Si_group .select_item option:first").val() != "empty") {\r
-            $(".Si_group .select_item").prepend("<option value='empty'></option>");\r
-            $(".Si_group .select_item").get(0).selectedIndex = 0;\r
-        }\r
-        $(".Si_group .select_item").get(0).selectedIndex = 0;\r
-        $(".Si_group .name_text").attr("disabled", false);\r
-    });\r
-\r
-\r
-    var edit_name = "";\r
-    $("#SI_Edit").click(function () {\r
-        edit_name = $(".Si_group .select_item option:selected").text().trim();\r
-        if (edit_name == "")\r
-            return;\r
-        //$("#SI_Delete").click();\r
-        $("#Add_show .name_text").val(edit_name);\r
-        //alert(localStorage.getItem(edit_name));\r
-        $("#Add_show .desc_text").val(localStorage.getItem(edit_name));\r
-        $("#Add_show").show();\r
-        flag = false;\r
-        $(".Si_group .name_text").attr("disabled", true);\r
-    });\r
-    $("#SI_Delete").click(function () {\r
-        var service_name = $(".Si_group .select_item").children("option:selected").text();\r
-        if (!service_name || typeof (service_name) == "undefined")\r
-            return;\r
-        $("#del_ser_dialog").dialog({\r
-            height: 240,\r
-            width: 400,\r
-            modal: true,\r
-            open: function (event, ui) { $(".ui-dialog-titlebar-close").hide(); },\r
-            buttons: {\r
-                "ok": function () {\r
-                    //remove service \r
-                    localStorage.removeItem($(".Si_group .select_item option:selected").val());\r
-                    //remove service entity\r
-                    var sevice_name = $(".Si_group .select_item").val();\r
-                    //$("#select_item option:selected").remove();\r
-                    localStorage.removeItem(sevice_name + "_entity_instance_list");\r
-                    localStorage.removeItem(sevice_name + "_policy_list");\r
-                    localStorage.removeItem(sevice_name + "_entity_instance_list_");\r
-                    localStorage.removeItem(sevice_name + "_policy_list_");\r
-                    localStorage.removeItem(service_name + "_nemo_str");\r
-                    localStorage.removeItem(service_name + "_svg");\r
-                    localStorage.removeItem(sevice_name + "_lgroup_aviable_node");\r
-                    localStorage.removeItem(sevice_name + "_chain_aviable_node");\r
-                    //update service list\r
-                    //localStorage.clear();\r
-                    $(".Si_group .select_item option:selected ").remove();\r
-                    $("#Add_show .text_item").val("");\r
-                    $("#Add_show").hide();\r
-                    clear_storage();\r
-                    //reload page\r
-                    // location.reload();\r
-                    getnemo_str();\r
-                    setSevice_names();\r
-                    $(".Si_group .select_item").change();\r
-                                       \r
-                                       //clear topo\r
-                                       clear_topo();\r
-                                       ne_flag=0;\r
-                    Node_List = new Array();\r
-                    Edge_List = new Array();\r
-       \r
-                       node_count=0;\r
-                       node_X=[];\r
-                    conn_Item=[];\r
-\r
-                       nodes.clear(); edges.clear();\r
-                    Node_Id = 0;\r
-                    Edge_Id = 0;       \r
-                       Edge_Count=0;\r
-\r
-       \r
-                       Node_Sp=[];\r
-                       Node_Sp_Id=[];\r
-                       Node_Sc=[];\r
-                       Node_Sc_Id=[];\r
-                       policy_count=[];\r
-                       policy_set=[];\r
-                    chain_count=[];\r
-                       chain_set=[];\r
-                       conn_set=[];\r
-                                                 nodes.add({\r
-                        id: 100000,\r
-                                               group: 'null',\r
-                                               x:700,\r
-                                               y:400\r
-                    });\r
-                    $(this).dialog("close");\r
-                },\r
-                "cancle": function () {\r
-                    $(this).dialog("close");\r
-                }\r
-            }\r
-        });\r
-\r
-\r
-    });\r
-    $(".close_group").click(function () {\r
-        $("#Add_show").hide();\r
-        $(".Si_group .select_item option[value=empty]").remove();\r
-        $(".Si_group .name_text").attr("disabled", false);\r
-        flag = true;\r
-    });\r
-    //test\r
-    //localStorage.setItem('data', "text");\r
-    //alert(localStorage.getItem('data'));\r
-\r
-    $("#SI_Save").click(function () {\r
-\r
-        var name = $("#Add_show .name_text").val().trim();\r
-        var f = 0;\r
-        $(".Si_group .select_item option").each(function () {\r
-            if ($(this).val() == name) {\r
-                if (flag == true) {\r
-                    $("#dialog").dialog({\r
-                        height: 240,\r
-                        width: 400,\r
-                        modal: true,\r
-                        open: function (event, ui) { $(".ui-dialog-titlebar-close").hide(); },\r
-                        buttons: {\r
-                            "确定": function () { $(this).dialog("close"); }\r
-                        }\r
-                    });\r
-                    //alert(name + " is already existing,please input another name!");\r
-                    f = 1;\r
-                    return false;\r
-                }\r
-            }\r
-        });\r
-        if (f == 1) {\r
-            return;\r
-        }\r
-        if (flag == false) {\r
-\r
-            $(".Si_group .select_item option[value=" + edit_name + "]").remove();\r
-            localStorage.removeItem(edit_name);\r
-            flag = true;\r
-        }\r
-        if (name == "") {\r
-\r
-            $("#ser_dialoge").dialog({\r
-                height: 200,\r
-                width: 350,\r
-                modal: true,\r
-                open: function (event, ui) { $(".ui-dialog-titlebar-close").hide(); },\r
-                buttons: {\r
-                    "确定": function () { $(this).dialog("close"); }\r
-                }\r
-            });\r
-        }\r
-        else {\r
-            $(".Si_group .select_item option[value=empty]").remove();\r
-            $(".Si_group .select_item").prepend("<option value='" + name + "'>" + name + "</option>");\r
-            $(".Si_group .select_item").get(0).selectedIndex = 0;\r
-\r
-            setSevice_names();\r
-\r
-            localStorage.setItem(name, $(".desc_text").val());\r
-            // alert(localStorage.getItem(name));\r
-            $("#Add_show").hide();\r
-            $("#Add_show .text_item").val("");\r
-            $(".Si_group .select_item").change();\r
-        }\r
-\r
-    });\r
-    //change event\r
-    $(".Si_group .select_item").change(function () {\r
-        service_select = $(this).val();\r
-    });\r
-    //trigger service instance click event, and get data\r
-    $("#ser_init").click(); \r
-    //hide service instance info\r
-    $("#ser_init").click(); \r
-\r
-});\r
diff --git a/nemo-ui/src/main/resources/nemo/js/Service_Policy.js b/nemo-ui/src/main/resources/nemo/js/Service_Policy.js
deleted file mode 100644 (file)
index 326092e..0000000
+++ /dev/null
@@ -1,1045 +0,0 @@
-function guid() {\r
-    function S4() {\r
-        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\r
-    }\r
-    return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());\r
-}\r
-jQuery(document).ready(function ($) {\r
-    function get_bid() {\r
-                var bid_flag = "false";\r
-                               var sevice_name = "";\r
-                var entity_name = "";\r
-                sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-                entity_name = $("#apply_entity option:selected").text();\r
-                if (sevice_name == "" || entity_name == "")\r
-                     return;\r
-                if (!entity_name || typeof (entity_name) == "undefined") return;\r
-\r
-                //get json string\r
-                var entity = sevice_name + "__" + entity_name.replace(':', '_');\r
-                var json_str = localStorage.getItem(entity);\r
-                if (!json_str || typeof (json_str) == "undefined")\r
-                       return;\r
-                console.log(json_str);\r
-                               var json = jQuery.parseJSON(json_str);\r
-                               if(json[entity]["Entity_Type"] == "flow")\r
-                               {\r
-                                       bid_flag=json[entity]["match_items"]["bidirect"];\r
-                               }\r
-                               return bid_flag;\r
-                                                               \r
-               }\r
-\r
-       function get_color(temp){\r
-               while(1)\r
-               {\r
-                  var num1 = Math.floor(Math.random()*(16000000/10*temp));\r
-                  if(num1<1600000)\r
-                          continue;\r
-                  return num1.toString(16);\r
-               }                       \r
-       }\r
-               function lead_policy(src_group,dest_group,flow_count_temp,color,id,chain_name,src_name,dest_name)\r
-               {\r
-                       var cir_r = parseInt($("#"+src_group+" circle:eq(0)").attr("r"));\r
-                       \r
-                       //get circle cx cy\r
-                       src_cx = parseInt($("#"+src_group+" circle:eq(0)").attr("cx"));\r
-                       src_cy = parseInt($("#"+src_group+" circle:eq(0)").attr("cy"));\r
-                       dest_cx = parseInt($("#"+dest_group+" circle:eq(0)").attr("cx"));\r
-                       dest_cy = parseInt($("#"+dest_group+" circle:eq(0)").attr("cy"));\r
-                       console.log(src_cx+"  "+src_cy+"  "+dest_cx+"   "+dest_cy);\r
-                       \r
-                       //calculate deg\r
-                       var tri_h = dest_cx-src_cx;\r
-                       var tri_l = src_cy-dest_cy;\r
-                       var tri_s = Math.sqrt(tri_l*tri_l + tri_h*tri_h);\r
-                       var deg = Math.asin(tri_l/tri_s);\r
-                       console.log(tri_h+"  "+tri_l+"  "+tri_s);\r
-                       //alert(deg);\r
-                       console.log(deg);\r
-                       \r
-                       \r
-                       //calculate offset\r
-                       var offset = ((20+(15*parseInt(flow_count_temp)))/180)*Math.PI;\r
-                       console.log("temp: "+flow_count_temp+" offset:  "+offset);\r
-                       \r
-                       //calculate path possition\r
-                       var path_src_x,path_src_y,path_dest_x,path_dest_y,mid_x,mid_y,b_x,b_y;\r
-                       if(tri_h >= 0)\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx + cir_r*(Math.cos(offset+deg));\r
-                               path_src_y = src_cy - cir_r*(Math.sin(offset+deg));\r
-                               path_dest_x = dest_cx - (cir_r+14)*(Math.cos(offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));;\r
-                                       b_y = mid_y - (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y - (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       else\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx - cir_r*(Math.cos(offset-deg));\r
-                               path_src_y = src_cy + cir_r*(Math.sin(offset-deg));\r
-                               path_dest_x = dest_cx + (cir_r+14)*(Math.cos(-offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(-offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       //path title\r
-                       var path_title = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       \r
-                       \r
-                       \r
-                       //create path\r
-                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       var path_main = $(path).attr({\r
-                               id: id,\r
-                               node_start:src_name,\r
-                               node_end:dest_name,\r
-                               type:"flow",\r
-                               sx:path_src_x,\r
-                               sy:path_src_y,\r
-                               mx:b_x,\r
-                               my:b_y,\r
-                               ex:path_dest_x,\r
-                               ey:path_dest_y,\r
-                               count:flow_count_temp,\r
-                               via:chain_name,\r
-                               d: 'M'+path_src_x + " " + path_src_y+' Q'+b_x+' '+b_y+' '+path_dest_x+' '+path_dest_y,\r
-                               'stroke':color,\r
-                               'stroke-width':3,\r
-                               fill:"none",\r
-                               'stroke-dasharray':"6,6" ,\r
-                               'marker-end':"url(#idArrow)",\r
-                               'marker-mid':"url(#idtext)"             \r
-                       });\r
-                               $('#service_svg').prepend(path_main);           \r
-\r
-               }\r
-    function getChainSet(){\r
-       var ser = $(".SP_up .select_item").children("option:selected").val();\r
-        var st = localStorage.getItem(ser + "_entity_instance_list");\r
-        if (!st ) return;\r
-        st = st.split(",");\r
-          $("#policy_data").empty();\r
-        for (var i = 0; i < st.length; i++) {\r
-         var j= ser +"__"+ st[i].replace(":","_");\r
-         var json_str = localStorage.getItem(j);\r
-         if(!json_str) return;\r
-         //console.log(json_str);\r
-       \r
-         var $json = JSON.parse(json_str);\r
-            if (st[i] != "" && $json[j]["node_type"]=="chain-group")\r
-                $("#policy_data").append("<Option value='" + st[i].split(":")[1] + "'>" + st[i].split(":")[1] + "</Option>");\r
-        }\r
-        $("#policy_data").get(0).selectedIndex = 0;   \r
-               \r
-}\r
-       function get_apply_entity() {\r
-                       var apply_entity_name;\r
-                var sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-                var entity_name = "policy_"+$("#policy_name_list option:selected").text();\r
-                if (!sevice_name  || !entity_name ) return;\r
-\r
-                //get json string\r
-                var entity = sevice_name + "__" + entity_name;\r
-                var json_str = localStorage.getItem(entity);\r
-                if (!json_str ) return;\r
-                console.log(json_str);\r
-                               var json = jQuery.parseJSON(json_str);\r
-                               apply_entity_name=json[entity]["apply_entity_id"];\r
-                               return apply_entity_name;\r
-                                                               \r
-               }\r
-   function get_sfc_flag() {\r
-                var sfc_flag = 0;\r
-                               var sevice_name = "";\r
-                var entity_name = "";\r
-                sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-                entity_name = $("#policy_name_list option:selected").text();\r
-                if (sevice_name == "" || entity_name == "")\r
-                     return;\r
-                if (!entity_name || typeof (entity_name) == "undefined") return;\r
-                //get json string\r
-                var entity = sevice_name + "__" + "policy_"+entity_name.replace(':', '_');\r
-                var json_str = localStorage.getItem(entity);\r
-                if (!json_str || typeof (json_str) == "undefined")\r
-                       return;\r
-                console.log(json_str);\r
-                               var json = jQuery.parseJSON(json_str);\r
-                               if(json[entity]["action"] == "go-through")\r
-                                       sfc_flag=1;\r
-                               else sfc_flag=0;\r
-                               return sfc_flag;\r
-               }\r
-               \r
-               \r
-               function get_flow_flag() {\r
-                var flow_flag = 0;\r
-                               var sevice_name = "";\r
-                var entity_name = "";\r
-                sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-                entity_name = $("#apply_entity option:selected").text();\r
-                if (sevice_name == "" || entity_name == "")\r
-                     return;\r
-                if (!entity_name || typeof (entity_name) == "undefined") return;\r
-\r
-                //get json string\r
-                var entity = sevice_name + "__" + entity_name.replace(':', '_');\r
-                var json_str = localStorage.getItem(entity);\r
-                if (!json_str || typeof (json_str) == "undefined")\r
-                       return;\r
-                console.log(json_str);\r
-                               var json = jQuery.parseJSON(json_str);\r
-                               if(json[entity]["Entity_Type"] == "flow")\r
-                                       flow_flag=1;\r
-                               else flow_flag=0;\r
-                               return flow_flag;\r
-               }\r
-               \r
-               function get_flow_sd() {\r
-                var node=[];\r
-                               var sevice_name = "";\r
-                var entity_name = "";\r
-                sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-                entity_name = $("#apply_entity option:selected").text();\r
-                if (sevice_name == "" || entity_name == "")\r
-                     return;\r
-                if (!entity_name || typeof (entity_name) == "undefined") return;\r
-\r
-                //get json string\r
-                var entity = sevice_name + "__" + entity_name.replace(':', '_');\r
-                var json_str = localStorage.getItem(entity);\r
-                if (!json_str || typeof (json_str) == "undefined")\r
-                       return;\r
-                console.log(json_str);\r
-                               var json = jQuery.parseJSON(json_str);\r
-                               if(json[entity]["Entity_Type"] == "flow")\r
-                                       flow_flag=1;\r
-                               else flow_flag=0;\r
-                               node[0]=json[entity]["match_items"]["src_node"];\r
-                               node[1]=json[entity]["match_items"]["dest_node"];\r
-                               return node;\r
-               }\r
-               function get_flow_sd_del() {\r
-                var node=[];\r
-                               var sevice_name = "";\r
-                var entity_name = "";\r
-                sevice_name = $(".NE_up #sel_1").children('option:selected').val();\r
-                entity_name =get_apply_entity();\r
-                if (sevice_name == "" || entity_name == "")\r
-                     return;\r
-                if (!entity_name || typeof (entity_name) == "undefined") return;\r
-\r
-                //get json string\r
-                var entity = sevice_name + "__" + entity_name.replace(':', '_');\r
-                var json_str = localStorage.getItem(entity);\r
-                if (!json_str || typeof (json_str) == "undefined")\r
-                       return;\r
-                console.log(json_str);\r
-                               var json = jQuery.parseJSON(json_str);\r
-                               if(json[entity]["Entity_Type"] == "flow")\r
-                                       flow_flag=1;\r
-                               else flow_flag = 0;\r
-                               if (json[entity]["match_items"])\r
-                                   node[0] = json[entity]["match_items"]["src_node"];\r
-                               if (json[entity]["match_items"])\r
-                               node[1]=json[entity]["match_items"]["dest_node"];\r
-                               return node;\r
-               }\r
-    //function\r
-    function sp_getSevice_names() {\r
-        var get_service_names = localStorage.getItem("service_names");\r
-        console.log(get_service_names);\r
-        if (!get_service_names && typeof (get_service_names) != "undefined" && get_service_names != 0)\r
-            return;\r
-        $(".SP_up .select_item").empty();\r
-        if (get_service_names != null || get_service_names != "") {\r
-            svc_name = get_service_names.split(",");\r
-            for (var j = 0; j < svc_name.length; j++) {\r
-                $(".SP_up .select_item").append("<Option value='" + svc_name[j] + "'>" + svc_name[j] + "</Option>");\r
-            }\r
-        }\r
-        $(".SP_up .select_item").val(service_select).attr("disabled", true);\r
-    }\r
-    function setpolicy_list() {\r
-        //$(".SP_up .select_item").get(0).selectedIndex = 0;\r
-        var service_name = "";\r
-        service_name = $(".SP_up .select_item").children("option:selected").val();\r
-        if (service_name == "")\r
-            return;\r
-        current_policy_list = "";\r
-        $("#policy_name_list option").each(function () {\r
-            current_policy_list += $(this).val().trim() + ",";\r
-        });\r
-        //console.log("cur_policy_list:" + current_policy_list);\r
-        current_policy_list = current_policy_list.substring(0, (current_policy_list.length - 1));\r
-        console.log("setpolicy_list current_policy_list: " + current_policy_list);\r
-        localStorage.setItem(service_name + "_policy_list", current_policy_list);\r
-    }\r
-    function setpolicy_list_() {\r
\r
-        var service_name = "";\r
-        service_name = $(".SP_up .select_item").children("option:selected").val();\r
-        if (service_name == "") return;\r
-        current_policy_list = "";\r
-\r
-        localStorage.setItem(service_name + "_policy_list_", $("#policy_name_list").html());\r
-        console.log("setpolicy_list_: " + $("#policy_name_list").html());\r
-    }\r
-    function getpolicy_list() {\r
-        $("#policy_name_list").empty();\r
-        var service_name = "";\r
-        service_name = $(".SP_up .select_item").children('option:selected').val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-        var policy_list = localStorage.getItem(service_name + "_policy_list_");\r
-        if(!policy_list)\r
-        {\r
-         policy_list = localStorage.getItem(service_name + "_policy_list");\r
-        console.log(policy_list);\r
-        if (!policy_list || typeof (policy_list) == "undefined")\r
-            return;\r
-\r
-        svc_name = policy_list.split(",");\r
-        for (var k = 0; k < svc_name.length; k++) {\r
-            if (svc_name[k] != "null" && svc_name[k]!=null && svc_name[k] != "")\r
-                $("#policy_name_list").append("<Option value='" + svc_name[k] + "'>" + svc_name[k] + "</Option>");\r
-        }\r
-        } \r
-        else{\r
-            $("#policy_name_list").html(policy_list); \r
-         }\r
-    }\r
-    function getpolicy_list_() {\r
-        $("#policy_name_list").empty();\r
-        var service_name = "";\r
-        service_name = $(".SP_up .select_item").children('option:selected').val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-        var policy_list = localStorage.getItem(service_name + "_policy_list_");\r
-        console.log(policy_list);\r
-        if (!policy_list || typeof (policy_list) == "undefined") return;\r
-\r
-        $("#policy_name").remove().append(policy_list);\r
-    }\r
-\r
-    function entity_show() {\r
-        var ser = $(".SP_up .select_item").children("option:selected").val();\r
-        var st = localStorage.getItem(ser + "_entity_instance_list");\r
-        if (!st ) return;\r
-        st = st.split(",");\r
-        for (var i = 0; i < st.length; i++) {\r
-        var j = ser +"__"+st[i].replace(":","_");\r
-         var json_str = localStorage.getItem(j);\r
-         if(!json_str) return;\r
-         var $json = JSON.parse(json_str);\r
-          console.log($json);\r
-\r
-            if (st[i] != "" && $json[j]["Entity_Type"]=="flow")\r
-                $("#apply_entity").append("<Option value='" + st[i] + "'>" + st[i] + "</Option>");\r
-        }\r
-        $("#apply_entity").get(0).selectedIndex = 0;\r
-        console.log(st);\r
-    }\r
-       function firewall_show() {\r
-           var ser = $(".SP_up .select_item").children("option:selected").val();\r
-        var st = localStorage.getItem(ser + "_entity_instance_list");\r
-        if (!st || typeof (st) == "undefined")\r
-            return;\r
-        st = st.split(",");\r
-        for (var i = 0; i < st.length; i++) {\r
-            if (st[i] != "" && st[i].indexOf("firewall"))\r
-                $("#apply_entity").append("<Option value='" + st[i] + "'>" + st[i] + "</Option>");\r
-        }\r
-        $("#apply_entity").get(0).selectedIndex = 0;\r
-        console.log(st);\r
-       }\r
-    function getnemo_str() {\r
-        $("#nemo_str_show").empty();\r
-        var service_name = "";\r
-        service_name = $(".select_item").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined")\r
-            return;\r
-        var str = localStorage.getItem(service_name + "_nemo_str");\r
-        //console.log("get:"+str);\r
-        //if (!str || typeof (str) == "undefined")\r
-        //    return;\r
-        //str = str.split("|");\r
-\r
-        //for (s = 0; s < str.length; s++) {\r
-        //    $("#nemo_str_show").append("<p class='key'>" + str[s] + "</p>");\r
-        //}\r
-        $("#nemo_str_show").append(str);\r
-\r
-    }\r
-    function setpolicy_nemo_str() {\r
-        var service_name = "";\r
-        service_name = $(".select_item").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined")\r
-            return;\r
-        str = "";\r
-\r
-        //$("#nemo_str_show p").each(function () {\r
-        //    str += $(this).html() + "|";\r
-        //});\r
-       // str = str.substring(0, str.length - 1);\r
-        //localStorage.setItem(service_name + "_nemo_str", str);\r
-        //console.log("set:"+localStorage.getItem(service_name + "_nemo_str"));\r
-\r
-        str = $("#nemo_str_show").html();\r
-        //console.log("set_add_policy_nemo:" + str);\r
-        localStorage.setItem(service_name + "_nemo_str", str);\r
-    }\r
-    //create table\r
-    function sp_CreateTable(rowCount, arr) {\r
-        var table = $("<table ' border=\"0\">");\r
-        table.appendTo($(".list_nodes"));\r
-        for (var i = 0; i < rowCount; i++) {\r
-            var tr = $("<tr></tr>");\r
-            tr.appendTo(table);\r
-            var td = $("<td> <input type='checkbox'> </td><td>" + arr[i] + "</td>");\r
-            td.appendTo(tr);\r
-        }\r
-        $(".list_nodes").append("</table>");\r
-    }\r
-\r
-    function table_show() {\r
-        var ser = $(".SP_up .select_item").children("option:selected").val();\r
-        var arr = new Array();\r
-        var st = localStorage.getItem(ser + "_entity_instance_list");\r
-        if (!st && typeof (st) != "undefined" && st != 0)\r
-            return;\r
-        count = 0;\r
-        st = st.split(",");\r
-        for (var k = 0; k < st.length; k++) {\r
-            if (st[k].indexOf("node") >= 0) {\r
-                s = st[k].split(':');\r
-                arr.push(s[1]);\r
-                count++;\r
-            }\r
-        }\r
-        console.log(arr);\r
-        sp_CreateTable(count, arr);\r
-    }\r
-    function get_flow_node() {\r
-        var entity_name = $("#apply_entity option:selected").val();\r
-        if (entity_name.indexOf("flow") >= 0) {\r
-            var service_name = $(".select_item").children("option:selected").val();\r
-            if (!service_name || typeof (service_name) == "undefined") return;\r
-            var j = service_name + "__" + entity_name.replace(":", "_");\r
-            var flow_info = localStorage.getItem(j);\r
-            var json = jQuery.parseJSON(flow_info);\r
-            var nodes = [];\r
-            nodes.push(json[j]["match_items"]["src_node"]);\r
-            nodes.push(json[j]["match_items"]["dest_node"]);\r
-            return nodes;\r
-        }\r
-        return null;\r
-    }\r
-    function get_node() {\r
-        var service_name = $(".SP_up .select_item").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-        var str = localStorage.getItem(service_name + "_entity_instance_list");\r
-        console.log("entity_list:" + str);\r
-        if (!str || typeof (str) == "undefined") return;\r
-        str = str.split(",");\r
-        $("#adc_node").empty();\r
-        for (var i = 0; i < str.length; i++) {\r
-            var j = service_name + "__" + str[i].replace(":", "_");\r
-            var json_str = localStorage.getItem(j);\r
-            var json = jQuery.parseJSON(json_str);\r
-            console.log("chain_node_type:" + json[j]["node_type"]);\r
-            if (json[j]["node_type"] == "host" || json[j]["node_type"] == "internet")\r
-                continue;\r
-\r
-            if (str[i].indexOf("node") >= 0) {\r
-                var s = str[i].split(":");\r
-                $("#adc_node").append("<Option value='" + s[1] + "'>" + s[1] + "</Option>");\r
-            }\r
-        }\r
-               \r
-               //remove group node ,show group name\r
-               /*for(var k=1;k<Group_List.length;k++)\r
-                {                      \r
-                        var ss=Group_List[k][0][2];\r
-                        if(ss==null||ss.length<6) continue;\r
-                        ss=ss.substring(6,ss.length-1);                                \r
-             console.log(Group_List[k][0][2]);\r
-                        console.log(ss);\r
-             st=ss.split(","); \r
-             console.log(st);                  \r
-                        for(var l=0;l<st.length;l++)\r
-                        {      \r
-                   $("#adc_node option[value='"+st[l]+"']").remove();\r
-                       }\r
-                          $("#adc_node").append("<Option value='group'>" + Group_List[k][0][2] + "</Option>");\r
-                }*/\r
-               \r
-    }\r
-       \r
-    \r
-       \r
-       \r
-    //init \r
-    $("#ser_poc_init").click(function () {\r
-        $("#policy_action").get(0).selectedIndex = 0;\r
-        $("#policy_action").change();\r
-        sp_getSevice_names();\r
-        getpolicy_list();\r
-        $("#SP_close_show").click();\r
-        //get_node();\r
-        getnemo_str();\r
-    });\r
-\r
-    $("#SP_close_show").click(function () {\r
-        $(".SP_add_show").hide();\r
-        $(".SP_add_show input.cle").val("");\r
-\r
-        $("#policy_name_list option").each(function () {\r
-            if ($(this).val() == "empty")\r
-                $(this).remove();\r
-        });\r
-        //$("#policy_name_list").get(0).selectedIndex = 0;\r
-    });\r
-\r
-    $("input.con_button").click(function () {\r
-        if ($(".con_show:nth-child(3)").val().trim() == "" || $("input.ext_con_3").val().trim() == "")\r
-            alert("Please input a number");\r
-        else\r
-        {\r
-            if ($("#con_select").find("p").length==0 && $(".ext_con_1").val() != "none") {\r
-                alert("第一个表达式与上一个条件的关系为 none");\r
-            }\r
-            else {\r
-                var con_str = $(".con_show:nth-child(1)").children("option:selected").val() + " ";\r
-                con_str += $(".con_show:nth-child(2)").children("option:selected").val() + " ";\r
-                con_str += $(".con_show:nth-child(3)").val().trim() + " ";\r
-                con_str += $(".ext_con_1").val().trim() + " ";\r
-                con_str += $(".ext_con_3").val().trim() + " ";\r
-                con_str += "(" + guid() + ")";\r
-                $("#con_select").append("<p >" + con_str + "</p>");\r
-            }\r
-        }\r
-    });\r
-    $("#con_clear").click(function () {\r
-        $("#con_select").empty();\r
-    });\r
-    var edit_flag = false;\r
-    $("#policy_add").click(function () {\r
-        var service_name = $(".SP_up .select_item").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined")\r
-            return;\r
-        $("#SP_close_show").click();\r
-        if (edit_flag == false)\r
-            $("#policy_name_list").prepend("<Option value='empty'></Option>").get(0).selectedIndex = 0;\r
-        edit_flag = false;\r
-\r
-        $("#policy_id").val(guid);\r
-        $("#policy_priority").val(0);\r
-        $(".SP_add_show").show();\r
-        $("#apply_entity").empty();\r
-        entity_show();\r
-        $(".list_nodes").empty();\r
-        $(".con_show:nth-child(3)").val(); $("#con_select").empty();\r
-        table_show();\r
-        $("#policy_name").attr("disabled", false);\r
-        $("#policy_name").blur();\r
-\r
-    });\r
-\r
-    $("#policy_delete").click(function () {\r
-        var $dele_obj = $("#policy_name_list option:selected");\r
-           var sfc_flag = 0;\r
-               var apply_entity_name=get_apply_entity();\r
-               var node_sd=get_flow_sd_del();\r
-               sfc_flag = get_sfc_flag();\r
-               if(sfc_flag == 1)\r
-               {\r
-                   var service_name = $(".SP_up .select_item").children("option:selected").val();\r
-                       var policy_name = $("#policy_name_list option:selected").text();\r
-                       //alert($("#policy_name_list option:selected").text());\r
-                       console.log(service_name+"   "+policy_name);\r
-                       if (!service_name || typeof (service_name) == "undefined") return;\r
-                       if (!policy_name || typeof (policy_name) == "undefined") return;\r
-                       if (policy_name == 'empty') return;\r
-                       var policy = service_name + "__policy_" + policy_name;\r
-                       console.log(policy);\r
-                       var json_str = localStorage.getItem(policy);\r
-                       console.log(json_str);\r
-                       if (!json_str || typeof (json_str) == "undefined")\r
-                               return;\r
-                       var json = jQuery.parseJSON(json_str);\r
-                       var flow_name = json[policy]["apply_entity_id"].split(":")[1];\r
-                       console.log("flow: "+flow_name);\r
-                       //alert(flow_name);\r
-                       for(var i=0; i<$("#service_svg path").length;i++)\r
-                       {\r
-                               if($("#service_svg path:eq("+i+")").attr("type") != "flow")\r
-                                       continue;\r
-                               if($("#service_svg path:eq("+i+")").attr("id").indexOf(flow_name) > -1)\r
-                               {\r
-                                       var src_group = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                       var dest_group = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                       var flow_count = $("#service_svg path:eq("+i+")").attr("count");\r
-                                       var flow_id = $("#service_svg path:eq("+i+")").attr("id").split("_")[0];\r
-                                       var flow_color = $("#service_svg path:eq("+i+")").attr("stroke");\r
-                                       lead_policy(src_group,dest_group,flow_count,flow_color,flow_id,"none",src_group,dest_group);            \r
-                                       break;\r
-                               }\r
-                       }\r
-                       $("#"+flow_name+"_1").remove();\r
-                       $("#"+flow_name+"_2").remove();\r
-               var sevice_name = $("#sel_1").val();\r
-        if(!sevice_name) return;\r
-               var svg_str = $("#service_svg").html();\r
-               localStorage.setItem(sevice_name+"_svg",svg_str);\r
-               }\r
-        var sercice_name = $(".SP_up .select_item").children("option:selected").val();\r
-        var policy = $(".SP_up #policy_name_list").children("option:selected").val();\r
-        if (!sercice_name || typeof (sercice_name) == "undefined") return;\r
-        if (!policy || typeof (policy) == "undefined") return;\r
-        if (policy == 'empty') return;\r
-     \r
-        var $tmp_policy_obj=$(".SP_up #policy_name_list").children("option:selected");\r
-        $(".SP_up #policy_name_list").children("option:selected").remove();\r
-        setpolicy_list();\r
-        setpolicy_list_();\r
-        var $op_obj;\r
-        $("#nemo_str_show p").each(function () {\r
-            if ($(this).text().indexOf("Operation") >= 0 && $(this).text().indexOf(policy + " ") >= 0) {\r
-                $op_obj = $(this);\r
-                return false;\r
-            }\r
-        });\r
-        console.log($op_obj.html());\r
-        if ($tmp_policy_obj.hasClass("grey_background")) {\r
-            var nemoSet=$op_obj.html().split(" ");\r
-            console.log(nemoSet);\r
-            $("#nemo_str_show").append("<p><span class='key'>DELETE Operation </span>" + $dele_obj.val() + "</p>");\r
-\r
-            var str = localStorage.getItem(sercice_name + "__policy_" + policy);\r
-            localStorage.setItem(sercice_name + "__delete_policy_" + policy,str);\r
-            console.log(sercice_name + "__delete_policy_" + policy+" : "+str);\r
-        }\r
-        else {\r
-            $op_obj.remove();\r
-        }\r
-        localStorage.removeItem(sercice_name + "__policy_" + policy);\r
-        setpolicy_nemo_str();\r
-               \r
-               \r
-               //delete topo\r
-               \r
-\r
-               \r
-        $("#SP_close_show").click();\r
-    });\r
-\r
-    $("#policy_edit").click(function () {\r
-        var sercice_name = $(".SP_up .select_item").children("option:selected").val();\r
-        var policy = $(".SP_up #policy_name_list").children("option:selected").val();\r
-        if (!sercice_name || typeof (sercice_name) == "undefined") return;\r
-        if (!policy || typeof (policy) == "undefined") return;\r
-        if (policy == 'empty') return;\r
-        var service_name = $(".SP_up .select_item").children("option:selected").val();\r
-        var policy_name = $(".SP_up #policy_name_list").children("option:selected").val();\r
-        //clear before\r
-        $("#con_select").empty(); $("con_show:nth-child(3)").val();\r
-        console.log("<edit>policy_name:" + policy_name);\r
-        edit_flag = true;//add event use this flag\r
-        $("#policy_add").click();\r
-        edit_flag = true;//save event use this flag\r
-        console.log("<edit>policy_name:" + policy_name);\r
-        var policy = service_name + "__policy_" + policy_name;\r
-        var json_str = localStorage.getItem(service_name + "__policy_" + policy_name);\r
-        if (!json_str || typeof (json_str) == "undefined") return;\r
-        console.log("json_str:" + json_str);\r
-        $("#policy_name").attr("disabled", true);\r
-\r
-        var json = jQuery.parseJSON(json_str);\r
-        $("#policy_id").val(json[policy]["policy_id"]);\r
-        $("#policy_name").val(json[policy]["policy_name"]);\r
-        $("#policy_priority").val(json[policy]["policy_priority"]);\r
-        $("#policy_name").blur();\r
-        $("#apply_entity option[value='" + json[policy]["apply_entity_id"] + "']").attr("selected", true);\r
-        //$("#StartTime").val(json[policy]["condition"]["start_time"].replace("-", ":"));\r
-        //$("#EndTime").val(json[policy]["condition"]["end_time"].replace("-", ":"));\r
-        if (json[policy]["condition"].length > 0)\r
-        {\r
-            for (d in json[policy]["condition"])\r
-            {\r
-                $("#con_select").append("<p>" + json[policy]["condition"] [d]+ "</p>");\r
-            }\r
-        }\r
-        $("#policy_action option[value='" + json[policy]["action"] + "']").attr("selected", true);\r
-        if(json[policy]["action"] =="go-through" )\r
-            $("#policy_action").get(0).selectedIndex=2;\r
-        $("#policy_action").change();\r
-        if (json[policy]["data"] == "chain") {\r
-            if (typeof (json[policy]["chain_node_list"]) != "undefined") {\r
-                if (json[policy]["chain_node_list"].length > 0) {\r
-                    No = 1;\r
-                    for (var d in json[policy]["chain_node_list"]) {\r
-                        $("#table_tab tr:last").find("td").eq(0).text(No);\r
-                        $("#table_tab tr:last").find("td").eq(1).text(json[policy]["chain_node_list"][d]);\r
-                        $("#table_tab").append("<tr><td></td><td></td></tr>");\r
-\r
-                        $("#num").prepend("<Option value='" + No + "'>" + No + "</Option>");\r
-                        $("#num").get(0).selectedIndex = 0;\r
-                        No++;\r
-                    }\r
-                }\r
-            }\r
-        }\r
-               \r
-               if (json[policy]["data"] == "firewall") {\r
-            if (typeof (json[policy]["firewall_list"]) != "undefined") {\r
-                if (json[policy]["firewall_list"].length > 0) {\r
-                    FNo = 1;\r
-                    for (var d in json[policy]["firewall_list"]) {\r
-                                                                 \r
-                        FNo++;\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        $(".list_nodes").children("input").attr("selected", false);\r
-        if (json[policy]["constraint"]["exclusive_node"].length > 0)\r
-            for (var d in json[policy]["constraint"]["exclusive_node"]) {\r
-                $(".list_nodes table").find("tr").each(function () {\r
-                    //alert($(this).html());\r
-                    if ($(this).children('td').eq(1).text() == json[policy]["constraint"]["exclusive_node"][d]) {\r
-                        $(this).children('td').eq(0).children('input').attr("checked", true);\r
-                    }\r
-                });\r
-            }\r
-            //$("#policy_data").empty();\r
-            //$("#policy_data").append("<option value='"+json[policy]["data"]+"'>"+json[policy]["data"]+"</option>");\r
-    });\r
-\r
-    var policy_name_match_flag = false;\r
-    //policy_name\r
-    $("#policy_name").blur(function () {\r
-        var policy_name = $("#policy_name").val().trim();\r
-        var match_null = /^[\s]*$/;\r
-        if (policy_name == "") {\r
-            policy_name_match_flag = false;\r
-            $("#policy_name_icon")[0].src = "src/app/nemo/images/alert.png";\r
-        }\r
-        else {\r
-            policy_name_match_flag = true;\r
-            $("#policy_name_icon")[0].src = "src/app/nemo/images/ok.png";\r
-        }\r
-    });\r
-    //save event\r
-    $("#sp_save").click(function () {\r
-        //validate\r
-        if (!policy_name_match_flag) {\r
-            return;\r
-        }\r
-        //validate name\r
-        service_name = $(".SP_up .select_item").children("option:selected").val();\r
-        if (!service_name || typeof (service_name) == "undefined") return;\r
-        var policy_list = localStorage.getItem(service_name + "_policy_list");\r
-        policy_name = $("#policy_name").val().trim();\r
-        if (policy_list && typeof (policy_list) != "undefined") {\r
-            policy = policy_list.split(",");\r
-            var validate = 0;\r
-            if (edit_flag == false) {\r
-                for (var v = 0; v < policy_list.length; v++) {\r
-                    if (policy[v] == policy_name) {\r
-                        $("#policy_dialog").dialog({\r
-                            height: 240,\r
-                            width: 400,\r
-                            modal: true,\r
-                            open: function (event, ui) { $(".ui-dialog-titlebar-close").hide(); },\r
-                            buttons: {\r
-                                "ok": function () { $(this).dialog("close"); }\r
-                            }\r
-                        });\r
-                        validate = 1;\r
-                        return false;\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        if (validate == 1)\r
-            return;\r
-               //policy_chain_save\r
-               \r
-               \r
-               \r
-                if($("#policy_action option:selected").val() == "go-through")\r
-               {\r
-                       var flow_name = $("#apply_entity option:selected").val().split(":")[1];\r
-                       var chain_name = $("#policy_data option:selected").val();\r
-                       var node_start = $("#"+flow_name).attr("node_start");\r
-                       var node_end = $("#"+flow_name).attr("node_end");\r
-                       var flow_count_cur = parseInt($("#"+flow_name).attr("count"));\r
-                       var flow_color = $("#"+flow_name).attr("stroke");\r
-                       if(edit_flag == true)\r
-                       {\r
-                               node_start = $("#"+flow_name+"_1").attr("node_start");\r
-                               node_end = $("#"+flow_name+"_1").attr("node_end");\r
-                               flow_count_cur = parseInt($("#"+flow_name+"_1").attr("count"));\r
-                               flow_color = $("#"+flow_name+"_1").attr("stroke");\r
-                       }\r
-                       var c1_flag = 0;\r
-                       var c2_flag = 0;\r
-                       for(var i=0; i<$("#service_svg path").length;i++)\r
-                       {\r
-                               if($("#service_svg path:eq("+i+")").attr("type") == "connection")\r
-                               {\r
-                                       var node_name_old_1 = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                       var node_name_old_2 = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                       console.log("old:"+node_name_old_1+"  "+node_name_old_2);\r
-                                       if(((node_start == node_name_old_1)&&(chain_name == node_name_old_2))||((node_start == node_name_old_2)&&(chain_name == node_name_old_1)))\r
-                                       {\r
-                                               c1_flag = 1;\r
-                                       }               \r
-                               }       \r
-                       }\r
-                       for(var i=0; i<$("#service_svg path").length;i++)\r
-                       {\r
-                               if($("#service_svg path:eq("+i+")").attr("type") == "connection")\r
-                               {\r
-                                       var node_name_old_1 = $("#service_svg path:eq("+i+")").attr("node_start");\r
-                                       var node_name_old_2 = $("#service_svg path:eq("+i+")").attr("node_end");\r
-                                       console.log("old:"+node_name_old_1+"  "+node_name_old_2);\r
-                                       if(((node_end == node_name_old_1)&&(chain_name == node_name_old_2))||((node_end == node_name_old_2)&&(chain_name == node_name_old_1)))\r
-                                       {\r
-                                               c2_flag = 1;\r
-                                       }               \r
-                               }       \r
-                       }\r
-                       if(c1_flag == 0 || c2_flag == 0)\r
-                       {\r
-                                       alert("No connection!");\r
-                                       return;\r
-                       }\r
-                       var op_due = $("#service_svg path").length;\r
-                       if(edit_flag == true)\r
-                       {\r
-                               $("#service_svg path[id^="+flow_name+"]").each(function(){\r
-                                       $(this).remove();\r
-                               });\r
-                               /* for(var delete_op = 0;delete_op<op_due;delete_op++)\r
-                               {\r
-                                       if($("#service_svg path:eq("+delete_op+")").attr("type") != "flow")\r
-                                               continue;                               \r
-                                       if($("#service_svg path:eq("+delete_op+")").attr("id").indexOf(flow_name) > -1)\r
-                                               $("#service_svg path:eq("+delete_op+")").remove();      \r
-                               } */\r
-                       }\r
-                       \r
-                       lead_policy(node_start,chain_name,flow_count_cur,flow_color,flow_name+"_1",chain_name,node_start,node_end)\r
-                       lead_policy(chain_name,node_end,flow_count_cur,flow_color,flow_name+"_2",chain_name,node_start,node_end)\r
-                       $("#"+flow_name).remove();              \r
-               }                               \r
-               \r
-               \r
-               \r
-               var flow_flag = 0;\r
-               flow_flag = get_flow_flag();\r
-        var nemo_str = "";\r
-        //create json string  and nemo string\r
-        nemo_str += "<span class='key'>CREATE Operation </span>"\r
-        //nemo_str += $("#policy_id").val();\r
-        //nemo_str += "<span class='key'> Name </span>";\r
-        nemo_str += $("#policy_name").val();\r
-        nemo_str += "<span class='key'> Target </span>";\r
-               var entity_name_t=$("#apply_entity option:selected").val()\r
-        nemo_str += $("#apply_entity option:selected").val().split(":")[1];\r
-        //if ($("#StartTime").val() != "" || $("#EndTime").val() != "") {\r
-        //    nemo_str += "<span class='key'> Condition</span>[";\r
-        //    if ($("#StartTime").val() != "")\r
-        //        nemo_str += "StartTime " + $("#StartTime").val();\r
-        //    else\r
-        //        nemo_str += "StartTime 00:00";\r
-        //    if ($("#EndTime").val() != "")\r
-        //        nemo_str += ",EndTime:" + $("#EndTime").val() + "]";\r
-        //    else\r
-        //        nemo_str += ",EndTime 23:59]";\r
-        //}\r
-        if ($("#con_select").children().length > 0)\r
-        {\r
-            nemo_str += "<span class='key'> Condition[</span>";\r
-            $("#con_select").children().each(function () {\r
-                nemo_str += $(this).html()+" , ";\r
-            });\r
-            nemo_str=nemo_str.substring(0,nemo_str.length-2)\r
-            nemo_str += "]";\r
-        }\r
-        nemo_str += "<span class='key'> Action </span>";\r
-        nemo_str += $("#policy_action option:selected").val();\r
-\r
-        var sercice_name = $(".SP_up .select_item").children("option:selected").val();\r
-        json_str = '{"';\r
-        json_str += sercice_name + '__policy_' + $("#policy_name").val().trim() + '":{';\r
-        json_str += '"policy_id":"' + $("#policy_id").val() + '",';\r
-        json_str += '"policy_name":"' + $("#policy_name").val().trim() + '",';\r
-        json_str += '"policy_priority":"' + $("#policy_priority").val().trim() + '",';\r
-        json_str += '"apply_entity_id":"' + $("#apply_entity").children("option:selected").val() + '",';\r
-        json_str += '"condition":[';\r
-        if ($("#con_select").children().length > 0) {\r
-            $("#con_select").children().each(function () {\r
-                json_str += '"'+$(this).html() + '", ';\r
-            });\r
-            json_str = json_str.substring(0, json_str.length - 2)\r
-        }\r
-        //json_str += '"start_time":"' + $("#StartTime").val().trim().replace(":", "-") + '",';\r
-        //json_str += '"end_time":"' + $("#EndTime").val().trim().replace(":", "-") + '"';\r
-        json_str += "],";\r
-        json_str += '"action":"' + $("#policy_action").children("option:selected").val() + '",';\r
-        json_str += '"data":"' + $("#policy_data").children("option:selected").val() + '",';\r
-\r
-        if ($("#policy_data").children("option:selected").val() == "chain") {\r
-            if (chain_node_list.length > 0) {\r
-                json_str += '"chain_node_list":[';\r
-                var chain_str = "";\r
-                for (var l = 0; l < chain_node_list.length; l++) {\r
-                    chain_str += '"' + chain_node_list[l] + '",';\r
-                }\r
-                chain_str = chain_str.substring(0, chain_str.length - 1);\r
-                json_str += chain_str + '],';\r
-\r
-                nemo_str += "<span class='key'> Chain</span>[" + chain_node_list + "] ";\r
-            }\r
-\r
-        }\r
-                               \r
-               if ($("#policy_data").children("option:selected").val() == "firewall") {\r
-            if (firewall_list.length > 0) {\r
-                json_str += '"firewall_list":[';\r
-                var chain_str = "";\r
-                for (var l = 0; l < firewall_list.length; l++) {\r
-                    chain_str += '"' + firewall_list[l] + '",';\r
-                }\r
-                chain_str = chain_str.substring(0, chain_str.length - 1);\r
-                json_str += chain_str + '],';\r
-                nemo_str += "<span class='key'> Firewall</span>[" + firewall_list + "] ";\r
-            }\r
-\r
-        }\r
-                               \r
-        json_str += '"constraint":{';\r
-\r
-        var data = [];\r
-        $(".list_nodes table").find(":checkbox:checked").each(function () {\r
-            var val = $(this).parent().next().text();\r
-            data.push(val);\r
-        });\r
-        json_str += '"exclusive_node":';\r
-        json_str += '[';\r
-        var node_list = "";\r
-        for (var k = 0; k < data.length; k++) {\r
-            node_list += '"' + data[k] + '",';\r
-        }\r
-        node_list = node_list.substring(0, node_list.length - 1);\r
-        json_str += node_list;\r
-        json_str += ']';\r
-        json_str += '}';\r
-        json_str += '}';\r
-        json_str += '}';\r
-\r
-        //nemo string continue\r
-        if (node_list != "") {\r
-            nemo_str += "<span class='key'> Constraint</span>[";\r
-            nemo_str += node_list.replace(new RegExp(/(")/g), "");\r
-            nemo_str += "]";\r
-        }\r
-        if($("#policy_data option:selected").val() !=null && typeof($("#policy_data option:selected").val())!="undefined")\r
-        nemo_str += ": "+$("#policy_data option:selected").val();\r
-\r
-        if (edit_flag == true) {\r
-            var $op_ob;\r
-            $("#nemo_str_show p").each(function () {\r
-                if ($(this).text().indexOf("Operation") >= 0 && $(this).text().indexOf($("#policy_name").val() + " ") >= 0)\r
-                {\r
-                    $op_ob=$(this);\r
-                    return false;\r
-                }\r
-            });\r
-            if ($("#policy_name_list option:selected").hasClass("grey_background")) {\r
-                $("#nemo_str_show").append("<p>" + nemo_str.replace("CREATE","UPDATE") + "</p>");              \r
-            }\r
-            else {\r
-                $op_ob.html(nemo_str);\r
-            }\r
-           \r
-        }\r
-        else\r
-            $("#nemo_str_show").append("<p>" + nemo_str + "</p>");\r
-\r
-        localStorage.setItem(sercice_name + "_nemo_str", nemo_str);\r
-        if (edit_flag == true){\r
-            var $edit_obj=$("#policy_name_list option:selected");\r
-            $("#policy_name_list").prepend($edit_obj);\r
-            //$("#policy_name_list option:selected").remove();\r
-        }\r
-        else{\r
-        $("#policy_name_list").prepend("<Option value='" + $("#policy_name").val().trim() + "'>" + $("#policy_name").val().trim() + "</Option>");\r
-        }\r
-        $("#policy_name_list").get(0).selectedIndex = 0;\r
-\r
-        localStorage.setItem(sercice_name + "__policy_" + $("#policy_name").val().trim(), json_str);\r
-        //console.log(":"+localStorage.getItem(sercice_name + "__policy_" + $("#policy_name").val().trim()));\r
-\r
-        setpolicy_nemo_str();\r
-        $("#SP_close_show").click();\r
-        setpolicy_list();\r
-        setpolicy_list_();\r
-        console.log(json_str);\r
-               var sevice_name = $("#sel_1").val();\r
-        if(!sevice_name) return;\r
-               var svg_str = $("#service_svg").html();\r
-               localStorage.setItem(sevice_name+"_svg",svg_str);\r
-               \r
-               \r
-        edit_flag = false;\r
-    });\r
-    \r
-    var chain_node_list = new Array();   \r
-   \r
-        var firewall_list = new Array();\r
-\r
-    \r
-    //change event\r
-    $(".SP_up .select_item").change(function () {\r
-        getpolicy_list();\r
-    });\r
-    $("#policy_action").change(function () {\r
-       console.log('change');\r
-     if ($(this).get(0).selectedIndex == 2 ) {\r
-            //$("#policy_data").get(0).selectedIndex = 1;\r
-            getChainSet();\r
-            $("#policy_data").attr("disabled", false);\r
-        }\r
-        else {\r
-            $("#policy_data").empty();\r
-            //$("#policy_data").attr("disabled", true);\r
-        }\r
-    });\r
-\r
-});\r
diff --git a/nemo-ui/src/main/resources/nemo/js/Service_views_main.js b/nemo-ui/src/main/resources/nemo/js/Service_views_main.js
deleted file mode 100644 (file)
index 59d959f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-//var nodes, edges, graph;\r
-//jQuery(document).ready(function ($) {\r
-//    nodes = new vis.DataSet();\r
-\r
-//    nodes.add([\r
-//    { id: '1', label: "server",title:"service",shape:"circle"},\r
-//    { id: '2', label: "firewall", title: "firewall", shape: "circle" }\r
-//    ]);\r
-\r
-//    edges = new vis.DataSet();\r
-\r
-//    //edges.add([\r
-//    //{ id: '1', from: '1', to: '2' }\r
-//    //]);\r
-\r
-//    var container = $("#graph").get(0);\r
-//    var data = {\r
-//        nodes: nodes,\r
-//        edges: edges\r
-//    }\r
-//    var options = {};\r
-//    graph = new vis.Graph(container, data, options);\r
-\r
-//});\r
diff --git a/nemo-ui/src/main/resources/nemo/js/analyjson.js b/nemo-ui/src/main/resources/nemo/js/analyjson.js
deleted file mode 100644 (file)
index 2303265..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-//var phy_hosts; move to nemo_main.js
-var phy_links,phy_nodes;
-var host_count,node_count_phy,link_count;
-var Node_phy_Id = 0;
-var Edge_phy_Id = 0;
-nodes_phy = new vis.DataSet();
-edges_phy = new vis.DataSet();
-var host_id = [];
-var host_name = [];
-var phy_host_ip = [];
-var phy_host_mac = [];
-var node_map_id = [];
-
-jQuery(document).ready(function ($) {
-
-       $("#query_topo").click(function(){
-              var topo_data = 0;
-               $.ajax({
-                       url: "/restconf/operational/generic-physical-network:physical-network/", 
-                       type:"GET",
-                       dataType:"json",
-                       success: function(data){
-                               if(data != null)
-                               {
-                                       topo_data = data;
-                                       analy_topo(topo_data);
-                                       create_physical_topo();
-                               }
-                               else
-                                       alert("No Physical Data");
-                       },
-                       error:function(data){
-                       alert("error");
-                       }
-               }); 
-/*             topo_data = pyh_data_test;
-               analy_topo(topo_data);
-               create_physical_topo(); */
-       });
-   $("#query_topo").click();
-});
-function analy_topo(topo_data)
-{
-       phy_hosts = [];
-       phy_nodes = [];
-       phy_links = [];
-       host_count = 0;
-       node_count_phy = 0;
-       link_count = 0;
-       if(topo_data["physical-network"]["physical-nodes"]!=null)
-       {
-               for(var i in topo_data["physical-network"]["physical-nodes"]["physical-node"])
-               {
-                       var node_data_temp = [];
-                       var data_temp;
-                       var json_temp = topo_data["physical-network"]["physical-nodes"]["physical-node"][i];
-/*                     for(var key in json_temp)
-                       {
-                               data_temp = json_temp[key];
-                       } */
-                       node_data_temp["node-id"] = json_temp["node-id"];
-                       node_data_temp["node-type"] = json_temp["node-type"];
-                       phy_nodes[node_count_phy] = node_data_temp;
-                       node_count_phy++;
-               }
-
-       }
-       if(topo_data["physical-network"]["physical-hosts"]!=null)
-       {
-               for(var i in topo_data["physical-network"]["physical-hosts"]["physical-host"])
-               {
-                       //var host_name_temp = 'host' + i;
-                               var host_data_temp = [];
-                       var data_temp;
-                       var json_temp = topo_data["physical-network"]["physical-hosts"]["physical-host"][i];
-                       /* for(var key in json_temp)
-                       {
-                               data_temp = json_temp[key];
-                       } */
-                       host_data_temp["node-id"] = json_temp["node-id"];
-                       host_data_temp["host-name"] = json_temp["host-name"];
-                       host_data_temp["host-id"] = json_temp["host-id"];
-                       phy_hosts[host_count] = host_data_temp;
-                       host_count++;
-                       host_id[json_temp["host-name"]] = json_temp["host-id"];
-                       host_name[json_temp["host-id"]] = json_temp["host-name"];
-                               phy_host_ip[json_temp["ip-addresses"]["ip-address"][0]] = json_temp["host-name"];
-                       phy_host_mac[json_temp["mac-address"]] = json_temp["host-name"];
-               }
-       }
-       if(topo_data["physical-network"]["physical-links"]!=null)
-       {
-               for(var i in topo_data["physical-network"]["physical-links"]["physical-link"])
-               {
-                       var link_data_temp = [];
-                       var data_temp;
-                       var json_temp = topo_data["physical-network"]["physical-links"]["physical-link"][i];
-               /*      for(var key in json_temp)
-                       {
-                               data_temp = json_temp[key];
-                       } */
-                       link_data_temp["link-id"] = json_temp["link-id"];
-                       link_data_temp["src-node-id"] = json_temp["src-node-id"];
-                       link_data_temp["dest-node-id"] = json_temp["dest-node-id"];
-                       phy_links[link_count] = link_data_temp;
-                       link_count++;
-               }
-       }
-}
-
-function create_physical_topo()
-{
-       nodes_phy.clear();
-       edges_phy.clear();
-       node_map_id = [];
-       Node_phy_Id = 0;
-       Edge_phy_Id = 0;
-       console.log(phy_nodes);
-       for(var i in phy_nodes)
-       {
-               nodes_phy.add({
-            id: ++Node_phy_Id,
-            label: phy_nodes[i]["node-type"]+phy_nodes[i]["node-id"].split(":")[1],
-            group: phy_nodes[i]["node-type"],
-        });
-               node_map_id[phy_nodes[i]["node-id"]] = Node_phy_Id;
-       }
-       for(var i in phy_hosts)
-       {
-               nodes_phy.add({
-            id: ++Node_phy_Id,
-            label: phy_hosts[i]["host-name"],
-            image: "src/app/nemo/images/host.png",
-            shape: 'image',
-                       fontSize: 15
-        });
-               var to_full_id;
-               for(var node_id_cursor in phy_nodes)
-               {
-                       if(phy_nodes[node_id_cursor]["node-id"].indexOf(phy_hosts[i]["node-id"]) > -1)
-                       {
-                               to_full_id = phy_nodes[node_id_cursor]["node-id"];
-                               break;
-                       }
-               }
-               edges_phy.add({
-                       id:++Edge_phy_Id,
-                       from:Node_phy_Id,
-                       to:node_map_id[to_full_id]
-               });
-               node_map_id[phy_nodes[i]["host-id"]] = Node_phy_Id;
-       }
-       for(var i in phy_links)
-       {
-           var from_full_id;
-               for(var node_id_cursor in phy_nodes)
-               {
-                       if(phy_nodes[node_id_cursor]["node-id"].indexOf(phy_links[i]["src-node-id"]) > -1)
-                       {
-                               from_full_id = phy_nodes[node_id_cursor]["node-id"];
-                               break;
-                       }
-               }
-               var to_full_id;
-               for(var node_id_cursor in phy_nodes)
-               {
-                       if(phy_nodes[node_id_cursor]["node-id"].indexOf(phy_links[i]["dest-node-id"]) > -1)
-                       {
-                               to_full_id = phy_nodes[node_id_cursor]["node-id"];
-                               break;
-                       }
-               }
-               edges_phy.add({
-                       id:++Edge_phy_Id,
-                       from:node_map_id[from_full_id],
-                       to:node_map_id[to_full_id]
-               });
-       }
-       var data = {
-               nodes: nodes_phy,
-               edges: edges_phy
-       };
-       var options3 = {
-               /* physics: {
-               repulsion: {
-                       centralGravity: 0,
-                       springLength: 200,//弹簧长度
-                       springConstant: 0,//弹簧常数
-                       nodeDistance: 0,
-                       damping: 0 //阻尼,减幅,衰减
-               }}, */
-               smoothCurves: false,
-               stabilize: true,
-               nodes: {
-          // default for all nodes
-                       shape: 'dot', 
-                       fontSize:15,
-                       radius:16,
-                       fixed:true
-               },
-               groups:{
-                       switch:{
-                               color: {
-                                       border: 'black',
-                                       background: '#B0E2FF',                          
-                               }
-            },
-                               
-                       router:{
-                               color: {
-                                       border: 'black',
-                                       background: '#7FFF00',
-                               }       
-
-                       }
-               }
-               
-       };
-       var container = document.getElementById('graph');
-       graph = new vis.Graph(container, data, options3)
-}
-
-
-
diff --git a/nemo-ui/src/main/resources/nemo/js/analyjson2.js b/nemo-ui/src/main/resources/nemo/js/analyjson2.js
deleted file mode 100644 (file)
index 4767a7a..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-var instance_name;\r
-var id_match_name = [];\r
-var flow_match_name = [];\r
-var storage_node_data = [];\r
-function analy_instance(instdata)\r
-{\r
-       instance_name = user_name + "_instance";\r
-       \r
-       \r
-       \r
-       \r
-}\r
-\r
-/* function find_node_name(node_id)\r
-{\r
-       var SI_name = instance_name;\r
-       for (var find_cursor = 0; find_cursor<localStorage.length;find_cursor++)\r
-       {\r
-               if(localStorage.key(find_cursor).indexOf(SI_name+'__') == -1)\r
-                       continue;\r
-               else if(localStorage.key(find_cursor).indexOf('node_') > -1 )\r
-               {\r
-                       var find_json_temp = jQuery.parseJSON(localStorage.getItem(localStorage.key(find_cursor)));\r
-                       for(var key in find_json_temp)\r
-                       {\r
-                               if(find_json_temp[key]["node_id"] == node_id)\r
-                                       return find_json_temp[key]["node_name"];\r
-                       }\r
-               }       \r
-       }\r
-       alert("no node id name match!!!");\r
-} */\r
-\r
-\r
-\r
-function analy_node(node_json)\r
-{\r
-       var node_local_json_tmp;\r
-       for(var i in node_json["objects"]["node"])\r
-       {\r
-               var json_tmp = node_json["objects"]["node"][i];\r
-               id_match_name[json_tmp["node-id"]] = json_tmp["node-name"];\r
-               storage_node_data[json_tmp["node-id"]] = json_tmp;\r
-               node_local_json_tmp = '{'+instance_name+'__'+'node_'+json_tmp["node-name"]+':{';\r
-               node_local_json_tmp += '"Entity_type":"node","node_id":"'+json_tmp["node-id"]+'","node_name":"'+json_tmp["node-name"]+'","node_type":"'+json_tmp["node-type"]+'","property":{';\r
-               for(var k in json_tmp["property"])\r
-               {\r
-                       var json_tmp2 = json_tmp["property"][k];\r
-                       if(json_tmp2["property-name"] =='location')\r
-                               node_local_json_tmp += '"'+json_tmp2["property-name"]+'":"'+json_tmp2["property-values"]["string-value"][0]["value"]+'",';\r
-                       else(json_tmp2["property-name"] =='capacity')\r
-                               node_local_json_tmp += '"'+json_tmp2["property-name"]+'":"'+json_tmp2["property-values"]["int-value"][0]["value"]+'",';\r
-               }\r
-               node_local_json_tmp = node_local_json_tmp.substring(0,node_local_json_tmp.length-1);\r
-               node_local_json_tmp += '}}}';\r
-       }\r
-    return     node_local_json_tmp;\r
-}\r
-\r
-function analy_sub_node()\r
-{\r
-       var SI_name = instance_name;\r
-       for (var find_cursor = 0; find_cursor<localStorage.length;find_cursor++)\r
-       {\r
-               if(localStorage.key(find_cursor).indexOf(SI_name+'__') == -1)\r
-                       continue;\r
-               else if(localStorage.key(find_cursor).indexOf('node_') > -1 )\r
-               {\r
-                       var find_str_temp = localStorage.getItem(localStorage.key(find_cursor));\r
-                       var find_json_temp = jQuery.parseJSON(localStorage.getItem(localStorage.key(find_cursor)));\r
-                       for(var key in find_json_temp)\r
-                       {\r
-                               if(find_json_temp[key]["node_type"].indexOf("group") > -1)\r
-                               {\r
-                                       var node_json = storage_node_data[find_json_temp[key]["node_id"]];\r
-                                       find_str_temp = find_str_temp.substring(0,find_str_temp.length-2);\r
-                                       find_str_temp += ',"sub-node":{';\r
-                                       var host_count = 0;\r
-                                       var group_count = 0;\r
-                                       for(var sub_cursor in node_json["sub-node"])\r
-                                       {\r
-                                               \r
-                                               if(id_match_name[node_json["sub-node"][sub_cursor]["node-id"]] != null)\r
-                                               {\r
-                                                       if(group_count == 0)\r
-                                                       {\r
-                                                               find_str_temp += '"sub-node_group": [';\r
-                                                       }\r
-                                                       find_str_temp += '"'+id_match_name[node_json["sub-node"][sub_cursor]["node-id"]]+'"';\r
-                                                       group_count++;\r
-                                               }\r
-                                       }\r
-                                       if(group_count>0)\r
-                                               find_str_temp += '],'\r
-                                       for(var sub_cursor in node_json["sub-node"])\r
-                                       {\r
-                                               if(host_name[node_json["sub-node"][sub_cursor]["node-id"]] != null)\r
-                                               {\r
-                                                       if(host_count == 0)\r
-                                                       {\r
-                                                               find_str_temp += '"sub-node_host": [';\r
-                                                       }\r
-                                                       find_str_temp += '"'+host_name[node_json["sub-node"][sub_cursor]["node-id"]]+'"';\r
-                                                       host_count++;\r
-                                               }\r
-                                       }\r
-                                       find_str_temp += '}';\r
-                                       if(host_count>0)\r
-                                               find_str_temp += ']'\r
-                                       if(group_count > 0 && host_count = 0)\r
-                                               find_str_temp = find_str_temp.substring(0,find_str_temp.length-1);\r
-                                       if(group_count > 0 || host_count > 0)\r
-                                               find_str_temp += '}}}';\r
-                                       else \r
-                                               find_str_temp = find_str_temp.substring(0,find_str_temp.length-13);\r
-                                       find_str_temp += '}}';\r
-                               }\r
-                       }\r
-                       localStorage[localStorage.key(find_cursor))] = find_str_temp;\r
-               }       \r
-       }\r
-       \r
-}\r
-\r
-\r
-function analy_connection(connection_json)\r
-{\r
-       var connection_local_json_tmp;\r
-       for(var i in node_json["objects"]["connection"])\r
-       {\r
-               var json_tmp = node_json["objects"]["connection"][i];\r
-               connection_local_json_tmp = '{'+instance_name+'__'+'connection_'+json_tmp["connection-name"]+':{';\r
-               connection_local_json_tmp += '"Entity_type":"connection","connection_id":"'+json_tmp["connection-id"]+'","connection_name":"'+json_tmp["connection-name"]+'","connection_ype":"'+json_tmp["connection-type"]+'"';\r
-               if(json_tmp["connection-type"] == 'p2p')\r
-               {\r
-                       connection_local_json_tmp +=',"End-nodes":{';\r
-                       connection_local_json_tmp += '"one_node_name":"'+id_match_name[json_tmp["connection-id"]["sub-node"][0]["node-id"]]+'",';\r
-                       connection_local_json_tmp += '"one_node_name":"'+id_match_name[json_tmp["connection-id"]["sub-node"][1]["node-id"]]+'"}';\r
-               }\r
-               else if(json_tmp["connection-type"] == 'p2mp')\r
-               {\r
-                       connection_local_json_tmp +=',"End-nodes":{';\r
-                       connection_local_json_tmp += '"one_node_name":"'+id_match_name[json_tmp["connection-id"]["sub-node"][0]["node-id"]]+'",';\r
-                       connection_local_json_tmp += '"other_node_name":[';\r
-                       for(var p2mp_cursor =1;p2mp_cursor<.length;p2mp_cursor++)\r
-                               connection_local_json_tmp += '"'+id_match_name[json_tmp["connection-id"]["sub-node"][p2mp_cursor]["node-id"]]+'",';\r
-                       connection_local_json_tmp = connection_local_json_tmp.substring(0,connection_local_json_tmp.length-1);\r
-                       connection_local_json_tmp += ']}';\r
-               }\r
-               connection_local_json_tmp += ',"property":{"'+json_tmp["property"][0]["property-name"]+'":"'+json_tmp["property"][0]["property-values"]["int-value"][0]["value"]+'"}';\r
-               connection_local_json_tmp += '}}';\r
-       }\r
-       return  connection_local_json_tmp;\r
-}\r
-\r
-function analy_flow(flow_json)\r
-{\r
-       var flow_local_json_tmp;\r
-       for(var i in flow_json["objects"]["flow"])\r
-       {\r
-               var json_tmp = node_json["objects"]["flow"][i];\r
-               flow_match_name[json_tmp["flow-id"]] = json_tmp["flow-name"];\r
-               flow_local_json_tmp = '{'+instance_name+'__'+'flow_'+json_tmp["flow-name"]+':{';\r
-               flow_local_json_tmp += '"Entity_type":"flow","flow_id":"'+json_tmp["flow-id"]+'","flow_name":"'+json_tmp["flow-name"]+'","match-items":{';\r
-               for(var flow_cursor in json_tmp["match-item"])\r
-               {\r
-                       flow_local_json_tmp += '"'+json_tmp["match-item"][flow_cursor]["match-item-name"]+'":"'+json_tmp["match-item"][flow_cursor]["match-item-values"]+'",';\r
-               }\r
-               flow_local_json_tmp = flow_local_json_tmp.substring(0,flow_local_json_tmp.length-1);\r
-               flow_local_json_tmp += '}}}';\r
-       }\r
-       return  flow_local_json_tmp;\r
-}\r
-\r
-function analy_policy(policy_json)\r
-{\r
-       var policy_local_json_tmp;\r
-       for(var i in flow_json["objects"]["operation"])\r
-       {\r
-               policy_local_json_tmp = '{'+instance_name+'__'+'policy_'+json_tmp["policy-name"]+':{';\r
-               policy_local_json_tmp += '"policy_id":"'+json_tmp["operation-id"]+'","policy_name":"'+json_tmp["operation-name"]+'","apply_entity_id":"'+'flow:'+flow_match_name[json_tmp["target-object"]]+'","condition:["';\r
-               for(var condition_cursor in json_tmp["condition"])\r
-               {\r
-                       policy_local_json_tmp += '"'+json_tmp["condition"][condition_cursor]["condition-parameter-name"]+' '+json_tmp["condition"][condition_cursor]["condition-parameter-match-pattern"]+' '+json_tmp["condition"][condition_cursor]["condtion-parameter-target-value"]["int-value"]+' '+ json_tmp["condition"][condition_cursor]["condition-relation-operator"]+' '+json_tmp["condition"][condition_cursor]["order"]+' '+json_tmp["condition"][condition_cursor]["condition-parameter-id"]+'";';\r
-               }\r
-               policy_local_json_tmp = policy_local_json_tmp.substring(0,policy_local_json_tmp.length-1);\r
-               policy_local_json_tmp += '],';\r
-               \r
-       }       \r
-       return  policy_local_json_tmp;\r
-}
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/jquery-1.7.1.min.js b/nemo-ui/src/main/resources/nemo/js/jquery-1.7.1.min.js
deleted file mode 100644 (file)
index 979ed08..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v1.7.1 jquery.com | jquery.org/license */\r
-(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};\r
-f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()\r
-{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/jquery-ui.min.js b/nemo-ui/src/main/resources/nemo/js/jquery-ui.min.js
deleted file mode 100644 (file)
index 5824d12..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*! jQuery UI - v1.11.4 - 2015-03-11
-* http://jqueryui.com
-* Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js
-* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
-
-(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/^(input|select|textarea|button|object)$/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}function s(e){for(var t,i;e.length&&e[0]!==document;){if(t=e.css("position"),("absolute"===t||"relative"===t||"fixed"===t)&&(i=parseInt(e.css("zIndex"),10),!isNaN(i)&&0!==i))return i;e=e.parent()}return 0}function n(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},e.extend(this._defaults,this.regional[""]),this.regional.en=e.extend(!0,{},this.regional[""]),this.regional["en-US"]=e.extend(!0,{},this.regional.en),this.dpDiv=a(e("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function a(t){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return t.delegate(i,"mouseout",function(){e(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",o)}function o(){e.datepicker._isDisabledDatepicker(v.inline?v.dpDiv.parent()[0]:v.input[0])||(e(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),e(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).addClass("ui-datepicker-next-hover"))}function r(t,i){e.extend(t,i);for(var s in i)null==i[s]&&(t[s]=i[s]);return t}function h(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var l=0,u=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,n=u.call(arguments,1),a=0,o=n.length;o>a;a++)for(i in n[a])s=n[a][i],n[a].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(n){var a="string"==typeof n,o=u.call(arguments,1),r=this;return a?this.each(function(){var i,a=e.data(this,s);return"instance"===n?(r=a,!1):a?e.isFunction(a[n])&&"_"!==n.charAt(0)?(i=a[n].apply(a,o),i!==a&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+n+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+n+"'")}):(o.length&&(n=e.widget.extend.apply(null,[n].concat(o))),this.each(function(){var t=e.data(this,s);t?(t.option(n||{}),t._init&&t._init()):e.data(this,s,new i(n,this))})),r}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=l++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var d=!1;e(document).mouseup(function(){d=!1}),e.widget("ui.mouse",{version:"1.11.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!d){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),d=!0,!0)):!0}},_mouseMove:function(t){if(this._mouseMoved){if(e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button)return this._mouseUp(t);if(!t.which)return this._mouseUp(t)}return(t.which||t.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),d=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),function(){function t(e,t,i){return[parseFloat(e[0])*(p.test(e[0])?t/100:1),parseFloat(e[1])*(p.test(e[1])?i/100:1)]}function i(t,i){return parseInt(e.css(t,i),10)||0}function s(t){var i=t[0];return 9===i.nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:e.isWindow(i)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var n,a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,d=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,p=/%$/,f=e.fn.position;e.position={scrollbarWidth:function(){if(void 0!==n)return n;var t,i,s=e("<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),a=s.children()[0];return e("body").append(s),t=a.offsetWidth,s.css("overflow","scroll"),i=a.offsetWidth,t===i&&(i=s[0].clientWidth),s.remove(),n=t-i},getScrollInfo:function(t){var i=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),s=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),n="scroll"===i||"auto"===i&&t.width<t.element[0].scrollWidth,a="scroll"===s||"auto"===s&&t.height<t.element[0].scrollHeight;return{width:a?e.position.scrollbarWidth():0,height:n?e.position.scrollbarWidth():0}},getWithinInfo:function(t){var i=e(t||window),s=e.isWindow(i[0]),n=!!i[0]&&9===i[0].nodeType;return{element:i,isWindow:s,isDocument:n,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s||n?i.width():i.outerWidth(),height:s||n?i.height():i.outerHeight()}}},e.fn.position=function(n){if(!n||!n.of)return f.apply(this,arguments);n=e.extend({},n);var p,m,g,v,y,b,_=e(n.of),x=e.position.getWithinInfo(n.within),w=e.position.getScrollInfo(x),k=(n.collision||"flip").split(" "),T={};return b=s(_),_[0].preventDefault&&(n.at="left top"),m=b.width,g=b.height,v=b.offset,y=e.extend({},v),e.each(["my","at"],function(){var e,t,i=(n[this]||"").split(" ");1===i.length&&(i=l.test(i[0])?i.concat(["center"]):u.test(i[0])?["center"].concat(i):["center","center"]),i[0]=l.test(i[0])?i[0]:"center",i[1]=u.test(i[1])?i[1]:"center",e=d.exec(i[0]),t=d.exec(i[1]),T[this]=[e?e[0]:0,t?t[0]:0],n[this]=[c.exec(i[0])[0],c.exec(i[1])[0]]}),1===k.length&&(k[1]=k[0]),"right"===n.at[0]?y.left+=m:"center"===n.at[0]&&(y.left+=m/2),"bottom"===n.at[1]?y.top+=g:"center"===n.at[1]&&(y.top+=g/2),p=t(T.at,m,g),y.left+=p[0],y.top+=p[1],this.each(function(){var s,l,u=e(this),d=u.outerWidth(),c=u.outerHeight(),f=i(this,"marginLeft"),b=i(this,"marginTop"),D=d+f+i(this,"marginRight")+w.width,S=c+b+i(this,"marginBottom")+w.height,M=e.extend({},y),C=t(T.my,u.outerWidth(),u.outerHeight());"right"===n.my[0]?M.left-=d:"center"===n.my[0]&&(M.left-=d/2),"bottom"===n.my[1]?M.top-=c:"center"===n.my[1]&&(M.top-=c/2),M.left+=C[0],M.top+=C[1],a||(M.left=h(M.left),M.top=h(M.top)),s={marginLeft:f,marginTop:b},e.each(["left","top"],function(t,i){e.ui.position[k[t]]&&e.ui.position[k[t]][i](M,{targetWidth:m,targetHeight:g,elemWidth:d,elemHeight:c,collisionPosition:s,collisionWidth:D,collisionHeight:S,offset:[p[0]+C[0],p[1]+C[1]],my:n.my,at:n.at,within:x,elem:u})}),n.using&&(l=function(e){var t=v.left-M.left,i=t+m-d,s=v.top-M.top,a=s+g-c,h={target:{element:_,left:v.left,top:v.top,width:m,height:g},element:{element:u,left:M.left,top:M.top,width:d,height:c},horizontal:0>i?"left":t>0?"right":"center",vertical:0>a?"top":s>0?"bottom":"middle"};d>m&&m>r(t+i)&&(h.horizontal="center"),c>g&&g>r(s+a)&&(h.vertical="middle"),h.important=o(r(t),r(i))>o(r(s),r(a))?"horizontal":"vertical",n.using.call(this,e,h)}),u.offset(e.extend(M,{using:l}))})},e.ui.position={fit:{left:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=e.left-t.collisionPosition.marginLeft,h=n-r,l=r+t.collisionWidth-a-n;t.collisionWidth>a?h>0&&0>=l?(i=e.left+h+t.collisionWidth-a-n,e.left+=h-i):e.left=l>0&&0>=h?n:h>l?n+a-t.collisionWidth:n:h>0?e.left+=h:l>0?e.left-=l:e.left=o(e.left-r,e.left)},top:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollTop:s.offset.top,a=t.within.height,r=e.top-t.collisionPosition.marginTop,h=n-r,l=r+t.collisionHeight-a-n;t.collisionHeight>a?h>0&&0>=l?(i=e.top+h+t.collisionHeight-a-n,e.top+=h-i):e.top=l>0&&0>=h?n:h>l?n+a-t.collisionHeight:n:h>0?e.top+=h:l>0?e.top-=l:e.top=o(e.top-r,e.top)}},flip:{left:function(e,t){var i,s,n=t.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=e.left-t.collisionPosition.marginLeft,u=l-h,d=l+t.collisionWidth-o-h,c="left"===t.my[0]?-t.elemWidth:"right"===t.my[0]?t.elemWidth:0,p="left"===t.at[0]?t.targetWidth:"right"===t.at[0]?-t.targetWidth:0,f=-2*t.offset[0];0>u?(i=e.left+c+p+f+t.collisionWidth-o-a,(0>i||r(u)>i)&&(e.left+=c+p+f)):d>0&&(s=e.left-t.collisionPosition.marginLeft+c+p+f-h,(s>0||d>r(s))&&(e.left+=c+p+f))},top:function(e,t){var i,s,n=t.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=e.top-t.collisionPosition.marginTop,u=l-h,d=l+t.collisionHeight-o-h,c="top"===t.my[1],p=c?-t.elemHeight:"bottom"===t.my[1]?t.elemHeight:0,f="top"===t.at[1]?t.targetHeight:"bottom"===t.at[1]?-t.targetHeight:0,m=-2*t.offset[1];0>u?(s=e.top+p+f+m+t.collisionHeight-o-a,(0>s||r(u)>s)&&(e.top+=p+f+m)):d>0&&(i=e.top-t.collisionPosition.marginTop+p+f+m-h,(i>0||d>r(i))&&(e.top+=p+f+m))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,i,s,n,o,r=document.getElementsByTagName("body")[0],h=document.createElement("div");t=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&e.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)t.style[o]=s[o];t.appendChild(h),i=r||document.documentElement,i.insertBefore(t,i.firstChild),h.style.cssText="position: absolute; left: 10.7432222px;",n=e(h).offset().left,a=n>10&&11>n,t.innerHTML="",i.removeChild(t)}()}(),e.ui.position,e.widget("ui.accordion",{version:"1.11.4",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),t.collapsible||t.active!==!1&&null!=t.active||(t.active=0),this._processPanels(),0>t.active&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("<span>").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").removeUniqueId(),this._destroyIcons(),e=this.headers.next().removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&e.css("height","")},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):("event"===e&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),"collapsible"!==e||t||this.options.active!==!1||this._activate(0),"icons"===e&&(this._destroyIcons(),t&&this._createIcons()),"disabled"===e&&(this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)),void 0)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var i=e.ui.keyCode,s=this.headers.length,n=this.headers.index(t.target),a=!1;switch(t.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(t);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(e(t.target).attr("tabIndex",-1),e(a).attr("tabIndex",0),a.focus(),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t=this.options;this._processPanels(),t.active===!1&&t.collapsible===!0||!this.headers.length?(t.active=!1,this.active=e()):t.active===!1?this._activate(0):this.active.length&&!e.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=e()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var e=this.headers,t=this.panels;this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-state-default ui-corner-all"),this.panels=this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide(),t&&(this._off(e.not(this.headers)),this._off(t.not(this.panels)))},_refresh:function(){var t,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var t=e(this),i=t.uniqueId().attr("id"),s=t.next(),n=s.uniqueId().attr("id");t.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(t=n.height(),this.element.siblings(":visible").each(function(){var i=e(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(t-=i.outerHeight(!0))}),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===s&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var i=this._findActive(t)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):e()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?e():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?e():n,newPanel:r};t.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",t,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?e():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(t){var i=t.newPanel,s=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,t):(s.hide(),i.show(),this._toggleComplete(t)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(e(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(e,t,i){var s,n,a,o=this,r=0,h=e.css("box-sizing"),l=e.length&&(!t.length||e.index()<t.index()),u=this.options.animate||{},d=l&&u.down||u,c=function(){o._toggleComplete(i)};return"number"==typeof d&&(a=d),"string"==typeof d&&(n=d),n=n||d.easing||u.easing,a=a||d.duration||u.duration,t.length?e.length?(s=e.show().outerHeight(),t.animate(this.hideProps,{duration:a,easing:n,step:function(e,t){t.now=Math.round(e)}}),e.hide().animate(this.showProps,{duration:a,easing:n,complete:c,step:function(e,i){i.now=Math.round(e),"height"!==i.prop?"content-box"===h&&(r+=i.now):"content"!==o.options.heightStyle&&(i.now=Math.round(s-t.outerHeight()-r),r=0)}}),void 0):t.animate(this.hideProps,a,n,c):e.animate(this.showProps,a,n,c)},_toggleComplete:function(e){var t=e.oldPanel;t.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),t.length&&(t.parent()[0].className=t.parent()[0].className),this._trigger("activate",null,e)}}),e.widget("ui.menu",{version:"1.11.4",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},items:"> *",menus:"ul",position:{my:"left-1 top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item":function(e){e.preventDefault()},"click .ui-menu-item":function(t){var i=e(t.target);!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&e(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){if(!this.previousFilter){var i=e(t.currentTarget);
-i.siblings(".ui-state-active").removeClass("ui-state-active"),this.focus(t,i)}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var i=this.active||this.element.find(this.options.items).eq(0);t||this.focus(e,i)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){this._closeOnDocumentClick(e)&&this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").removeUniqueId().removeClass("ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){var i,s,n,a,o=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:o=!1,s=this.previousFilter||"",n=String.fromCharCode(t.keyCode),a=!1,clearTimeout(this.filterTimer),n===s?a=!0:n=s+n,i=this._filterMenuItems(n),i=a&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(t.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(t,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}o&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.is("[aria-haspopup='true']")?this.expand(e):this.select(e))},refresh:function(){var t,i,s=this,n=this.options.icons.submenu,a=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),a.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-front").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),i=t.parent(),s=e("<span>").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);i.attr("aria-haspopup","true").prepend(s),t.attr("aria-labelledby",i.attr("id"))}),t=a.add(this.element),i=t.find(this.options.items),i.not(".ui-menu-item").each(function(){var t=e(this);s._isDivider(t)&&t.addClass("ui-widget-content ui-menu-divider")}),i.not(".ui-menu-item, .ui-menu-divider").addClass("ui-menu-item").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(e,t){"icons"===e&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(t.submenu),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},focus:function(e,t){var i,s;this.blur(e,e&&"focus"===e.type),this._scrollIntoView(t),this.active=t.first(),s=this.active.addClass("ui-state-focus").removeClass("ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").addClass("ui-state-active"),e&&"keydown"===e.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=t.children(".ui-menu"),i.length&&e&&/^mouse/.test(e.type)&&this._startOpening(i),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,n=t.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=t.outerHeight(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(e,t){t||clearTimeout(this.timer),this.active&&(this.active.removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active}))},_startOpening:function(e){clearTimeout(this.timer),"true"===e.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(e)},this.delay))},_open:function(t){var i=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(t,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(t),this.activeMenu=s},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find(".ui-state-active").not(".ui-state-focus").removeClass("ui-state-active")},_closeOnDocumentClick:function(t){return!e(t.target).closest(".ui-menu").length},_isDivider:function(e){return!/[^\-\u2014\u2013\s]/.test(e.text())},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,i){var s;this.active&&(s="first"===e||"last"===e?this.active["first"===e?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[e+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[t]()),this.focus(i,s)},nextPage:function(t){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=e(this),0>i.offset().top-s-n}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(t),void 0)},previousPage:function(t){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=e(this),i.offset().top-s+n>0}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items).first())),void 0):(this.next(t),void 0)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(t){this.active=this.active||e(t.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(t,!0),this._trigger("select",t,i)},_filterMenuItems:function(t){var i=t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"),s=RegExp("^"+i,"i");return this.activeMenu.find(this.options.items).filter(".ui-menu-item").filter(function(){return s.test(e.trim(e(this).text()))})}}),e.widget("ui.autocomplete",{version:"1.11.4",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,void 0;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),void 0):(this._searchTimeout(e),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(e),this._change(e),void 0)}}),this._initSource(),this.menu=e("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];e(t.target).closest(".ui-menu-item").length||this._delay(function(){var t=this;this.document.one("mousedown",function(s){s.target===t.element[0]||s.target===i||e.contains(i,s.target)||t.close()})})},menufocus:function(t,i){var s,n;return this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type))?(this.menu.blur(),this.document.one("mousemove",function(){e(t.target).trigger(t.originalEvent)}),void 0):(n=i.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",t,{item:n})&&t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(n.value),s=i.item.attr("aria-label")||n.value,s&&e.trim(s).length&&(this.liveRegion.children().hide(),e("<div>").text(s).appendTo(this.liveRegion)),void 0)},menuselect:function(e,t){var i=t.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",e,{item:i})&&this._value(i.value),this.term=this._value(),this.close(e),this.selectedItem=i}}),this.liveRegion=e("<span>",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(e,t){this._super(e,t),"source"===e&&this._initSource(),"appendTo"===e&&this.menu.element.appendTo(this._appendTo()),"disabled"===e&&t&&this.xhr&&this.xhr.abort()},_appendTo:function(){var t=this.options.appendTo;return t&&(t=t.jquery||t.nodeType?e(t):this.document.find(t).eq(0)),t&&t[0]||(t=this.element.closest(".ui-front")),t.length||(t=this.document[0].body),t},_initSource:function(){var t,i,s=this;e.isArray(this.options.source)?(t=this.options.source,this.source=function(i,s){s(e.ui.autocomplete.filter(t,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(t,n){s.xhr&&s.xhr.abort(),s.xhr=e.ajax({url:i,data:t,dataType:"json",success:function(e){n(e)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(e){clearTimeout(this.searching),this.searching=this._delay(function(){var t=this.term===this._value(),i=this.menu.element.is(":visible"),s=e.altKey||e.ctrlKey||e.metaKey||e.shiftKey;(!t||t&&!i&&!s)&&(this.selectedItem=null,this.search(null,e))},this.options.delay)},search:function(e,t){return e=null!=e?e:this._value(),this.term=this._value(),e.length<this.options.minLength?this.close(t):this._trigger("search",t)!==!1?this._search(e):void 0},_search:function(e){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:e},this._response())},_response:function(){var t=++this.requestIndex;return e.proxy(function(e){t===this.requestIndex&&this.__response(e),this.pending--,this.pending||this.element.removeClass("ui-autocomplete-loading")},this)},__response:function(e){e&&(e=this._normalize(e)),this._trigger("response",null,{content:e}),!this.options.disabled&&e&&e.length&&!this.cancelSearch?(this._suggest(e),this._trigger("open")):this._close()},close:function(e){this.cancelSearch=!0,this._close(e)},_close:function(e){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",e))},_change:function(e){this.previous!==this._value()&&this._trigger("change",e,{item:this.selectedItem})},_normalize:function(t){return t.length&&t[0].label&&t[0].value?t:e.map(t,function(t){return"string"==typeof t?{label:t,value:t}:e.extend({},t,{label:t.label||t.value,value:t.value||t.label})})},_suggest:function(t){var i=this.menu.element.empty();this._renderMenu(i,t),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(e.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var e=this.menu.element;e.outerWidth(Math.max(e.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(t,i){var s=this;e.each(i,function(e,i){s._renderItemData(t,i)})},_renderItemData:function(e,t){return this._renderItem(e,t).data("ui-autocomplete-item",t)},_renderItem:function(t,i){return e("<li>").text(i.label).appendTo(t)},_move:function(e,t){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(e)||this.menu.isLastItem()&&/^next/.test(e)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[e](t),void 0):(this.search(null,t),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(e,t){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(e,t),t.preventDefault())}}),e.extend(e.ui.autocomplete,{escapeRegex:function(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,i){var s=RegExp(e.ui.autocomplete.escapeRegex(i),"i");return e.grep(t,function(e){return s.test(e.label||e.value||e)})}}),e.widget("ui.autocomplete",e.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(e){return e+(e>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.children().hide(),e("<div>").text(i).appendTo(this.liveRegion))}}),e.ui.autocomplete;var c,p="ui-button ui-widget ui-state-default ui-corner-all",f="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",m=function(){var t=e(this);setTimeout(function(){t.find(":ui-button").button("refresh")},1)},g=function(t){var i=t.name,s=t.form,n=e([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?e(s).find("[name='"+i+"'][type=radio]"):e("[name='"+i+"'][type=radio]",t.ownerDocument).filter(function(){return!this.form})),n};e.widget("ui.button",{version:"1.11.4",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,m),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var t=this,i=this.options,s="checkbox"===this.type||"radio"===this.type,n=s?"":"ui-state-active";null===i.label&&(i.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(p).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){i.disabled||this===c&&e(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){i.disabled||e(this).removeClass(n)}).bind("click"+this.eventNamespace,function(e){i.disabled&&(e.preventDefault(),e.stopImmediatePropagation())}),this._on({focus:function(){this.buttonElement.addClass("ui-state-focus")},blur:function(){this.buttonElement.removeClass("ui-state-focus")}}),s&&this.element.bind("change"+this.eventNamespace,function(){t.refresh()}),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return i.disabled?!1:void 0}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(i.disabled)return!1;e(this).addClass("ui-state-active"),t.buttonElement.attr("aria-pressed","true");var s=t.element[0];g(s).not(s).map(function(){return e(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return i.disabled?!1:(e(this).addClass("ui-state-active"),c=this,t.document.one("mouseup",function(){c=null}),void 0)}).bind("mouseup"+this.eventNamespace,function(){return i.disabled?!1:(e(this).removeClass("ui-state-active"),void 0)}).bind("keydown"+this.eventNamespace,function(t){return i.disabled?!1:((t.keyCode===e.ui.keyCode.SPACE||t.keyCode===e.ui.keyCode.ENTER)&&e(this).addClass("ui-state-active"),void 0)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){e(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(t){t.keyCode===e.ui.keyCode.SPACE&&e(this).click()})),this._setOption("disabled",i.disabled),this._resetButton()},_determineButtonType:function(){var e,t,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(e=this.element.parents().last(),t="label[for='"+this.element.attr("id")+"']",this.buttonElement=e.find(t),this.buttonElement.length||(e=e.length?e.siblings():this.element.siblings(),this.buttonElement=e.filter(t),this.buttonElement.length||(this.buttonElement=e.find(t))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(p+" ui-state-active "+f).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(e,t){return this._super(e,t),"disabled"===e?(this.widget().toggleClass("ui-state-disabled",!!t),this.element.prop("disabled",!!t),t&&("checkbox"===this.type||"radio"===this.type?this.buttonElement.removeClass("ui-state-focus"):this.buttonElement.removeClass("ui-state-focus ui-state-active")),void 0):(this._resetButton(),void 0)},refresh:function(){var t=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");t!==this.options.disabled&&this._setOption("disabled",t),"radio"===this.type?g(this.element[0]).each(function(){e(this).is(":checked")?e(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):e(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),void 0;var t=this.buttonElement.removeClass(f),i=e("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(t.empty()).text(),s=this.options.icons,n=s.primary&&s.secondary,a=[];s.primary||s.secondary?(this.options.text&&a.push("ui-button-text-icon"+(n?"s":s.primary?"-primary":"-secondary")),s.primary&&t.prepend("<span class='ui-button-icon-primary ui-icon "+s.primary+"'></span>"),s.secondary&&t.append("<span class='ui-button-icon-secondary ui-icon "+s.secondary+"'></span>"),this.options.text||(a.push(n?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||t.attr("title",e.trim(i)))):a.push("ui-button-text-only"),t.addClass(a.join(" "))}}),e.widget("ui.buttonset",{version:"1.11.4",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(e,t){"disabled"===e&&this.buttons.button("option",e,t),this._super(e,t)},refresh:function(){var t="rtl"===this.element.css("direction"),i=this.element.find(this.options.items),s=i.filter(":ui-button");i.not(":ui-button").button(),s.button("refresh"),this.buttons=i.map(function(){return e(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(t?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(t?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return e(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}}),e.ui.button,e.extend(e.ui,{datepicker:{version:"1.11.4"}});var v;e.extend(n.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(e){return r(this._defaults,e||{}),this},_attachDatepicker:function(t,i){var s,n,a;s=t.nodeName.toLowerCase(),n="div"===s||"span"===s,t.id||(this.uuid+=1,t.id="dp"+this.uuid),a=this._newInst(e(t),n),a.settings=e.extend({},i||{}),"input"===s?this._connectDatepicker(t,a):n&&this._inlineDatepicker(t,a)},_newInst:function(t,i){var s=t[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:s,input:t,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?a(e("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(t,i){var s=e(t);i.append=e([]),i.trigger=e([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),e.data(t,"datepicker",i),i.settings.disabled&&this._disableDatepicker(t))},_attachments:function(t,i){var s,n,a,o=this._get(i,"appendText"),r=this._get(i,"isRTL");i.append&&i.append.remove(),o&&(i.append=e("<span class='"+this._appendClass+"'>"+o+"</span>"),t[r?"before":"after"](i.append)),t.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&t.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),a=this._get(i,"buttonImage"),i.trigger=e(this._get(i,"buttonImageOnly")?e("<img/>").addClass(this._triggerClass).attr({src:a,alt:n,title:n}):e("<button type='button'></button>").addClass(this._triggerClass).html(a?e("<img/>").attr({src:a,alt:n,title:n}):n)),t[r?"before":"after"](i.trigger),i.trigger.click(function(){return e.datepicker._datepickerShowing&&e.datepicker._lastInput===t[0]?e.datepicker._hideDatepicker():e.datepicker._datepickerShowing&&e.datepicker._lastInput!==t[0]?(e.datepicker._hideDatepicker(),e.datepicker._showDatepicker(t[0])):e.datepicker._showDatepicker(t[0]),!1}))},_autoSize:function(e){if(this._get(e,"autoSize")&&!e.inline){var t,i,s,n,a=new Date(2009,11,20),o=this._get(e,"dateFormat");o.match(/[DM]/)&&(t=function(e){for(i=0,s=0,n=0;e.length>n;n++)e[n].length>i&&(i=e[n].length,s=n);return s},a.setMonth(t(this._get(e,o.match(/MM/)?"monthNames":"monthNamesShort"))),a.setDate(t(this._get(e,o.match(/DD/)?"dayNames":"dayNamesShort"))+20-a.getDay())),e.input.attr("size",this._formatDate(e,a).length)}},_inlineDatepicker:function(t,i){var s=e(t);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),e.data(t,"datepicker",i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(t),i.dpDiv.css("display","block"))},_dialogDatepicker:function(t,i,s,n,a){var o,h,l,u,d,c=this._dialogInst;return c||(this.uuid+=1,o="dp"+this.uuid,this._dialogInput=e("<input type='text' id='"+o+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),e("body").append(this._dialogInput),c=this._dialogInst=this._newInst(this._dialogInput,!1),c.settings={},e.data(this._dialogInput[0],"datepicker",c)),r(c.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(c,i):i,this._dialogInput.val(i),this._pos=a?a.length?a:[a.pageX,a.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+u,l/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),c.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),e.blockUI&&e.blockUI(this.dpDiv),e.data(this._dialogInput[0],"datepicker",c),this},_destroyDatepicker:function(t){var i,s=e(t),n=e.data(t,"datepicker");s.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),e.removeData(t,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),v===n&&(v=null))},_enableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!1,a.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}))},_disableDatepicker:function(t){var i,s,n=e(t),a=e.data(t,"datepicker");n.hasClass(this.markerClassName)&&(i=t.nodeName.toLowerCase(),"input"===i?(t.disabled=!0,a.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=e.map(this._disabledInputs,function(e){return e===t?null:e}),this._disabledInputs[this._disabledInputs.length]=t)},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;this._disabledInputs.length>t;t++)if(this._disabledInputs[t]===e)return!0;return!1},_getInst:function(t){try{return e.data(t,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(t,i,s){var n,a,o,h,l=this._getInst(t);return 2===arguments.length&&"string"==typeof i?"defaults"===i?e.extend({},e.datepicker._defaults):l?"all"===i?e.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),a=this._getDateDatepicker(t,!0),o=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),r(l.settings,n),null!==o&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,o)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(t):this._enableDatepicker(t)),this._attachments(e(t),l),this._autoSize(l),this._setDate(l,a),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(e,t,i){this._optionDatepicker(e,t,i)},_refreshDatepicker:function(e){var t=this._getInst(e);t&&this._updateDatepicker(t)},_setDateDatepicker:function(e,t){var i=this._getInst(e);i&&(this._setDate(i,t),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(e,t){var i=this._getInst(e);return i&&!i.inline&&this._setDateFromField(i,t),i?this._getDate(i):null},_doKeyDown:function(t){var i,s,n,a=e.datepicker._getInst(t.target),o=!0,r=a.dpDiv.is(".ui-datepicker-rtl");if(a._keyEvent=!0,e.datepicker._datepickerShowing)switch(t.keyCode){case 9:e.datepicker._hideDatepicker(),o=!1;break;case 13:return n=e("td."+e.datepicker._dayOverClass+":not(."+e.datepicker._currentClass+")",a.dpDiv),n[0]&&e.datepicker._selectDay(t.target,a.selectedMonth,a.selectedYear,n[0]),i=e.datepicker._get(a,"onSelect"),i?(s=e.datepicker._formatDate(a),i.apply(a.input?a.input[0]:null,[s,a])):e.datepicker._hideDatepicker(),!1;case 27:e.datepicker._hideDatepicker();break;case 33:e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 34:e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 35:(t.ctrlKey||t.metaKey)&&e.datepicker._clearDate(t.target),o=t.ctrlKey||t.metaKey;break;case 36:(t.ctrlKey||t.metaKey)&&e.datepicker._gotoToday(t.target),o=t.ctrlKey||t.metaKey;break;case 37:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?1:-1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?-e.datepicker._get(a,"stepBigMonths"):-e.datepicker._get(a,"stepMonths"),"M");break;case 38:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,-7,"D"),o=t.ctrlKey||t.metaKey;break;case 39:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,r?-1:1,"D"),o=t.ctrlKey||t.metaKey,t.originalEvent.altKey&&e.datepicker._adjustDate(t.target,t.ctrlKey?+e.datepicker._get(a,"stepBigMonths"):+e.datepicker._get(a,"stepMonths"),"M");break;case 40:(t.ctrlKey||t.metaKey)&&e.datepicker._adjustDate(t.target,7,"D"),o=t.ctrlKey||t.metaKey;break;default:o=!1}else 36===t.keyCode&&t.ctrlKey?e.datepicker._showDatepicker(this):o=!1;o&&(t.preventDefault(),t.stopPropagation())},_doKeyPress:function(t){var i,s,n=e.datepicker._getInst(t.target);
-return e.datepicker._get(n,"constrainInput")?(i=e.datepicker._possibleChars(e.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==t.charCode?t.keyCode:t.charCode),t.ctrlKey||t.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(t){var i,s=e.datepicker._getInst(t.target);if(s.input.val()!==s.lastVal)try{i=e.datepicker.parseDate(e.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,e.datepicker._getFormatConfig(s)),i&&(e.datepicker._setDateFromField(s),e.datepicker._updateAlternate(s),e.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(t){if(t=t.target||t,"input"!==t.nodeName.toLowerCase()&&(t=e("input",t.parentNode)[0]),!e.datepicker._isDisabledDatepicker(t)&&e.datepicker._lastInput!==t){var i,n,a,o,h,l,u;i=e.datepicker._getInst(t),e.datepicker._curInst&&e.datepicker._curInst!==i&&(e.datepicker._curInst.dpDiv.stop(!0,!0),i&&e.datepicker._datepickerShowing&&e.datepicker._hideDatepicker(e.datepicker._curInst.input[0])),n=e.datepicker._get(i,"beforeShow"),a=n?n.apply(t,[t,i]):{},a!==!1&&(r(i.settings,a),i.lastVal=null,e.datepicker._lastInput=t,e.datepicker._setDateFromField(i),e.datepicker._inDialog&&(t.value=""),e.datepicker._pos||(e.datepicker._pos=e.datepicker._findPos(t),e.datepicker._pos[1]+=t.offsetHeight),o=!1,e(t).parents().each(function(){return o|="fixed"===e(this).css("position"),!o}),h={left:e.datepicker._pos[0],top:e.datepicker._pos[1]},e.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),e.datepicker._updateDatepicker(i),h=e.datepicker._checkOffset(i,h,o),i.dpDiv.css({position:e.datepicker._inDialog&&e.blockUI?"static":o?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),i.inline||(l=e.datepicker._get(i,"showAnim"),u=e.datepicker._get(i,"duration"),i.dpDiv.css("z-index",s(e(t))+1),e.datepicker._datepickerShowing=!0,e.effects&&e.effects.effect[l]?i.dpDiv.show(l,e.datepicker._get(i,"showOptions"),u):i.dpDiv[l||"show"](l?u:null),e.datepicker._shouldFocusInput(i)&&i.input.focus(),e.datepicker._curInst=i))}},_updateDatepicker:function(t){this.maxRows=4,v=t,t.dpDiv.empty().append(this._generateHTML(t)),this._attachHandlers(t);var i,s=this._getNumberOfMonths(t),n=s[1],a=17,r=t.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),t.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&t.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),t.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),t.dpDiv[(this._get(t,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),t===e.datepicker._curInst&&e.datepicker._datepickerShowing&&e.datepicker._shouldFocusInput(t)&&t.input.focus(),t.yearshtml&&(i=t.yearshtml,setTimeout(function(){i===t.yearshtml&&t.yearshtml&&t.dpDiv.find("select.ui-datepicker-year:first").replaceWith(t.yearshtml),i=t.yearshtml=null},0))},_shouldFocusInput:function(e){return e.input&&e.input.is(":visible")&&!e.input.is(":disabled")&&!e.input.is(":focus")},_checkOffset:function(t,i,s){var n=t.dpDiv.outerWidth(),a=t.dpDiv.outerHeight(),o=t.input?t.input.outerWidth():0,r=t.input?t.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:e(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:e(document).scrollTop());return i.left-=this._get(t,"isRTL")?n-o:0,i.left-=s&&i.left===t.input.offset().left?e(document).scrollLeft():0,i.top-=s&&i.top===t.input.offset().top+r?e(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+a>l&&l>a?Math.abs(a+r):0),i},_findPos:function(t){for(var i,s=this._getInst(t),n=this._get(s,"isRTL");t&&("hidden"===t.type||1!==t.nodeType||e.expr.filters.hidden(t));)t=t[n?"previousSibling":"nextSibling"];return i=e(t).offset(),[i.left,i.top]},_hideDatepicker:function(t){var i,s,n,a,o=this._curInst;!o||t&&o!==e.data(t,"datepicker")||this._datepickerShowing&&(i=this._get(o,"showAnim"),s=this._get(o,"duration"),n=function(){e.datepicker._tidyDialog(o)},e.effects&&(e.effects.effect[i]||e.effects[i])?o.dpDiv.hide(i,e.datepicker._get(o,"showOptions"),s,n):o.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,a=this._get(o,"onClose"),a&&a.apply(o.input?o.input[0]:null,[o.input?o.input.val():"",o]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),e.blockUI&&(e.unblockUI(),e("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(e){e.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(t){if(e.datepicker._curInst){var i=e(t.target),s=e.datepicker._getInst(i[0]);(i[0].id!==e.datepicker._mainDivId&&0===i.parents("#"+e.datepicker._mainDivId).length&&!i.hasClass(e.datepicker.markerClassName)&&!i.closest("."+e.datepicker._triggerClass).length&&e.datepicker._datepickerShowing&&(!e.datepicker._inDialog||!e.blockUI)||i.hasClass(e.datepicker.markerClassName)&&e.datepicker._curInst!==s)&&e.datepicker._hideDatepicker()}},_adjustDate:function(t,i,s){var n=e(t),a=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(a,i+("M"===s?this._get(a,"showCurrentAtPos"):0),s),this._updateDatepicker(a))},_gotoToday:function(t){var i,s=e(t),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(t,i,s){var n=e(t),a=this._getInst(n[0]);a["selected"+("M"===s?"Month":"Year")]=a["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(a),this._adjustDate(n)},_selectDay:function(t,i,s,n){var a,o=e(t);e(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(o[0])||(a=this._getInst(o[0]),a.selectedDay=a.currentDay=e("a",n).html(),a.selectedMonth=a.currentMonth=i,a.selectedYear=a.currentYear=s,this._selectDate(t,this._formatDate(a,a.currentDay,a.currentMonth,a.currentYear)))},_clearDate:function(t){var i=e(t);this._selectDate(i,"")},_selectDate:function(t,i){var s,n=e(t),a=this._getInst(n[0]);i=null!=i?i:this._formatDate(a),a.input&&a.input.val(i),this._updateAlternate(a),s=this._get(a,"onSelect"),s?s.apply(a.input?a.input[0]:null,[i,a]):a.input&&a.input.trigger("change"),a.inline?this._updateDatepicker(a):(this._hideDatepicker(),this._lastInput=a.input[0],"object"!=typeof a.input[0]&&a.input.focus(),this._lastInput=null)},_updateAlternate:function(t){var i,s,n,a=this._get(t,"altField");a&&(i=this._get(t,"altFormat")||this._get(t,"dateFormat"),s=this._getDate(t),n=this.formatDate(i,s,this._getFormatConfig(t)),e(a).each(function(){e(this).val(n)}))},noWeekends:function(e){var t=e.getDay();return[t>0&&6>t,""]},iso8601Week:function(e){var t,i=new Date(e.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),t=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((t-i)/864e5)/7)+1},parseDate:function(t,i,s){if(null==t||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,a,o,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),d=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,c=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,m=-1,g=-1,v=-1,y=-1,b=!1,_=function(e){var i=t.length>n+1&&t.charAt(n+1)===e;return i&&n++,i},x=function(e){var t=_(e),s="@"===e?14:"!"===e?20:"y"===e&&t?4:"o"===e?3:2,n="y"===e?s:1,a=RegExp("^\\d{"+n+","+s+"}"),o=i.substring(h).match(a);if(!o)throw"Missing number at position "+h;return h+=o[0].length,parseInt(o[0],10)},w=function(t,s,n){var a=-1,o=e.map(_(t)?n:s,function(e,t){return[[t,e]]}).sort(function(e,t){return-(e[1].length-t[1].length)});if(e.each(o,function(e,t){var s=t[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(a=t[0],h+=s.length,!1):void 0}),-1!==a)return a+1;throw"Unknown name at position "+h},k=function(){if(i.charAt(h)!==t.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;t.length>n;n++)if(b)"'"!==t.charAt(n)||_("'")?k():b=!1;else switch(t.charAt(n)){case"d":v=x("d");break;case"D":w("D",d,c);break;case"o":y=x("o");break;case"m":g=x("m");break;case"M":g=w("M",p,f);break;case"y":m=x("y");break;case"@":r=new Date(x("@")),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"!":r=new Date((x("!")-this._ticksTo1970)/1e4),m=r.getFullYear(),g=r.getMonth()+1,v=r.getDate();break;case"'":_("'")?k():b=!0;break;default:k()}if(i.length>h&&(o=i.substr(h),!/^\s+/.test(o)))throw"Extra/unparsed characters found in date: "+o;if(-1===m?m=(new Date).getFullYear():100>m&&(m+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=m?0:-100)),y>-1)for(g=1,v=y;;){if(a=this._getDaysInMonth(m,g-1),a>=v)break;g++,v-=a}if(r=this._daylightSavingAdjust(new Date(m,g-1,v)),r.getFullYear()!==m||r.getMonth()+1!==g||r.getDate()!==v)throw"Invalid date";return r},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(e,t,i){if(!t)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,a=(i?i.dayNames:null)||this._defaults.dayNames,o=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(t){var i=e.length>s+1&&e.charAt(s+1)===t;return i&&s++,i},l=function(e,t,i){var s=""+t;if(h(e))for(;i>s.length;)s="0"+s;return s},u=function(e,t,i,s){return h(e)?s[t]:i[t]},d="",c=!1;if(t)for(s=0;e.length>s;s++)if(c)"'"!==e.charAt(s)||h("'")?d+=e.charAt(s):c=!1;else switch(e.charAt(s)){case"d":d+=l("d",t.getDate(),2);break;case"D":d+=u("D",t.getDay(),n,a);break;case"o":d+=l("o",Math.round((new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()-new Date(t.getFullYear(),0,0).getTime())/864e5),3);break;case"m":d+=l("m",t.getMonth()+1,2);break;case"M":d+=u("M",t.getMonth(),o,r);break;case"y":d+=h("y")?t.getFullYear():(10>t.getYear()%100?"0":"")+t.getYear()%100;break;case"@":d+=t.getTime();break;case"!":d+=1e4*t.getTime()+this._ticksTo1970;break;case"'":h("'")?d+="'":c=!0;break;default:d+=e.charAt(s)}return d},_possibleChars:function(e){var t,i="",s=!1,n=function(i){var s=e.length>t+1&&e.charAt(t+1)===i;return s&&t++,s};for(t=0;e.length>t;t++)if(s)"'"!==e.charAt(t)||n("'")?i+=e.charAt(t):s=!1;else switch(e.charAt(t)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=e.charAt(t)}return i},_get:function(e,t){return void 0!==e.settings[t]?e.settings[t]:this._defaults[t]},_setDateFromField:function(e,t){if(e.input.val()!==e.lastVal){var i=this._get(e,"dateFormat"),s=e.lastVal=e.input?e.input.val():null,n=this._getDefaultDate(e),a=n,o=this._getFormatConfig(e);try{a=this.parseDate(i,s,o)||n}catch(r){s=t?"":s}e.selectedDay=a.getDate(),e.drawMonth=e.selectedMonth=a.getMonth(),e.drawYear=e.selectedYear=a.getFullYear(),e.currentDay=s?a.getDate():0,e.currentMonth=s?a.getMonth():0,e.currentYear=s?a.getFullYear():0,this._adjustInstDate(e)}},_getDefaultDate:function(e){return this._restrictMinMax(e,this._determineDate(e,this._get(e,"defaultDate"),new Date))},_determineDate:function(t,i,s){var n=function(e){var t=new Date;return t.setDate(t.getDate()+e),t},a=function(i){try{return e.datepicker.parseDate(e.datepicker._get(t,"dateFormat"),i,e.datepicker._getFormatConfig(t))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?e.datepicker._getDate(t):null)||new Date,a=n.getFullYear(),o=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":o+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o));break;case"y":case"Y":a+=parseInt(l[1],10),r=Math.min(r,e.datepicker._getDaysInMonth(a,o))}l=h.exec(i)}return new Date(a,o,r)},o=null==i||""===i?s:"string"==typeof i?a(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return o=o&&"Invalid Date"==""+o?s:o,o&&(o.setHours(0),o.setMinutes(0),o.setSeconds(0),o.setMilliseconds(0)),this._daylightSavingAdjust(o)},_daylightSavingAdjust:function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},_setDate:function(e,t,i){var s=!t,n=e.selectedMonth,a=e.selectedYear,o=this._restrictMinMax(e,this._determineDate(e,t,new Date));e.selectedDay=e.currentDay=o.getDate(),e.drawMonth=e.selectedMonth=e.currentMonth=o.getMonth(),e.drawYear=e.selectedYear=e.currentYear=o.getFullYear(),n===e.selectedMonth&&a===e.selectedYear||i||this._notifyChange(e),this._adjustInstDate(e),e.input&&e.input.val(s?"":this._formatDate(e))},_getDate:function(e){var t=!e.currentYear||e.input&&""===e.input.val()?null:this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return t},_attachHandlers:function(t){var i=this._get(t,"stepMonths"),s="#"+t.id.replace(/\\\\/g,"\\");t.dpDiv.find("[data-handler]").map(function(){var t={prev:function(){e.datepicker._adjustDate(s,-i,"M")},next:function(){e.datepicker._adjustDate(s,+i,"M")},hide:function(){e.datepicker._hideDatepicker()},today:function(){e.datepicker._gotoToday(s)},selectDay:function(){return e.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return e.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return e.datepicker._selectMonthYear(s,this,"Y"),!1}};e(this).bind(this.getAttribute("data-event"),t[this.getAttribute("data-handler")])})},_generateHTML:function(e){var t,i,s,n,a,o,r,h,l,u,d,c,p,f,m,g,v,y,b,_,x,w,k,T,D,S,M,C,N,A,P,I,H,z,F,E,O,j,W,L=new Date,R=this._daylightSavingAdjust(new Date(L.getFullYear(),L.getMonth(),L.getDate())),Y=this._get(e,"isRTL"),B=this._get(e,"showButtonPanel"),J=this._get(e,"hideIfNoPrevNext"),q=this._get(e,"navigationAsDateFormat"),K=this._getNumberOfMonths(e),V=this._get(e,"showCurrentAtPos"),U=this._get(e,"stepMonths"),Q=1!==K[0]||1!==K[1],G=this._daylightSavingAdjust(e.currentDay?new Date(e.currentYear,e.currentMonth,e.currentDay):new Date(9999,9,9)),X=this._getMinMaxDate(e,"min"),$=this._getMinMaxDate(e,"max"),Z=e.drawMonth-V,et=e.drawYear;if(0>Z&&(Z+=12,et--),$)for(t=this._daylightSavingAdjust(new Date($.getFullYear(),$.getMonth()-K[0]*K[1]+1,$.getDate())),t=X&&X>t?X:t;this._daylightSavingAdjust(new Date(et,Z,1))>t;)Z--,0>Z&&(Z=11,et--);for(e.drawMonth=Z,e.drawYear=et,i=this._get(e,"prevText"),i=q?this.formatDate(i,this._daylightSavingAdjust(new Date(et,Z-U,1)),this._getFormatConfig(e)):i,s=this._canAdjustMonth(e,-1,et,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":J?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(e,"nextText"),n=q?this.formatDate(n,this._daylightSavingAdjust(new Date(et,Z+U,1)),this._getFormatConfig(e)):n,a=this._canAdjustMonth(e,1,et,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":J?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",o=this._get(e,"currentText"),r=this._get(e,"gotoCurrent")&&e.currentDay?G:R,o=q?this.formatDate(o,r,this._getFormatConfig(e)):o,h=e.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(e,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(e,r)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+o+"</button>":"")+(Y?"":h)+"</div>":"",u=parseInt(this._get(e,"firstDay"),10),u=isNaN(u)?0:u,d=this._get(e,"showWeek"),c=this._get(e,"dayNames"),p=this._get(e,"dayNamesMin"),f=this._get(e,"monthNames"),m=this._get(e,"monthNamesShort"),g=this._get(e,"beforeShowDay"),v=this._get(e,"showOtherMonths"),y=this._get(e,"selectOtherMonths"),b=this._getDefaultDate(e),_="",w=0;K[0]>w;w++){for(k="",this.maxRows=4,T=0;K[1]>T;T++){if(D=this._daylightSavingAdjust(new Date(et,Z,e.selectedDay)),S=" ui-corner-all",M="",Q){if(M+="<div class='ui-datepicker-group",K[1]>1)switch(T){case 0:M+=" ui-datepicker-group-first",S=" ui-corner-"+(Y?"right":"left");break;case K[1]-1:M+=" ui-datepicker-group-last",S=" ui-corner-"+(Y?"left":"right");break;default:M+=" ui-datepicker-group-middle",S=""}M+="'>"}for(M+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+S+"'>"+(/all|left/.test(S)&&0===w?Y?a:s:"")+(/all|right/.test(S)&&0===w?Y?s:a:"")+this._generateMonthYearHeader(e,Z,et,X,$,w>0||T>0,f,m)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",C=d?"<th class='ui-datepicker-week-col'>"+this._get(e,"weekHeader")+"</th>":"",x=0;7>x;x++)N=(x+u)%7,C+="<th scope='col'"+((x+u+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+c[N]+"'>"+p[N]+"</span></th>";for(M+=C+"</tr></thead><tbody>",A=this._getDaysInMonth(et,Z),et===e.selectedYear&&Z===e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,A)),P=(this._getFirstDayOfMonth(et,Z)-u+7)%7,I=Math.ceil((P+A)/7),H=Q?this.maxRows>I?this.maxRows:I:I,this.maxRows=H,z=this._daylightSavingAdjust(new Date(et,Z,1-P)),F=0;H>F;F++){for(M+="<tr>",E=d?"<td class='ui-datepicker-week-col'>"+this._get(e,"calculateWeek")(z)+"</td>":"",x=0;7>x;x++)O=g?g.apply(e.input?e.input[0]:null,[z]):[!0,""],j=z.getMonth()!==Z,W=j&&!y||!O[0]||X&&X>z||$&&z>$,E+="<td class='"+((x+u+6)%7>=5?" ui-datepicker-week-end":"")+(j?" ui-datepicker-other-month":"")+(z.getTime()===D.getTime()&&Z===e.selectedMonth&&e._keyEvent||b.getTime()===z.getTime()&&b.getTime()===D.getTime()?" "+this._dayOverClass:"")+(W?" "+this._unselectableClass+" ui-state-disabled":"")+(j&&!v?"":" "+O[1]+(z.getTime()===G.getTime()?" "+this._currentClass:"")+(z.getTime()===R.getTime()?" ui-datepicker-today":""))+"'"+(j&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"&#39;")+"'")+(W?"":" data-handler='selectDay' data-event='click' data-month='"+z.getMonth()+"' data-year='"+z.getFullYear()+"'")+">"+(j&&!v?"&#xa0;":W?"<span class='ui-state-default'>"+z.getDate()+"</span>":"<a class='ui-state-default"+(z.getTime()===R.getTime()?" ui-state-highlight":"")+(z.getTime()===G.getTime()?" ui-state-active":"")+(j?" ui-priority-secondary":"")+"' href='#'>"+z.getDate()+"</a>")+"</td>",z.setDate(z.getDate()+1),z=this._daylightSavingAdjust(z);M+=E+"</tr>"}Z++,Z>11&&(Z=0,et++),M+="</tbody></table>"+(Q?"</div>"+(K[0]>0&&T===K[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),k+=M}_+=k}return _+=l,e._keyEvent=!1,_},_generateMonthYearHeader:function(e,t,i,s,n,a,o,r){var h,l,u,d,c,p,f,m,g=this._get(e,"changeMonth"),v=this._get(e,"changeYear"),y=this._get(e,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",_="";if(a||!g)_+="<span class='ui-datepicker-month'>"+o[t]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,_+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",u=0;12>u;u++)(!h||u>=s.getMonth())&&(!l||n.getMonth()>=u)&&(_+="<option value='"+u+"'"+(u===t?" selected='selected'":"")+">"+r[u]+"</option>");_+="</select>"}if(y||(b+=_+(!a&&g&&v?"":"&#xa0;")),!e.yearshtml)if(e.yearshtml="",a||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(d=this._get(e,"yearRange").split(":"),c=(new Date).getFullYear(),p=function(e){var t=e.match(/c[+\-].*/)?i+parseInt(e.substring(1),10):e.match(/[+\-].*/)?c+parseInt(e,10):parseInt(e,10);return isNaN(t)?c:t},f=p(d[0]),m=Math.max(f,p(d[1]||"")),f=s?Math.max(f,s.getFullYear()):f,m=n?Math.min(m,n.getFullYear()):m,e.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";m>=f;f++)e.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";e.yearshtml+="</select>",b+=e.yearshtml,e.yearshtml=null}return b+=this._get(e,"yearSuffix"),y&&(b+=(!a&&g&&v?"":"&#xa0;")+_),b+="</div>"},_adjustInstDate:function(e,t,i){var s=e.drawYear+("Y"===i?t:0),n=e.drawMonth+("M"===i?t:0),a=Math.min(e.selectedDay,this._getDaysInMonth(s,n))+("D"===i?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(s,n,a)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(e)},_restrictMinMax:function(e,t){var i=this._getMinMaxDate(e,"min"),s=this._getMinMaxDate(e,"max"),n=i&&i>t?i:t;return s&&n>s?s:n},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return null==t?[1,1]:"number"==typeof t?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return new Date(e,t,1).getDay()},_canAdjustMonth:function(e,t,i,s){var n=this._getNumberOfMonths(e),a=this._daylightSavingAdjust(new Date(i,s+(0>t?t:n[0]*n[1]),1));return 0>t&&a.setDate(this._getDaysInMonth(a.getFullYear(),a.getMonth())),this._isInRange(e,a)},_isInRange:function(e,t){var i,s,n=this._getMinMaxDate(e,"min"),a=this._getMinMaxDate(e,"max"),o=null,r=null,h=this._get(e,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),o=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(o+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||t.getTime()>=n.getTime())&&(!a||t.getTime()<=a.getTime())&&(!o||t.getFullYear()>=o)&&(!r||r>=t.getFullYear())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t="string"!=typeof t?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,i,s){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var n=t?"object"==typeof t?t:this._daylightSavingAdjust(new Date(s,i,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),n,this._getFormatConfig(e))}}),e.fn.datepicker=function(t){if(!this.length)return this;e.datepicker.initialized||(e(document).mousedown(e.datepicker._checkExternalClick),e.datepicker.initialized=!0),0===e("#"+e.datepicker._mainDivId).length&&e("body").append(e.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof t||"isDisabled"!==t&&"getDate"!==t&&"widget"!==t?"option"===t&&2===arguments.length&&"string"==typeof arguments[1]?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof t?e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this].concat(i)):e.datepicker._attachDatepicker(this,t)}):e.datepicker["_"+t+"Datepicker"].apply(e.datepicker,[this[0]].concat(i))},e.datepicker=new n,e.datepicker.initialized=!1,e.datepicker.uuid=(new Date).getTime(),e.datepicker.version="1.11.4",e.datepicker,e.widget("ui.draggable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._setHandleClassName(),this._mouseInit()},_setOption:function(e,t){this._super(e,t),"handle"===e&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(t){var i=this.options;return this._blurActiveElement(t),this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(t){this.iframeBlocks=this.document.find(t).map(function(){var t=e(this);return e("<div>").css("position","absolute").appendTo(t.parent()).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(t){var i=this.document[0];if(this.handleElement.is(t.target))try{i.activeElement&&"body"!==i.activeElement.nodeName.toLowerCase()&&e(i.activeElement).blur()}catch(s){}},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===e(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(t),this.originalPosition=this.position=this._generatePosition(t,!1),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._normalizeRightBottom(),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_refreshOffsets:function(e){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:e.pageX-this.offset.left,top:e.pageY-this.offset.top}},_mouseDrag:function(t,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1},_mouseUp:function(t){return this._unblockFrames(),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),this.handleElement.is(t.target)&&this.element.focus(),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this.handleElement.addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.handleElement.removeClass("ui-draggable-handle")},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper),n=s?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_isRootNode:function(e){return/(html|body)/i.test(e.tagName)||e===this.document[0]},_getParentOffset:function(){var t=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var e=this.element.position(),t=this._isRootNode(this.scrollParent[0]);return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+(t?0:this.scrollParent.scrollTop()),left:e.left-(parseInt(this.helper.css("left"),10)||0)+(t?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options,a=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,e(a).width()-this.helperProportions.width-this.margins.left,(e(a).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)
-},_convertPositionTo:function(e,t){t||(t=this.position);var i="absolute"===e?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:t.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:t.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(e,t){var i,s,n,a,o=this.options,r=this._isRootNode(this.scrollParent[0]),h=e.pageX,l=e.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),t&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.left<i[0]&&(h=i[0]+this.offset.click.left),e.pageY-this.offset.click.top<i[1]&&(l=i[1]+this.offset.click.top),e.pageX-this.offset.click.left>i[2]&&(h=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a),"y"===o.axis&&(h=this.originalPageX),"x"===o.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_normalizeRightBottom:function(){"y"!==this.options.axis&&"auto"!==this.helper.css("right")&&(this.helper.width(this.helper.width()),this.helper.css("right","auto")),"x"!==this.options.axis&&"auto"!==this.helper.css("bottom")&&(this.helper.height(this.helper.height()),this.helper.css("bottom","auto"))},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s,this],!0),/^(drag|start|stop)/.test(t)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i,s){var n=e.extend({},i,{item:s.element});s.sortables=[],e(s.options.connectToSortable).each(function(){var i=e(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",t,n))})},stop:function(t,i,s){var n=e.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,e.each(s.sortables,function(){var e=this;e.isOver?(e.isOver=0,s.cancelHelperRemoval=!0,e.cancelHelperRemoval=!1,e._storedCSS={position:e.placeholder.css("position"),top:e.placeholder.css("top"),left:e.placeholder.css("left")},e._mouseStop(t),e.options.helper=e.options._helper):(e.cancelHelperRemoval=!0,e._trigger("deactivate",t,n))})},drag:function(t,i,s){e.each(s.sortables,function(){var n=!1,a=this;a.positionAbs=s.positionAbs,a.helperProportions=s.helperProportions,a.offset.click=s.offset.click,a._intersectsWith(a.containerCache)&&(n=!0,e.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==a&&this._intersectsWith(this.containerCache)&&e.contains(a.element[0],this.element[0])&&(n=!1),n})),n?(a.isOver||(a.isOver=1,s._parent=i.helper.parent(),a.currentItem=i.helper.appendTo(a.element).data("ui-sortable-item",!0),a.options._helper=a.options.helper,a.options.helper=function(){return i.helper[0]},t.target=a.currentItem[0],a._mouseCapture(t,!0),a._mouseStart(t,!0,!0),a.offset.click.top=s.offset.click.top,a.offset.click.left=s.offset.click.left,a.offset.parent.left-=s.offset.parent.left-a.offset.parent.left,a.offset.parent.top-=s.offset.parent.top-a.offset.parent.top,s._trigger("toSortable",t),s.dropped=a.element,e.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,a.fromOutside=s),a.currentItem&&(a._mouseDrag(t),i.position=a.position)):a.isOver&&(a.isOver=0,a.cancelHelperRemoval=!0,a.options._revert=a.options.revert,a.options.revert=!1,a._trigger("out",t,a._uiHash(a)),a._mouseStop(t,!0),a.options.revert=a.options._revert,a.options.helper=a.options._helper,a.placeholder&&a.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(t),i.position=s._generatePosition(t,!0),s._trigger("fromSortable",t),s.dropped=!1,e.each(s.sortables,function(){this.refreshPositions()}))})}}),e.ui.plugin.add("draggable","cursor",{start:function(t,i,s){var n=e("body"),a=s.options;n.css("cursor")&&(a._cursor=n.css("cursor")),n.css("cursor",a.cursor)},stop:function(t,i,s){var n=s.options;n._cursor&&e("body").css("cursor",n._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("opacity")&&(a._opacity=n.css("opacity")),n.css("opacity",a.opacity)},stop:function(t,i,s){var n=s.options;n._opacity&&e(i.helper).css("opacity",n._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(e,t,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(t,i,s){var n=s.options,a=!1,o=s.scrollParentNotHidden[0],r=s.document[0];o!==r&&"HTML"!==o.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+o.offsetHeight-t.pageY<n.scrollSensitivity?o.scrollTop=a=o.scrollTop+n.scrollSpeed:t.pageY-s.overflowOffset.top<n.scrollSensitivity&&(o.scrollTop=a=o.scrollTop-n.scrollSpeed)),n.axis&&"y"===n.axis||(s.overflowOffset.left+o.offsetWidth-t.pageX<n.scrollSensitivity?o.scrollLeft=a=o.scrollLeft+n.scrollSpeed:t.pageX-s.overflowOffset.left<n.scrollSensitivity&&(o.scrollLeft=a=o.scrollLeft-n.scrollSpeed))):(n.axis&&"x"===n.axis||(t.pageY-e(r).scrollTop()<n.scrollSensitivity?a=e(r).scrollTop(e(r).scrollTop()-n.scrollSpeed):e(window).height()-(t.pageY-e(r).scrollTop())<n.scrollSensitivity&&(a=e(r).scrollTop(e(r).scrollTop()+n.scrollSpeed))),n.axis&&"y"===n.axis||(t.pageX-e(r).scrollLeft()<n.scrollSensitivity?a=e(r).scrollLeft(e(r).scrollLeft()-n.scrollSpeed):e(window).width()-(t.pageX-e(r).scrollLeft())<n.scrollSensitivity&&(a=e(r).scrollLeft(e(r).scrollLeft()+n.scrollSpeed)))),a!==!1&&e.ui.ddmanager&&!n.dropBehaviour&&e.ui.ddmanager.prepareOffsets(s,t)}}),e.ui.plugin.add("draggable","snap",{start:function(t,i,s){var n=s.options;s.snapElements=[],e(n.snap.constructor!==String?n.snap.items||":data(ui-draggable)":n.snap).each(function(){var t=e(this),i=t.offset();this!==s.element[0]&&s.snapElements.push({item:this,width:t.outerWidth(),height:t.outerHeight(),top:i.top,left:i.left})})},drag:function(t,i,s){var n,a,o,r,h,l,u,d,c,p,f=s.options,m=f.snapTolerance,g=i.offset.left,v=g+s.helperProportions.width,y=i.offset.top,b=y+s.helperProportions.height;for(c=s.snapElements.length-1;c>=0;c--)h=s.snapElements[c].left-s.margins.left,l=h+s.snapElements[c].width,u=s.snapElements[c].top-s.margins.top,d=u+s.snapElements[c].height,h-m>v||g>l+m||u-m>b||y>d+m||!e.contains(s.snapElements[c].item.ownerDocument,s.snapElements[c].item)?(s.snapElements[c].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(n=m>=Math.abs(u-b),a=m>=Math.abs(d-y),o=m>=Math.abs(h-v),r=m>=Math.abs(l-g),n&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||a||o||r,"outer"!==f.snapMode&&(n=m>=Math.abs(u-y),a=m>=Math.abs(d-b),o=m>=Math.abs(h-g),r=m>=Math.abs(l-v),n&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:d-s.helperProportions.height,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[c].snapping&&(n||a||o||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=n||a||o||r||p)}}),e.ui.plugin.add("draggable","stack",{start:function(t,i,s){var n,a=s.options,o=e.makeArray(e(a.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});o.length&&(n=parseInt(e(o[0]).css("zIndex"),10)||0,e(o).each(function(t){e(this).css("zIndex",n+t)}),this.css("zIndex",n+o.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i,s){var n=e(i.helper),a=s.options;n.css("zIndex")&&(a._zIndex=n.css("zIndex")),n.css("zIndex",a.zIndex)},stop:function(t,i,s){var n=s.options;n._zIndex&&e(i.helper).css("zIndex",n._zIndex)}}),e.ui.draggable,e.widget("ui.resizable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(e){return parseInt(e,10)||0},_isNumber:function(e){return!isNaN(parseInt(e,10))},_hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return t[s]>0?!0:(t[s]=1,n=t[s]>0,t[s]=0,n)},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(e("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=e(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("<div class='ui-resizable-handle "+a+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=e(this.handles[i]),this._on(this.handles[i],{mousedown:o._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var i,s,n,a=this.options,o=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),a.containment&&(i+=e(a.containment).scrollLeft()||0,s+=e(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:o.width(),height:o.height()},this.originalSize=this._helper?{width:o.outerWidth(),height:o.outerHeight()}:{width:o.width(),height:o.height()},this.sizeDiff={width:o.outerWidth()-o.width(),height:o.outerHeight()-o.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===n?this.axis+"-resize":n),o.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var i,s,n=this.originalMousePosition,a=this.axis,o=t.pageX-n.left||0,r=t.pageY-n.top||0,h=this._change[a];return this._updatePrevProperties(),h?(i=h.apply(this,[t,o,r]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var e={};return this.position.top!==this.prevPosition.top&&(e.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(e.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(e.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(e.height=this.size.height+"px"),this.helper.css(e),e},_updateVirtualBoundaries:function(e){var t,i,s,n,a,o=this.options;a={minWidth:this._isNumber(o.minWidth)?o.minWidth:0,maxWidth:this._isNumber(o.maxWidth)?o.maxWidth:1/0,minHeight:this._isNumber(o.minHeight)?o.minHeight:0,maxHeight:this._isNumber(o.maxHeight)?o.maxHeight:1/0},(this._aspectRatio||e)&&(t=a.minHeight*this.aspectRatio,s=a.minWidth/this.aspectRatio,i=a.maxHeight*this.aspectRatio,n=a.maxWidth/this.aspectRatio,t>a.minWidth&&(a.minWidth=t),s>a.minHeight&&(a.minHeight=s),a.maxWidth>i&&(a.maxWidth=i),a.maxHeight>n&&(a.maxHeight=n)),this._vBoundaries=a},_updateCache:function(e){this.offset=this.helper.offset(),this._isNumber(e.left)&&(this.position.left=e.left),this._isNumber(e.top)&&(this.position.top=e.top),this._isNumber(e.height)&&(this.size.height=e.height),this._isNumber(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,i=this.size,s=this.axis;return this._isNumber(e.height)?e.width=e.height*this.aspectRatio:this._isNumber(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===s&&(e.left=t.left+(i.width-e.width),e.top=null),"nw"===s&&(e.top=t.top+(i.height-e.height),e.left=t.left+(i.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,i=this.axis,s=this._isNumber(e.width)&&t.maxWidth&&t.maxWidth<e.width,n=this._isNumber(e.height)&&t.maxHeight&&t.maxHeight<e.height,a=this._isNumber(e.width)&&t.minWidth&&t.minWidth>e.width,o=this._isNumber(e.height)&&t.minHeight&&t.minHeight>e.height,r=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,l=/sw|nw|w/.test(i),u=/nw|ne|n/.test(i);return a&&(e.width=t.minWidth),o&&(e.height=t.minHeight),s&&(e.width=t.maxWidth),n&&(e.height=t.maxHeight),a&&l&&(e.left=r-t.minWidth),s&&l&&(e.left=r-t.maxWidth),o&&u&&(e.top=h-t.minHeight),n&&u&&(e.top=h-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_getPaddingPlusBorderDimensions:function(e){for(var t=0,i=[],s=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],n=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];4>t;t++)i[t]=parseInt(s[t],10)||0,i[t]+=parseInt(n[t],10)||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var e,t=0,i=this.helper||this.element;this._proportionallyResizeElements.length>t;t++)e=this._proportionallyResizeElements[t],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(e)),e.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var t,i,s,n,a,o,r,h=e(this).resizable("instance"),l=h.options,u=h.element,d=l.containment,c=d instanceof e?d.get(0):/parent/.test(d)?u.parent().get(0):d;c&&(h.containerElement=e(c),/document/.test(d)||d===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(t=e(c),i=[],e(["Top","Right","Left","Bottom"]).each(function(e,s){i[e]=h._num(t.css("padding"+s))}),h.containerOffset=t.offset(),h.containerPosition=t.position(),h.containerSize={height:t.innerHeight()-i[3],width:t.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,a=h.containerSize.width,o=h._hasScroll(c,"left")?c.scrollWidth:a,r=h._hasScroll(c)?c.scrollHeight:n,h.parentData={element:c,left:s.left,top:s.top,width:o,height:r}))},resize:function(t){var i,s,n,a,o=e(this).resizable("instance"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,d={top:0,left:0},c=o.containerElement,p=!0;c[0]!==document&&/static/.test(c.css("position"))&&(d=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-d.left),u&&(o.size.height=o.size.width/o.aspectRatio,p=!1),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio,p=!1),o.position.top=o._helper?h.top:0),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a?(o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top):(o.offset.left=o.element.offset().left,o.offset.top=o.element.offset().top),i=Math.abs(o.sizeDiff.width+(o._helper?o.offset.left-d.left:o.offset.left-h.left)),s=Math.abs(o.sizeDiff.height+(o._helper?o.offset.top-d.top:o.offset.top-h.top)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio,p=!1)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio,p=!1)),p||(o.position.left=o.prevPosition.left,o.position.top=o.prevPosition.top,o.size.width=o.prevSize.width,o.size.height=o.prevSize.height)},stop:function(){var t=e(this).resizable("instance"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).resizable("instance"),i=t.options;e(i.alsoResize).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})},resize:function(t,i){var s=e(this).resizable("instance"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0};e(n.alsoResize).each(function(){var t=e(this),s=e(this).data("ui-resizable-alsoresize"),n={},a=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(a,function(e,t){var i=(s[t]||0)+(r[t]||0);i&&i>=0&&(n[t]=i||null)}),t.css(n)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).resizable("instance"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t,i=e(this).resizable("instance"),s=i.options,n=i.size,a=i.originalSize,o=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,u=h[1]||1,d=Math.round((n.width-a.width)/l)*l,c=Math.round((n.height-a.height)/u)*u,p=a.width+d,f=a.height+c,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,v=s.minWidth&&s.minWidth>p,y=s.minHeight&&s.minHeight>f;s.grid=h,v&&(p+=l),y&&(f+=u),m&&(p-=l),g&&(f-=u),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=o.top-c):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=o.left-d):((0>=f-u||0>=p-l)&&(t=i._getPaddingPlusBorderDimensions(this)),f-u>0?(i.size.height=f,i.position.top=o.top-c):(f=u-t.height,i.size.height=f,i.position.top=o.top+a.height-f),p-l>0?(i.size.width=p,i.position.left=o.left-d):(p=l-t.width,i.size.width=p,i.position.left=o.left+a.width-p))}}),e.ui.resizable,e.widget("ui.dialog",{version:"1.11.4",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"Close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var i=e(this).css(t).offset().top;0>i&&e(this).css("top",t.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&e.fn.draggable&&this._makeDraggable(),this.options.resizable&&e.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var t=this.options.appendTo;return t&&(t.jquery||t.nodeType)?e(t):this.document.find(t||"body").eq(0)},_destroy:function(){var e,t=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},disable:e.noop,enable:e.noop,close:function(t){var i,s=this;if(this._isOpen&&this._trigger("beforeClose",t)!==!1){if(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),!this.opener.filter(":focusable").focus().length)try{i=this.document[0].activeElement,i&&"body"!==i.nodeName.toLowerCase()&&e(i).blur()}catch(n){}this._hide(this.uiDialog,this.options.hide,function(){s._trigger("close",t)})}},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+e(this).css("z-index")}).get(),a=Math.max.apply(null,n);return a>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",a+1),s=!0),s&&!i&&this._trigger("focus",t),s},open:function(){var t=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=e(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){t._focusTabbable(),t._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var e=this._focusedElement;e||(e=this.element.find("[autofocus]")),e.length||(e=this.element.find(":tabbable")),e.length||(e=this.uiDialogButtonPane.find(":tabbable")),e.length||(e=this.uiDialogTitlebarClose.filter(":tabbable")),e.length||(e=this.uiDialog),e.eq(0).focus()},_keepFocus:function(t){function i(){var t=this.document[0].activeElement,i=this.uiDialog[0]===t||e.contains(this.uiDialog[0],t);i||this._focusTabbable()}t.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=e("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(t){if(this.options.closeOnEscape&&!t.isDefaultPrevented()&&t.keyCode&&t.keyCode===e.ui.keyCode.ESCAPE)return t.preventDefault(),this.close(t),void 0;
-if(t.keyCode===e.ui.keyCode.TAB&&!t.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");t.target!==n[0]&&t.target!==this.uiDialog[0]||t.shiftKey?t.target!==s[0]&&t.target!==this.uiDialog[0]||!t.shiftKey||(this._delay(function(){n.focus()}),t.preventDefault()):(this._delay(function(){s.focus()}),t.preventDefault())}},mousedown:function(e){this._moveToTop(e)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var t;this.uiDialogTitlebar=e("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(t){e(t.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=e("<button type='button'></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(e){e.preventDefault(),this.close(e)}}),t=e("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(t),this.uiDialog.attr({"aria-labelledby":t.attr("id")})},_title:function(e){this.options.title||e.html("&#160;"),e.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=e("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=e("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var t=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),e.isEmptyObject(i)||e.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),void 0):(e.each(i,function(i,s){var n,a;s=e.isFunction(s)?{click:s,text:i}:s,s=e.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(t.element[0],arguments)},a={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,e("<button></button>",s).button(a).appendTo(t.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function t(e){return{position:e.position,offset:e.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){e(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,t(n))},drag:function(e,s){i._trigger("drag",e,t(s))},stop:function(n,a){var o=a.offset.left-i.document.scrollLeft(),r=a.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(o>=0?"+":"")+o+" "+"top"+(r>=0?"+":"")+r,of:i.window},e(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,t(a))}})},_makeResizable:function(){function t(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}var i=this,s=this.options,n=s.resizable,a=this.uiDialog.css("position"),o="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:o,start:function(s,n){e(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,t(n))},resize:function(e,s){i._trigger("resize",e,t(s))},stop:function(n,a){var o=i.uiDialog.offset(),r=o.left-i.document.scrollLeft(),h=o.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},e(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,t(a))}}).css("position",a)},_trackFocus:function(){this._on(this.widget(),{focusin:function(t){this._makeFocusTarget(),this._focusedElement=e(t.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var t=this._trackingInstances(),i=e.inArray(this,t);-1!==i&&t.splice(i,1)},_trackingInstances:function(){var e=this.document.data("ui-dialog-instances");return e||(e=[],this.document.data("ui-dialog-instances",e)),e},_minHeight:function(){var e=this.options;return"auto"===e.height?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(){var e=this.uiDialog.is(":visible");e||this.uiDialog.show(),this.uiDialog.position(this.options.position),e||this.uiDialog.hide()},_setOptions:function(t){var i=this,s=!1,n={};e.each(t,function(e,t){i._setOption(e,t),e in i.sizeRelatedOptions&&(s=!0),e in i.resizableRelatedOptions&&(n[e]=t)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,t){var i,s,n=this.uiDialog;"dialogClass"===e&&n.removeClass(this.options.dialogClass).addClass(t),"disabled"!==e&&(this._super(e,t),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:""+t}),"draggable"===e&&(i=n.is(":data(ui-draggable)"),i&&!t&&n.draggable("destroy"),!i&&t&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(s=n.is(":data(ui-resizable)"),s&&!t&&n.resizable("destroy"),s&&"string"==typeof t&&n.resizable("option","handles",t),s||t===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var e,t,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),e=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),t=Math.max(0,s.minHeight-e),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-e):"none","auto"===s.height?this.element.css({minHeight:t,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-e)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var t=e(this);return e("<div>").css({position:"absolute",width:t.outerWidth(),height:t.outerHeight()}).appendTo(t.parent()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(t){return e(t.target).closest(".ui-dialog").length?!0:!!e(t.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var t=!0;this._delay(function(){t=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(e){t||this._allowInteraction(e)||(e.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=e("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var e=this.document.data("ui-dialog-overlays")-1;e?this.document.data("ui-dialog-overlays",e):this.document.unbind("focusin").removeData("ui-dialog-overlays"),this.overlay.remove(),this.overlay=null}}}),e.widget("ui.droppable",{version:"1.11.4",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(s)?s:function(e){return e.is(s)},this.proportions=function(){return arguments.length?(t=arguments[0],void 0):t?t:t={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this.element.addClass("ui-droppable")},_addToManager:function(t){e.ui.ddmanager.droppables[t]=e.ui.ddmanager.droppables[t]||[],e.ui.ddmanager.droppables[t].push(this)},_splice:function(e){for(var t=0;e.length>t;t++)e[t]===this&&e.splice(t,1)},_destroy:function(){var t=e.ui.ddmanager.droppables[this.options.scope];this._splice(t),this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){if("accept"===t)this.accept=e.isFunction(i)?i:function(e){return e.is(i)};else if("scope"===t){var s=e.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(t,i)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=e(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(i,{offset:i.element.offset()}),i.options.tolerance,t)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(){function e(e,t,i){return e>=t&&t+i>e}return function(t,i,s,n){if(!i.offset)return!1;var a=(t.positionAbs||t.position.absolute).left+t.margins.left,o=(t.positionAbs||t.position.absolute).top+t.margins.top,r=a+t.helperProportions.width,h=o+t.helperProportions.height,l=i.offset.left,u=i.offset.top,d=l+i.proportions().width,c=u+i.proportions().height;switch(s){case"fit":return a>=l&&d>=r&&o>=u&&c>=h;case"intersect":return a+t.helperProportions.width/2>l&&d>r-t.helperProportions.width/2&&o+t.helperProportions.height/2>u&&c>h-t.helperProportions.height/2;case"pointer":return e(n.pageY,u,i.proportions().height)&&e(n.pageX,l,i.proportions().width);case"touch":return(o>=u&&c>=o||h>=u&&c>=h||u>o&&h>c)&&(a>=l&&d>=a||r>=l&&d>=r||l>a&&r>d);default:return!1}}}(),e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions().height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions({width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight}))}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance,i),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e(this).droppable("instance").options.scope===n}),a.length&&(s=e(a[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}},e.ui.droppable;var y="ui-effects-",b=e;e.effects={effect:{}},function(e,t){function i(e,t,i){var s=d[t.type]||{};return null==e?i||!t.def?null:t.def:(e=s.floor?~~e:parseFloat(e),isNaN(e)?t.def:s.mod?(e+s.mod)%s.mod:0>e?0:e>s.max?s.max:e)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(e,a){var o,r=a.re.exec(i),h=r&&a.parse(r),l=a.space||"rgba";return h?(o=s[l](h),s[u[l].cache]=o[u[l].cache],n=s._rgba=o._rgba,!1):t}),n.length?("0,0,0,0"===n.join()&&e.extend(n,a.transparent),s):a[i]}function n(e,t,i){return i=(i+1)%1,1>6*i?e+6*(t-e)*i:1>2*i?t:2>3*i?e+6*(t-e)*(2/3-i):e}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[e[1],e[2],e[3],e[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(e){return[2.55*e[1],2.55*e[2],2.55*e[3],e[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(e){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(e){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(e){return[e[1],e[2]/100,e[3]/100,e[4]]}}],l=e.Color=function(t,i,s,n){return new e.Color.fn.parse(t,i,s,n)},u={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},d={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},c=l.support={},p=e("<p>")[0],f=e.each;p.style.cssText="background-color:rgba(1,1,1,.5)",c.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),l.fn=e.extend(l.prototype,{parse:function(n,o,r,h){if(n===t)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=e(n).css(o),o=t);var d=this,c=e.type(n),p=this._rgba=[];return o!==t&&(n=[n,o,r,h],c="array"),"string"===c?this.parse(s(n)||a._default):"array"===c?(f(u.rgba.props,function(e,t){p[t.idx]=i(n[t.idx],t)}),this):"object"===c?(n instanceof l?f(u,function(e,t){n[t.cache]&&(d[t.cache]=n[t.cache].slice())}):f(u,function(t,s){var a=s.cache;f(s.props,function(e,t){if(!d[a]&&s.to){if("alpha"===e||null==n[e])return;d[a]=s.to(d._rgba)}d[a][t.idx]=i(n[e],t,!0)}),d[a]&&0>e.inArray(null,d[a].slice(0,3))&&(d[a][3]=1,s.from&&(d._rgba=s.from(d[a])))}),this):t},is:function(e){var i=l(e),s=!0,n=this;return f(u,function(e,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(e,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:t})),s}),s},_space:function(){var e=[],t=this;return f(u,function(i,s){t[s.cache]&&e.push(i)}),e.pop()},transition:function(e,t){var s=l(e),n=s._space(),a=u[n],o=0===this.alpha()?l("transparent"):this,r=o[a.cache]||a.to(o._rgba),h=r.slice();return s=s[a.cache],f(a.props,function(e,n){var a=n.idx,o=r[a],l=s[a],u=d[n.type]||{};null!==l&&(null===o?h[a]=l:(u.mod&&(l-o>u.mod/2?o+=u.mod:o-l>u.mod/2&&(o-=u.mod)),h[a]=i((l-o)*t+o,n)))}),this[n](h)},blend:function(t){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(t)._rgba;return l(e.map(i,function(e,t){return(1-s)*n[t]+s*e}))},toRgbaString:function(){var t="rgba(",i=e.map(this._rgba,function(e,t){return null==e?t>2?1:0:e});return 1===i[3]&&(i.pop(),t="rgb("),t+i.join()+")"},toHslaString:function(){var t="hsla(",i=e.map(this.hsla(),function(e,t){return null==e&&(e=t>2?1:0),t&&3>t&&(e=Math.round(100*e)+"%"),e});return 1===i[3]&&(i.pop(),t="hsl("),t+i.join()+")"},toHexString:function(t){var i=this._rgba.slice(),s=i.pop();return t&&i.push(~~(255*s)),"#"+e.map(i,function(e){return e=(e||0).toString(16),1===e.length?"0"+e:e}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,u.hsla.to=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t,i,s=e[0]/255,n=e[1]/255,a=e[2]/255,o=e[3],r=Math.max(s,n,a),h=Math.min(s,n,a),l=r-h,u=r+h,d=.5*u;return t=h===r?0:s===r?60*(n-a)/l+360:n===r?60*(a-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=d?l/u:l/(2-u),[Math.round(t)%360,i,d,null==o?1:o]},u.hsla.from=function(e){if(null==e[0]||null==e[1]||null==e[2])return[null,null,null,e[3]];var t=e[0]/360,i=e[1],s=e[2],a=e[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,t+1/3)),Math.round(255*n(r,o,t)),Math.round(255*n(r,o,t-1/3)),a]},f(u,function(s,n){var a=n.props,o=n.cache,h=n.to,u=n.from;l.fn[s]=function(s){if(h&&!this[o]&&(this[o]=h(this._rgba)),s===t)return this[o].slice();var n,r=e.type(s),d="array"===r||"object"===r?s:arguments,c=this[o].slice();return f(a,function(e,t){var s=d["object"===r?e:t.idx];null==s&&(s=c[t.idx]),c[t.idx]=i(s,t)}),u?(n=l(u(c)),n[o]=c,n):l(c)},f(a,function(t,i){l.fn[t]||(l.fn[t]=function(n){var a,o=e.type(n),h="alpha"===t?this._hsla?"hsla":"rgba":s,l=this[h](),u=l[i.idx];return"undefined"===o?u:("function"===o&&(n=n.call(this,u),o=e.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=u+parseFloat(a[2])*("+"===a[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(t){var i=t.split(" ");f(i,function(t,i){e.cssHooks[i]={set:function(t,n){var a,o,r="";if("transparent"!==n&&("string"!==e.type(n)||(a=s(n)))){if(n=l(a||n),!c.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?t.parentNode:t;(""===r||"transparent"===r)&&o&&o.style;)try{r=e.css(o,"backgroundColor"),o=o.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{t.style[i]=n}catch(h){}}},e.fx.step[i]=function(t){t.colorInit||(t.start=l(t.elem,i),t.end=l(t.end),t.colorInit=!0),e.cssHooks[i].set(t.elem,t.start.transition(t.end,t.pos))}})},l.hook(o),e.cssHooks.borderColor={expand:function(e){var t={};return f(["Top","Right","Bottom","Left"],function(i,s){t["border"+s+"Color"]=e}),t}},a=e.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(b),function(){function t(t){var i,s,n=t.ownerDocument.defaultView?t.ownerDocument.defaultView.getComputedStyle(t,null):t.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[e.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function i(t,i){var s,a,o={};for(s in i)a=i[s],t[s]!==a&&(n[s]||(e.fx.step[s]||!isNaN(parseFloat(a)))&&(o[s]=a));return o}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,i){e.fx.step[i]=function(e){("none"!==e.end&&!e.setAttr||1===e.pos&&!e.setAttr)&&(b.style(e.elem,i,e.end),e.setAttr=!0)}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e.effects.animateClass=function(n,a,o,r){var h=e.speed(a,o,r);return this.queue(function(){var a,o=e(this),r=o.attr("class")||"",l=h.children?o.find("*").addBack():o;l=l.map(function(){var i=e(this);return{el:i,start:t(this)}}),a=function(){e.each(s,function(e,t){n[t]&&o[t+"Class"](n[t])})},a(),l=l.map(function(){return this.end=t(this.el[0]),this.diff=i(this.start,this.end),this}),o.attr("class",r),l=l.map(function(){var t=this,i=e.Deferred(),s=e.extend({},h,{queue:!1,complete:function(){i.resolve(t)}});return this.el.animate(this.diff,s),i.promise()}),e.when.apply(e,l.get()).done(function(){a(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),h.complete.call(o[0])})})},e.fn.extend({addClass:function(t){return function(i,s,n,a){return s?e.effects.animateClass.call(this,{add:i},s,n,a):t.apply(this,arguments)}}(e.fn.addClass),removeClass:function(t){return function(i,s,n,a){return arguments.length>1?e.effects.animateClass.call(this,{remove:i},s,n,a):t.apply(this,arguments)}}(e.fn.removeClass),toggleClass:function(t){return function(i,s,n,a,o){return"boolean"==typeof s||void 0===s?n?e.effects.animateClass.call(this,s?{add:i}:{remove:i},n,a,o):t.apply(this,arguments):e.effects.animateClass.call(this,{toggle:i},s,n,a)}}(e.fn.toggleClass),switchClass:function(t,i,s,n,a){return e.effects.animateClass.call(this,{add:i,remove:t},s,n,a)}})}(),function(){function t(t,i,s,n){return e.isPlainObject(t)&&(i=t,t=t.effect),t={effect:t},null==i&&(i={}),e.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||e.fx.speeds[i])&&(n=s,s=i,i={}),e.isFunction(s)&&(n=s,s=null),i&&e.extend(t,i),s=s||i.duration,t.duration=e.fx.off?0:"number"==typeof s?s:s in e.fx.speeds?e.fx.speeds[s]:e.fx.speeds._default,t.complete=n||i.complete,t}function i(t){return!t||"number"==typeof t||e.fx.speeds[t]?!0:"string"!=typeof t||e.effects.effect[t]?e.isFunction(t)?!0:"object"!=typeof t||t.effect?!1:!0:!0}e.extend(e.effects,{version:"1.11.4",save:function(e,t){for(var i=0;t.length>i;i++)null!==t[i]&&e.data(y+t[i],e[0].style[t[i]])},restore:function(e,t){var i,s;for(s=0;t.length>s;s++)null!==t[s]&&(i=e.data(y+t[s]),void 0===i&&(i=""),e.css(t[s],i))},setMode:function(e,t){return"toggle"===t&&(t=e.is(":hidden")?"show":"hide"),t},getBaseline:function(e,t){var i,s;switch(e[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=e[0]/t.height}switch(e[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=e[1]/t.width}return{x:s,y:i}},createWrapper:function(t){if(t.parent().is(".ui-effects-wrapper"))return t.parent();var i={width:t.outerWidth(!0),height:t.outerHeight(!0),"float":t.css("float")},s=e("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:t.width(),height:t.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return t.wrap(s),(t[0]===a||e.contains(t[0],a))&&e(a).focus(),s=t.parent(),"static"===t.css("position")?(s.css({position:"relative"}),t.css({position:"relative"})):(e.extend(i,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,s){i[s]=t.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(n),s.css(i).show()},removeWrapper:function(t){var i=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===i||e.contains(t[0],i))&&e(i).focus()),t},setTransition:function(t,i,s,n){return n=n||{},e.each(i,function(e,i){var a=t.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),e.fn.extend({effect:function(){function i(t){function i(){e.isFunction(a)&&a.call(n[0]),e.isFunction(t)&&t()}var n=e(this),a=s.complete,r=s.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),i()):o.call(n[0],s,i)}var s=t.apply(this,arguments),n=s.mode,a=s.queue,o=e.effects.effect[s.effect];return e.fx.off||!o?n?this[n](s.duration,s.complete):this.each(function(){s.complete&&s.complete.call(this)}):a===!1?this.each(i):this.queue(a||"fx",i)},show:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="show",this.effect.call(this,n)}}(e.fn.show),hide:function(e){return function(s){if(i(s))return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(e.fn.hide),toggle:function(e){return function(s){if(i(s)||"boolean"==typeof s)return e.apply(this,arguments);var n=t.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(e.fn.toggle),cssUnit:function(t){var i=this.css(t),s=[];return e.each(["em","px","%","pt"],function(e,t){i.indexOf(t)>0&&(s=[parseFloat(i),t])}),s}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,i){t[i]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return 0===e||1===e?e:-Math.pow(2,8*(e-1))*Math.sin((80*(e-1)-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){for(var t,i=4;((t=Math.pow(2,--i))-1)/11>e;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*t-2)/22-e,2)}}),e.each(t,function(t,i){e.easing["easeIn"+t]=i,e.easing["easeOut"+t]=function(e){return 1-i(1-e)},e.easing["easeInOut"+t]=function(e){return.5>e?i(2*e)/2:1-i(-2*e+2)/2}})}(),e.effects,e.effects.effect.blind=function(t,i){var s,n,a,o=e(this),r=/up|down|vertical/,h=/up|left|vertical|horizontal/,l=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(o,t.mode||"hide"),d=t.direction||"up",c=r.test(d),p=c?"height":"width",f=c?"top":"left",m=h.test(d),g={},v="show"===u;o.parent().is(".ui-effects-wrapper")?e.effects.save(o.parent(),l):e.effects.save(o,l),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n=s[p](),a=parseFloat(s.css(f))||0,g[p]=v?n:0,m||(o.css(c?"bottom":"right",0).css(c?"top":"left","auto").css({position:"absolute"}),g[f]=v?a:n+a),v&&(s.css(p,0),m||s.css(f,a+n)),s.animate(g,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){"hide"===u&&o.hide(),e.effects.restore(o,l),e.effects.removeWrapper(o),i()}})},e.effects.effect.bounce=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"effect"),l="hide"===h,u="show"===h,d=t.direction||"up",c=t.distance,p=t.times||5,f=2*p+(u||l?1:0),m=t.duration/f,g=t.easing,v="up"===d||"down"===d?"top":"left",y="up"===d||"left"===d,b=o.queue(),_=b.length;for((u||l)&&r.push("opacity"),e.effects.save(o,r),o.show(),e.effects.createWrapper(o),c||(c=o["top"===v?"outerHeight":"outerWidth"]()/3),u&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,y?2*-c:2*c).animate(a,m,g)),l&&(c/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g).animate(a,m,g),c=l?2*c:c/2;l&&(n={opacity:0},n[v]=(y?"-=":"+=")+c,o.animate(n,m,g)),o.queue(function(){l&&o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}),_>1&&b.splice.apply(b,[1,0].concat(b.splice(_,f+1))),o.dequeue()},e.effects.effect.clip=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","height","width"],h=e.effects.setMode(o,t.mode||"hide"),l="show"===h,u=t.direction||"vertical",d="vertical"===u,c=d?"height":"width",p=d?"top":"left",f={};e.effects.save(o,r),o.show(),s=e.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[c](),l&&(n.css(c,0),n.css(p,a/2)),f[c]=l?a:0,f[p]=l?0:a/2,n.animate(f,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){l||o.hide(),e.effects.restore(o,r),e.effects.removeWrapper(o),i()}})},e.effects.effect.drop=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","opacity","height","width"],o=e.effects.setMode(n,t.mode||"hide"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h?"pos":"neg",d={opacity:r?1:0};e.effects.save(n,a),n.show(),e.effects.createWrapper(n),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===u?-s:s),d[l]=(r?"pos"===u?"+=":"-=":"pos"===u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.explode=function(t,i){function s(){b.push(this),b.length===d*c&&n()}function n(){p.css({visibility:"visible"}),e(b).remove(),m||p.hide(),i()}var a,o,r,h,l,u,d=t.pieces?Math.round(Math.sqrt(t.pieces)):3,c=d,p=e(this),f=e.effects.setMode(p,t.mode||"hide"),m="show"===f,g=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/c),y=Math.ceil(p.outerHeight()/d),b=[];for(a=0;d>a;a++)for(h=g.top+a*y,u=a-(d-1)/2,o=0;c>o;o++)r=g.left+o*v,l=o-(c-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*y}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:y,left:r+(m?l*v:0),top:h+(m?u*y:0),opacity:m?0:1}).animate({left:r+(m?0:l*v),top:h+(m?0:u*y),opacity:m?1:0},t.duration||500,t.easing,s)},e.effects.effect.fade=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:t.duration,easing:t.easing,complete:i})},e.effects.effect.fold=function(t,i){var s,n,a=e(this),o=["position","top","bottom","left","right","height","width"],r=e.effects.setMode(a,t.mode||"hide"),h="show"===r,l="hide"===r,u=t.size||15,d=/([0-9]+)%/.exec(u),c=!!t.horizFirst,p=h!==c,f=p?["width","height"]:["height","width"],m=t.duration/2,g={},v={};e.effects.save(a,o),a.show(),s=e.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],d&&(u=parseInt(d[1],10)/100*n[l?0:1]),h&&s.css(c?{height:0,width:u}:{height:u,width:0}),g[f[0]]=h?n[0]:u,v[f[1]]=h?n[1]:0,s.animate(g,m,t.easing).animate(v,m,t.easing,function(){l&&a.hide(),e.effects.restore(a,o),e.effects.removeWrapper(a),i()})},e.effects.effect.highlight=function(t,i){var s=e(this),n=["backgroundImage","backgroundColor","opacity"],a=e.effects.setMode(s,t.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),e.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===a&&s.hide(),e.effects.restore(s,n),i()}})},e.effects.effect.size=function(t,i){var s,n,a,o=e(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],u=["fontSize"],d=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],c=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),f=t.restore||"effect"!==p,m=t.scale||"both",g=t.origin||["middle","center"],v=o.css("position"),y=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===t.mode&&"show"===p?(o.from=t.to||b,o.to=t.from||s):(o.from=t.from||("show"===p?b:s),o.to=t.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===m||"both"===m)&&(a.from.y!==a.to.y&&(y=y.concat(d),o.from=e.effects.setTransition(o,d,a.from.y,o.from),o.to=e.effects.setTransition(o,d,a.to.y,o.to)),a.from.x!==a.to.x&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,a.from.x,o.from),o.to=e.effects.setTransition(o,c,a.to.x,o.to))),("content"===m||"both"===m)&&a.from.y!==a.to.y&&(y=y.concat(u).concat(l),o.from=e.effects.setTransition(o,u,a.from.y,o.from),o.to=e.effects.setTransition(o,u,a.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),g&&(n=e.effects.getBaseline(g,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===m||"both"===m)&&(d=d.concat(["marginTop","marginBottom"]).concat(u),c=c.concat(["marginLeft","marginRight"]),l=r.concat(d).concat(c),o.find("*[width]").each(function(){var i=e(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};
-f&&e.effects.save(i,l),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=e.effects.setTransition(i,d,a.from.y,i.from),i.to=e.effects.setTransition(i,d,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=e.effects.setTransition(i,c,a.from.x,i.from),i.to=e.effects.setTransition(i,c,a.to.x,i.to)),i.css(i.from),i.animate(i.to,t.duration,t.easing,function(){f&&e.effects.restore(i,l)})})),o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),e.effects.restore(o,y),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,i){var s=parseInt(i,10),n=e?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),e.effects.removeWrapper(o),i()}})},e.effects.effect.scale=function(t,i){var s=e(this),n=e.extend(!0,{},t),a=e.effects.setMode(s,t.mode||"effect"),o=parseInt(t.percent,10)||(0===parseInt(t.percent,10)?0:"hide"===a?0:100),r=t.direction||"both",h=t.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},u={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=h||["middle","center"],n.restore=!0),n.from=t.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*u.y,width:l.width*u.x,outerHeight:l.outerHeight*u.y,outerWidth:l.outerWidth*u.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},e.effects.effect.puff=function(t,i){var s=e(this),n=e.effects.setMode(s,t.mode||"hide"),a="hide"===n,o=parseInt(t.percent,10)||150,r=o/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(t)},e.effects.effect.pulsate=function(t,i){var s,n=e(this),a=e.effects.setMode(n,t.mode||"show"),o="show"===a,r="hide"===a,h=o||"hide"===a,l=2*(t.times||5)+(h?1:0),u=t.duration/l,d=0,c=n.queue(),p=c.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),d=1),s=1;l>s;s++)n.animate({opacity:d},u,t.easing),d=1-d;n.animate({opacity:d},u,t.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&c.splice.apply(c,[1,0].concat(c.splice(p,l+1))),n.dequeue()},e.effects.effect.shake=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","height","width"],o=e.effects.setMode(n,t.mode||"effect"),r=t.direction||"left",h=t.distance||20,l=t.times||3,u=2*l+1,d=Math.round(t.duration/u),c="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},m={},g={},v=n.queue(),y=v.length;for(e.effects.save(n,a),n.show(),e.effects.createWrapper(n),f[c]=(p?"-=":"+=")+h,m[c]=(p?"+=":"-=")+2*h,g[c]=(p?"-=":"+=")+2*h,n.animate(f,d,t.easing),s=1;l>s;s++)n.animate(m,d,t.easing).animate(g,d,t.easing);n.animate(m,d,t.easing).animate(f,d/2,t.easing).queue(function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}),y>1&&v.splice.apply(v,[1,0].concat(v.splice(y,u+1))),n.dequeue()},e.effects.effect.slide=function(t,i){var s,n=e(this),a=["position","top","bottom","left","right","width","height"],o=e.effects.setMode(n,t.mode||"show"),r="show"===o,h=t.direction||"left",l="up"===h||"down"===h?"top":"left",u="up"===h||"left"===h,d={};e.effects.save(n,a),n.show(),s=t.distance||n["top"===l?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,u?isNaN(s)?"-"+s:-s:s),d[l]=(r?u?"+=":"-=":u?"-=":"+=")+s,n.animate(d,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){"hide"===o&&n.hide(),e.effects.restore(n,a),e.effects.removeWrapper(n),i()}})},e.effects.effect.transfer=function(t,i){var s=e(this),n=e(t.to),a="fixed"===n.css("position"),o=e("body"),r=a?o.scrollTop():0,h=a?o.scrollLeft():0,l=n.offset(),u={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},d=s.offset(),c=e("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(t.className).css({top:d.top-r,left:d.left-h,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(u,t.duration,t.easing,function(){c.remove(),i()})},e.widget("ui.progressbar",{version:"1.11.4",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=e("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return void 0===e?this.options.value:(this.options.value=this._constrainedValue(e),this._refreshValue(),void 0)},_constrainedValue:function(e){return void 0===e&&(e=this.options.value),this.indeterminate=e===!1,"number"!=typeof e&&(e=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,e))},_setOptions:function(e){var t=e.value;delete e.value,this._super(e),this.options.value=this._constrainedValue(t),this._refreshValue()},_setOption:function(e,t){"max"===e&&(t=Math.max(this.min,t)),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var t=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||t>this.min).toggleClass("ui-corner-right",t===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=e("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":t}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==t&&(this.oldValue=t,this._trigger("change")),t===this.options.max&&this._trigger("complete")}}),e.widget("ui.selectable",e.ui.mouse,{version:"1.11.4",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}}),e.widget("ui.selectmenu",{version:"1.11.4",defaultElement:"<select>",options:{appendTo:null,disabled:null,icons:{button:"ui-icon-triangle-1-s"},position:{my:"left top",at:"left bottom",collision:"none"},width:null,change:null,close:null,focus:null,open:null,select:null},_create:function(){var e=this.element.uniqueId().attr("id");this.ids={element:e,button:e+"-button",menu:e+"-menu"},this._drawButton(),this._drawMenu(),this.options.disabled&&this.disable()},_drawButton:function(){var t=this;this.label=e("label[for='"+this.ids.element+"']").attr("for",this.ids.button),this._on(this.label,{click:function(e){this.button.focus(),e.preventDefault()}}),this.element.hide(),this.button=e("<span>",{"class":"ui-selectmenu-button ui-widget ui-state-default ui-corner-all",tabindex:this.options.disabled?-1:0,id:this.ids.button,role:"combobox","aria-expanded":"false","aria-autocomplete":"list","aria-owns":this.ids.menu,"aria-haspopup":"true"}).insertAfter(this.element),e("<span>",{"class":"ui-icon "+this.options.icons.button}).prependTo(this.button),this.buttonText=e("<span>",{"class":"ui-selectmenu-text"}).appendTo(this.button),this._setText(this.buttonText,this.element.find("option:selected").text()),this._resizeButton(),this._on(this.button,this._buttonEvents),this.button.one("focusin",function(){t.menuItems||t._refreshMenu()}),this._hoverable(this.button),this._focusable(this.button)},_drawMenu:function(){var t=this;this.menu=e("<ul>",{"aria-hidden":"true","aria-labelledby":this.ids.button,id:this.ids.menu}),this.menuWrap=e("<div>",{"class":"ui-selectmenu-menu ui-front"}).append(this.menu).appendTo(this._appendTo()),this.menuInstance=this.menu.menu({role:"listbox",select:function(e,i){e.preventDefault(),t._setSelection(),t._select(i.item.data("ui-selectmenu-item"),e)},focus:function(e,i){var s=i.item.data("ui-selectmenu-item");null!=t.focusIndex&&s.index!==t.focusIndex&&(t._trigger("focus",e,{item:s}),t.isOpen||t._select(s,e)),t.focusIndex=s.index,t.button.attr("aria-activedescendant",t.menuItems.eq(s.index).attr("id"))}}).menu("instance"),this.menu.addClass("ui-corner-bottom").removeClass("ui-corner-all"),this.menuInstance._off(this.menu,"mouseleave"),this.menuInstance._closeOnDocumentClick=function(){return!1},this.menuInstance._isDivider=function(){return!1}},refresh:function(){this._refreshMenu(),this._setText(this.buttonText,this._getSelectedItem().text()),this.options.width||this._resizeButton()},_refreshMenu:function(){this.menu.empty();var e,t=this.element.find("option");t.length&&(this._parseOptions(t),this._renderMenu(this.menu,this.items),this.menuInstance.refresh(),this.menuItems=this.menu.find("li").not(".ui-selectmenu-optgroup"),e=this._getSelectedItem(),this.menuInstance.focus(null,e),this._setAria(e.data("ui-selectmenu-item")),this._setOption("disabled",this.element.prop("disabled")))},open:function(e){this.options.disabled||(this.menuItems?(this.menu.find(".ui-state-focus").removeClass("ui-state-focus"),this.menuInstance.focus(null,this._getSelectedItem())):this._refreshMenu(),this.isOpen=!0,this._toggleAttr(),this._resizeMenu(),this._position(),this._on(this.document,this._documentClick),this._trigger("open",e))},_position:function(){this.menuWrap.position(e.extend({of:this.button},this.options.position))},close:function(e){this.isOpen&&(this.isOpen=!1,this._toggleAttr(),this.range=null,this._off(this.document),this._trigger("close",e))},widget:function(){return this.button},menuWidget:function(){return this.menu},_renderMenu:function(t,i){var s=this,n="";e.each(i,function(i,a){a.optgroup!==n&&(e("<li>",{"class":"ui-selectmenu-optgroup ui-menu-divider"+(a.element.parent("optgroup").prop("disabled")?" ui-state-disabled":""),text:a.optgroup}).appendTo(t),n=a.optgroup),s._renderItemData(t,a)})},_renderItemData:function(e,t){return this._renderItem(e,t).data("ui-selectmenu-item",t)},_renderItem:function(t,i){var s=e("<li>");return i.disabled&&s.addClass("ui-state-disabled"),this._setText(s,i.label),s.appendTo(t)},_setText:function(e,t){t?e.text(t):e.html("&#160;")},_move:function(e,t){var i,s,n=".ui-menu-item";this.isOpen?i=this.menuItems.eq(this.focusIndex):(i=this.menuItems.eq(this.element[0].selectedIndex),n+=":not(.ui-state-disabled)"),s="first"===e||"last"===e?i["first"===e?"prevAll":"nextAll"](n).eq(-1):i[e+"All"](n).eq(0),s.length&&this.menuInstance.focus(t,s)},_getSelectedItem:function(){return this.menuItems.eq(this.element[0].selectedIndex)},_toggle:function(e){this[this.isOpen?"close":"open"](e)},_setSelection:function(){var e;this.range&&(window.getSelection?(e=window.getSelection(),e.removeAllRanges(),e.addRange(this.range)):this.range.select(),this.button.focus())},_documentClick:{mousedown:function(t){this.isOpen&&(e(t.target).closest(".ui-selectmenu-menu, #"+this.ids.button).length||this.close(t))}},_buttonEvents:{mousedown:function(){var e;window.getSelection?(e=window.getSelection(),e.rangeCount&&(this.range=e.getRangeAt(0))):this.range=document.selection.createRange()},click:function(e){this._setSelection(),this._toggle(e)},keydown:function(t){var i=!0;switch(t.keyCode){case e.ui.keyCode.TAB:case e.ui.keyCode.ESCAPE:this.close(t),i=!1;break;case e.ui.keyCode.ENTER:this.isOpen&&this._selectFocusedItem(t);break;case e.ui.keyCode.UP:t.altKey?this._toggle(t):this._move("prev",t);break;case e.ui.keyCode.DOWN:t.altKey?this._toggle(t):this._move("next",t);break;case e.ui.keyCode.SPACE:this.isOpen?this._selectFocusedItem(t):this._toggle(t);break;case e.ui.keyCode.LEFT:this._move("prev",t);break;case e.ui.keyCode.RIGHT:this._move("next",t);break;case e.ui.keyCode.HOME:case e.ui.keyCode.PAGE_UP:this._move("first",t);break;case e.ui.keyCode.END:case e.ui.keyCode.PAGE_DOWN:this._move("last",t);break;default:this.menu.trigger(t),i=!1}i&&t.preventDefault()}},_selectFocusedItem:function(e){var t=this.menuItems.eq(this.focusIndex);t.hasClass("ui-state-disabled")||this._select(t.data("ui-selectmenu-item"),e)},_select:function(e,t){var i=this.element[0].selectedIndex;this.element[0].selectedIndex=e.index,this._setText(this.buttonText,e.label),this._setAria(e),this._trigger("select",t,{item:e}),e.index!==i&&this._trigger("change",t,{item:e}),this.close(t)},_setAria:function(e){var t=this.menuItems.eq(e.index).attr("id");this.button.attr({"aria-labelledby":t,"aria-activedescendant":t}),this.menu.attr("aria-activedescendant",t)},_setOption:function(e,t){"icons"===e&&this.button.find("span.ui-icon").removeClass(this.options.icons.button).addClass(t.button),this._super(e,t),"appendTo"===e&&this.menuWrap.appendTo(this._appendTo()),"disabled"===e&&(this.menuInstance.option("disabled",t),this.button.toggleClass("ui-state-disabled",t).attr("aria-disabled",t),this.element.prop("disabled",t),t?(this.button.attr("tabindex",-1),this.close()):this.button.attr("tabindex",0)),"width"===e&&this._resizeButton()},_appendTo:function(){var t=this.options.appendTo;return t&&(t=t.jquery||t.nodeType?e(t):this.document.find(t).eq(0)),t&&t[0]||(t=this.element.closest(".ui-front")),t.length||(t=this.document[0].body),t},_toggleAttr:function(){this.button.toggleClass("ui-corner-top",this.isOpen).toggleClass("ui-corner-all",!this.isOpen).attr("aria-expanded",this.isOpen),this.menuWrap.toggleClass("ui-selectmenu-open",this.isOpen),this.menu.attr("aria-hidden",!this.isOpen)},_resizeButton:function(){var e=this.options.width;e||(e=this.element.show().outerWidth(),this.element.hide()),this.button.outerWidth(e)},_resizeMenu:function(){this.menu.outerWidth(Math.max(this.button.outerWidth(),this.menu.width("").outerWidth()+1))},_getCreateOptions:function(){return{disabled:this.element.prop("disabled")}},_parseOptions:function(t){var i=[];t.each(function(t,s){var n=e(s),a=n.parent("optgroup");i.push({element:n,index:t,value:n.val(),label:n.text(),optgroup:a.attr("label")||"",disabled:a.prop("disabled")||n.prop("disabled")})}),this.items=i},_destroy:function(){this.menuWrap.remove(),this.button.remove(),this.element.show(),this.element.removeUniqueId(),this.label.attr("for",this.ids.element)}}),e.widget("ui.slider",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},numPages:5,_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this._calculateNewMax(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var t,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),a="<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",o=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),t=n.length;i>t;t++)o.push(a);this.handles=n.add(e(o.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(t){e(this).data("ui-slider-handle-index",t)})},_createRange:function(){var t=this.options,i="";t.range?(t.range===!0&&(t.values?t.values.length&&2!==t.values.length?t.values=[t.values[0],t.values[0]]:e.isArray(t.values)&&(t.values=t.values.slice(0)):t.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=e("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===t.range||"max"===t.range?" ui-slider-range-"+t.range:""))):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){this._off(this.handles),this._on(this.handles,this._handleEvents),this._hoverable(this.handles),this._focusable(this.handles)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(t){var i,s,n,a,o,r,h,l,u=this,d=this.options;return d.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:t.pageX,y:t.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(t){var i=Math.abs(s-u.values(t));(n>i||n===i&&(t===u._lastChangedValue||u.values(t)===d.min))&&(n=i,a=e(this),o=t)}),r=this._start(t,o),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,a.addClass("ui-state-active").focus(),h=a.offset(),l=!e(t.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:t.pageX-h.left-a.width()/2,top:t.pageY-h.top-a.height()/2-(parseInt(a.css("borderTopWidth"),10)||0)-(parseInt(a.css("borderBottomWidth"),10)||0)+(parseInt(a.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,o,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},i=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,i),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,i,s,n,a;return"horizontal"===this.orientation?(t=this.elementSize.width,i=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,i=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/t,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),a=this._valueMin()+s*n,this._trimAlignValue(a)},_start:function(e,t){var i={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("start",e,i)},_slide:function(e,t,i){var s,n,a;this.options.values&&this.options.values.length?(s=this.values(t?0:1),2===this.options.values.length&&this.options.range===!0&&(0===t&&i>s||1===t&&s>i)&&(i=s),i!==this.values(t)&&(n=this.values(),n[t]=i,a=this._trigger("slide",e,{handle:this.handles[t],value:i,values:n}),s=this.values(t?0:1),a!==!1&&this.values(t,i))):i!==this.value()&&(a=this._trigger("slide",e,{handle:this.handles[t],value:i}),a!==!1&&this.value(i))},_stop:function(e,t){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("stop",e,i)},_change:function(e,t){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._lastChangedValue=t,this._trigger("change",e,i)}},value:function(e){return arguments.length?(this.options.value=this._trimAlignValue(e),this._refreshValue(),this._change(null,0),void 0):this._value()},values:function(t,i){var s,n,a;if(arguments.length>1)return this.options.values[t]=this._trimAlignValue(i),this._refreshValue(),this._change(null,t),void 0;if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();for(s=this.options.values,n=arguments[0],a=0;s.length>a;a+=1)s[a]=this._trimAlignValue(n[a]),this._change(null,a);this._refreshValue()},_setOption:function(t,i){var s,n=0;switch("range"===t&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),e.isArray(this.options.values)&&(n=this.options.values.length),"disabled"===t&&this.element.toggleClass("ui-state-disabled",!!i),this._super(t,i),t){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue(),this.handles.css("horizontal"===i?"bottom":"left","");break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"step":case"min":case"max":this._animateOff=!0,this._calculateNewMax(),this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var e=this.options.value;return e=this._trimAlignValue(e)},_values:function(e){var t,i,s;if(arguments.length)return t=this.options.values[e],t=this._trimAlignValue(t);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(e){if(this._valueMin()>=e)return this._valueMin();if(e>=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,i=(e-this._valueMin())%t,s=e-i;return 2*Math.abs(i)>=t&&(s+=i>0?t:-t),parseFloat(s.toFixed(5))},_calculateNewMax:function(){var e=this.options.max,t=this._valueMin(),i=this.options.step,s=Math.floor(+(e-t).toFixed(this._precision())/i)*i;e=s+t,this.max=parseFloat(e.toFixed(this._precision()))},_precision:function(){var e=this._precisionOf(this.options.step);return null!==this.options.min&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=""+e,i=t.indexOf(".");return-1===i?0:t.length-i-1},_valueMin:function(){return this.options.min},_valueMax:function(){return this.max},_refreshValue:function(){var t,i,s,n,a,o=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,u={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),u["horizontal"===h.orientation?"left":"bottom"]=i+"%",e(this).stop(1,1)[l?"animate":"css"](u,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-t+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-t+"%"},{queue:!1,duration:r.animate}))),t=i}):(s=this.value(),n=this._valueMin(),a=this._valueMax(),i=a!==n?100*((s-n)/(a-n)):0,u["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](u,r.animate),"min"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===o&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===o&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(t){var i,s,n,a,o=e(t.target).data("ui-slider-handle-index");switch(t.keyCode){case e.ui.keyCode.HOME:case e.ui.keyCode.END:case e.ui.keyCode.PAGE_UP:case e.ui.keyCode.PAGE_DOWN:case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(t.preventDefault(),!this._keySliding&&(this._keySliding=!0,e(t.target).addClass("ui-state-active"),i=this._start(t,o),i===!1))return}switch(a=this.options.step,s=n=this.options.values&&this.options.values.length?this.values(o):this.value(),t.keyCode){case e.ui.keyCode.HOME:n=this._valueMin();break;case e.ui.keyCode.END:n=this._valueMax();break;case e.ui.keyCode.PAGE_UP:n=this._trimAlignValue(s+(this._valueMax()-this._valueMin())/this.numPages);break;case e.ui.keyCode.PAGE_DOWN:n=this._trimAlignValue(s-(this._valueMax()-this._valueMin())/this.numPages);break;case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:if(s===this._valueMax())return;n=this._trimAlignValue(s+a);break;case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(s===this._valueMin())return;n=this._trimAlignValue(s-a)}this._slide(t,o,n)},keyup:function(t){var i=e(t.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(t,i),this._change(t,i),e(t.target).removeClass("ui-state-active"))}}}),e.widget("ui.sortable",e.ui.mouse,{version:"1.11.4",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(e,t,i){return e>=t&&t+i>e},_isFloating:function(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))},_create:function(){this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(e,t){this._super(e,t),"handle"===e&&this._setHandleClassName()},_setHandleClassName:function(){this.element.find(".ui-sortable-handle").removeClass("ui-sortable-handle"),e.each(this.items,function(){(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item).addClass("ui-sortable-handle")})},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").find(".ui-sortable-handle").removeClass("ui-sortable-handle"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(t,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,a.widgetName+"-item")===a?(s=e(this),!1):void 0}),e.data(t.target,a.widgetName+"-item")===a&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=e("<style>*{ cursor: "+o.cursor+" !important; }</style>").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",t,this._uiHash(this));
-return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY<o.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+o.scrollSpeed:t.pageY-this.overflowOffset.top<o.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-o.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-t.pageX<o.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+o.scrollSpeed:t.pageX-this.overflowOffset.left<o.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-o.scrollSpeed)):(t.pageY-this.document.scrollTop()<o.scrollSensitivity?r=this.document.scrollTop(this.document.scrollTop()-o.scrollSpeed):this.window.height()-(t.pageY-this.document.scrollTop())<o.scrollSensitivity&&(r=this.document.scrollTop(this.document.scrollTop()+o.scrollSpeed)),t.pageX-this.document.scrollLeft()<o.scrollSensitivity?r=this.document.scrollLeft(this.document.scrollLeft()-o.scrollSpeed):this.window.width()-(t.pageX-this.document.scrollLeft())<o.scrollSensitivity&&(r=this.document.scrollLeft(this.document.scrollLeft()+o.scrollSpeed))),r!==!1&&e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!e.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=e.left,o=a+e.width,r=e.top,h=r+e.height,l=this.offset.click.top,u=this.offset.click.left,d="x"===this.options.axis||s+l>r&&h>s+l,c="y"===this.options.axis||t+u>a&&o>t+u,p=d&&c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(e){var t="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top,e.height),i="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left,e.width),s=t&&i,n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return s?this.floating?a&&"right"===a||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var t=this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&t||"up"===s&&!t)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){function i(){r.push(this)}var s,n,a,o,r=[],h=[],l=this._connectWith();if(l&&t)for(s=l.length-1;s>=0;s--)for(a=e(l[s],this.document[0]),n=a.length-1;n>=0;n--)o=e.data(a[n],this.widgetFullName),o&&o!==this&&!o.options.disabled&&h.push([e.isFunction(o.options.items)?o.options.items.call(o.element):e(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(h.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,u=this.items,d=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],c=this._connectWith();if(c&&this.ready)for(i=c.length-1;i>=0;i--)for(n=e(c[i],this.document[0]),s=n.length-1;s>=0;s--)a=e.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(d.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a));for(i=d.length-1;i>=0;i--)for(o=d[i][1],r=d[i][0],s=0,l=r.length;l>s;s++)h=e(r[s]),h.data(this.widgetName+"-item",o),u.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),n=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tbody"===s?t._createTrPlaceholder(t.currentItem.find("tr").eq(0),e("<tr>",t.document[0]).appendTo(n)):"tr"===s?t._createTrPlaceholder(t.currentItem,n):"img"===s&&n.attr("src",t.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(e,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_createTrPlaceholder:function(t,i){var s=this;t.children().each(function(){e("<td>&#160;</td>",s.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(t){var i,s,n,a,o,r,h,l,u,d,c=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!e.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(c&&e.contains(this.containers[i].element[0],c.element[0]))continue;c=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0);if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,a=null,u=c.floating||this._isFloating(this.currentItem),o=u?"left":"top",r=u?"width":"height",d=u?"clientX":"clientY",s=this.items.length-1;s>=0;s--)e.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[o],l=!1,t[d]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(t[d]-h)&&(n=Math.abs(t[d]-h),a=this.items[s],this.direction=l?"up":"down"));if(!a&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;a?this._rearrange(t,a,null,!0):this._rearrange(t,null,this.containers[p].element,!0),this._trigger("change",t,this._uiHash()),this.containers[p]._trigger("change",t,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.width():this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(t=e(n.containment)[0],i=e(n.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(t){var i,s,n=this.options,a=t.pageX,o=t.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.left<this.containment[0]&&(a=this.containment[0]+this.offset.click.left),t.pageY-this.offset.click.top<this.containment[1]&&(o=this.containment[1]+this.offset.click.top),t.pageX-this.offset.click.left>this.containment[2]&&(a=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){function i(e,t,i){return function(s){i._trigger(e,s,t._uiHash(t))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&n.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||n.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(n.push(function(e){this._trigger("remove",e,this._uiHash())}),n.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)t||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!t){for(s=0;n.length>s;s++)n[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}}),e.widget("ui.spinner",{version:"1.11.4",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},i=this.element;return e.each(["min","max","step"],function(e,s){var n=i.attr(s);void 0!==n&&n.length&&(t[s]=n)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e),void 0)},mousewheel:function(e,t){if(t){if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()}},"mousedown .ui-spinner-button":function(t){function i(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(t)!==!1&&this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){return e(t.currentTarget).hasClass("ui-state-active")?this._start(t)===!1?!1:(this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*e.height())&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var i=this.options,s=e.ui.keyCode;switch(t.keyCode){case s.UP:return this._repeat(null,1,t),!0;case s.DOWN:return this._repeat(null,-1,t),!0;case s.PAGE_UP:return this._repeat(null,i.page,t),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,t),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>&#9650;</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>&#9660;</span>"+"</a>"},_start:function(e){return this.spinning||this._trigger("start",e)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(e,t,i){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,i)},e),this._spin(t*this.options.step,i)},_spin:function(e,t){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+e*this._increment(this.counter)),this.spinning&&this._trigger("spin",t,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(t){var i=this.options.incremental;return i?e.isFunction(i)?i(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return null!==this.options.min&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=""+e,i=t.indexOf(".");return-1===i?0:t.length-i-1},_adjustValue:function(e){var t,i,s=this.options;return t=null!==s.min?s.min:0,i=e-t,i=Math.round(i/s.step)*s.step,e=t+i,e=parseFloat(e.toFixed(this._precision())),null!==s.max&&e>s.max?s.max:null!==s.min&&s.min>e?s.min:e},_stop:function(e){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",e))},_setOption:function(e,t){if("culture"===e||"numberFormat"===e){var i=this._parse(this.element.val());return this.options[e]=t,this.element.val(this._format(i)),void 0}("max"===e||"min"===e||"step"===e)&&"string"==typeof t&&(t=this._parse(t)),"icons"===e&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(t.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(t.down)),this._super(e,t),"disabled"===e&&(this.widget().toggleClass("ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable"))},_setOptions:h(function(e){this._super(e)}),_parse:function(e){return"string"==typeof e&&""!==e&&(e=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(e,10,this.options.culture):+e),""===e||isNaN(e)?null:e},_format:function(e){return""===e?"":window.Globalize&&this.options.numberFormat?Globalize.format(e,this.options.numberFormat,this.options.culture):e},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var e=this.value();return null===e?!1:e===this._adjustValue(e)},_value:function(e,t){var i;""!==e&&(i=this._parse(e),null!==i&&(t||(i=this._adjustValue(i)),e=this._format(i))),this.element.val(e),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:h(function(e){this._stepUp(e)}),_stepUp:function(e){this._start()&&(this._spin((e||1)*this.options.step),this._stop())},stepDown:h(function(e){this._stepDown(e)}),_stepDown:function(e){this._start()&&(this._spin((e||1)*-this.options.step),this._stop())},pageUp:h(function(e){this._stepUp((e||1)*this.options.page)}),pageDown:h(function(e){this._stepDown((e||1)*this.options.page)}),value:function(e){return arguments.length?(h(this._value).call(this,e),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),e.widget("ui.tabs",{version:"1.11.4",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var e=/#.*$/;return function(t){var i,s;t=t.cloneNode(!1),i=t.href.replace(e,""),s=location.href.replace(e,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return t.hash.length>1&&i===s}}(),_create:function(){var t=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible),this._processTabs(),i.active=this._initialActive(),e.isArray(i.disabled)&&(i.disabled=e.unique(i.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):e(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var t=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===t&&(s&&this.tabs.each(function(i,n){return e(n).attr("aria-controls")===s?(t=i,!1):void 0}),null===t&&(t=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===t||-1===t)&&(t=this.tabs.length?0:!1)),t!==!1&&(t=this.tabs.index(this.tabs.eq(t)),-1===t&&(t=i?!1:0)),!i&&t===!1&&this.anchors.length&&(t=0),t},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var i=e(this.document[0].activeElement).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(t)){switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:s++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:n=!1,s--;break;case e.ui.keyCode.END:s=this.anchors.length-1;break;case e.ui.keyCode.HOME:s=0;break;case e.ui.keyCode.SPACE:return t.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case e.ui.keyCode.ENTER:return t.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}t.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),t.ctrlKey||t.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(t){this._handlePageNav(t)||t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){return t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(t,i){function s(){return t>n&&(t=0),0>t&&(t=n),t}for(var n=this.tabs.length-1;-1!==e.inArray(s(),this.options.disabled);)t=i?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):"disabled"===e?(this._setupDisabled(t),void 0):(this._super(e,t),"collapsible"===e&&(this.element.toggleClass("ui-tabs-collapsible",t),t||this.options.active!==!1||this._activate(0)),"event"===e&&this._setupEvents(t),"heightStyle"===e&&this._setupHeightStyle(t),void 0)},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,i=this.tablist.children(":has(a[href])");t.disabled=e.map(i.filter(".ui-state-disabled"),function(e){return i.index(e)}),this._processTabs(),t.active!==!1&&this.anchors.length?this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active):(t.active=!1,this.active=e()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this,i=this.tabs,s=this.anchors,n=this.panels;
-this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist").delegate("> li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(i,s){var n,a,o,r=e(s).uniqueId().attr("id"),h=e(s).closest("li"),l=h.attr("aria-controls");t._isLocal(s)?(n=s.hash,o=n.substring(1),a=t.element.find(t._sanitizeSelector(n))):(o=h.attr("aria-controls")||e({}).uniqueId()[0].id,n="#"+o,a=t.element.find(n),a.length||(a=t._createPanel(o),a.insertAfter(t.panels[i-1]||t.tablist)),a.attr("aria-live","polite")),a.length&&(t.panels=t.panels.add(a)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":o,"aria-labelledby":r}),a.attr("aria-labelledby",r)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("<div>").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var i,s=0;i=this.tabs[s];s++)t===!0||-1!==e.inArray(s,t)?e(i).addClass("ui-state-disabled").attr("aria-disabled","true"):e(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var i={};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(e){e.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var i,s=this.element.parent();"fill"===t?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var t=e(this),s=t.css("position");"absolute"!==s&&"fixed"!==s&&(i-=t.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,i-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===t&&(i=0,this.panels.each(function(){i=Math.max(i,e(this).height("").height())}).height(i))},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?e():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):e(),u={oldTab:s,oldPanel:l,newTab:r?e():a,newPanel:h};t.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",t,u)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?e():a,this.xhr&&this.xhr.abort(),l.length||h.length||e.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),t),this._toggle(t,u))},_toggle:function(t,i){function s(){a.running=!1,a._trigger("activate",t,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===e(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(t){var i,s=this._findActive(t);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tablist.unbind(this.eventNamespace),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),i=t.data("ui-tabs-aria-controls");i?t.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):t.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(t){var i=this.options.disabled;i!==!1&&(void 0===t?i=!1:(t=this._getIndex(t),i=e.isArray(i)?e.map(i,function(e){return e!==t?e:null}):e.map(this.tabs,function(e,i){return i!==t?i:null})),this._setupDisabled(i))},disable:function(t){var i=this.options.disabled;if(i!==!0){if(void 0===t)i=!0;else{if(t=this._getIndex(t),-1!==e.inArray(t,i))return;i=e.isArray(i)?e.merge([t],i).sort():[t]}this._setupDisabled(i)}},load:function(t,i){t=this._getIndex(t);var s=this,n=this.tabs.eq(t),a=n.find(".ui-tabs-anchor"),o=this._getPanelForTab(n),r={tab:n,panel:o},h=function(e,t){"abort"===t&&s.panels.stop(!1,!0),n.removeClass("ui-tabs-loading"),o.removeAttr("aria-busy"),e===s.xhr&&delete s.xhr};this._isLocal(a[0])||(this.xhr=e.ajax(this._ajaxSettings(a,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(n.addClass("ui-tabs-loading"),o.attr("aria-busy","true"),this.xhr.done(function(e,t,n){setTimeout(function(){o.html(e),s._trigger("load",i,r),h(n,t)},1)}).fail(function(e,t){setTimeout(function(){h(e,t)},1)})))},_ajaxSettings:function(t,i,s){var n=this;return{url:t.attr("href"),beforeSend:function(t,a){return n._trigger("beforeLoad",i,e.extend({jqXHR:t,ajaxSettings:a},s))}}},_getPanelForTab:function(t){var i=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),e.widget("ui.tooltip",{version:"1.11.4",options:{content:function(){var t=e(this).attr("title")||"";return e("<a>").text(t).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_addDescribedBy:function(t,i){var s=(t.attr("aria-describedby")||"").split(/\s+/);s.push(i),t.data("ui-tooltip-id",i).attr("aria-describedby",e.trim(s.join(" ")))},_removeDescribedBy:function(t){var i=t.data("ui-tooltip-id"),s=(t.attr("aria-describedby")||"").split(/\s+/),n=e.inArray(i,s);-1!==n&&s.splice(n,1),t.removeData("ui-tooltip-id"),s=e.trim(s.join(" ")),s?t.attr("aria-describedby",s):t.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable(),this.liveRegion=e("<div>").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).addClass("ui-helper-hidden-accessible").appendTo(this.document[0].body)},_setOption:function(t,i){var s=this;return"disabled"===t?(this[i?"_disable":"_enable"](),this.options[t]=i,void 0):(this._super(t,i),"content"===t&&e.each(this.tooltips,function(e,t){s._updateContent(t.element)}),void 0)},_disable:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur");n.target=n.currentTarget=s.element[0],t.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).removeAttr("title")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var i=this,s=e(t?t.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),t&&"mouseover"===t.type&&s.parents().each(function(){var t,s=e(this);s.data("ui-tooltip-open")&&(t=e.Event("blur"),t.target=t.currentTarget=this,i.close(t,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(t,s),this._updateContent(s,t))},_updateContent:function(e,t){var i,s=this.options.content,n=this,a=t?t.type:null;return"string"==typeof s?this._open(t,e,s):(i=s.call(e[0],function(i){n._delay(function(){e.data("ui-tooltip-open")&&(t&&(t.type=a),this._open(t,e,i))})}),i&&this._open(t,e,i),void 0)},_open:function(t,i,s){function n(e){l.of=e,o.is(":hidden")||o.position(l)}var a,o,r,h,l=e.extend({},this.options.position);if(s){if(a=this._find(i))return a.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(t&&"mouseover"===t.type?i.attr("title",""):i.removeAttr("title")),a=this._tooltip(i),o=a.tooltip,this._addDescribedBy(i,o.attr("id")),o.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),s.clone?(h=s.clone(),h.removeAttr("id").find("[id]").removeAttr("id")):h=s,e("<div>").html(h).appendTo(this.liveRegion),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:n}),n(t)):o.position(e.extend({of:i},this.options.position)),o.hide(),this._show(o,this.options.show),this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){o.is(":visible")&&(n(l.of),clearInterval(r))},e.fx.interval)),this._trigger("open",t,{tooltip:o})}},_registerCloseHandlers:function(t,i){var s={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var s=e.Event(t);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),t&&"mouseover"!==t.type||(s.mouseleave="close"),t&&"focusin"!==t.type||(s.focusout="close"),this._on(!0,i,s)},close:function(t){var i,s=this,n=e(t?t.currentTarget:this.element),a=this._find(n);return a?(i=a.tooltip,a.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),a.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(e(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),t&&"mouseleave"===t.type&&e.each(this.parents,function(t,i){e(i.element).attr("title",i.title),delete s.parents[t]}),a.closing=!0,this._trigger("close",t,{tooltip:i}),a.hiding||(a.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(t){var i=e("<div>").attr("role","tooltip").addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||"")),s=i.uniqueId().attr("id");return e("<div>").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),this.tooltips[s]={element:t,tooltip:i}},_find:function(e){var t=e.data("ui-tooltip-id");return t?this.tooltips[t]:null},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur"),a=s.element;n.target=n.currentTarget=a[0],t.close(n,!0),e("#"+i).remove(),a.data("ui-tooltip-title")&&(a.attr("title")||a.attr("title",a.data("ui-tooltip-title")),a.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}})});
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/jquery.shCircleLoader-min.js b/nemo-ui/src/main/resources/nemo/js/jquery.shCircleLoader-min.js
deleted file mode 100644 (file)
index 0bbe2da..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*!
- * SunHater Circle Loader v0.2 (2013-12-28)
- * jQuery plugin
- * Copyright (c) 2014 Pavel Tzonkov <sunhater@sunhater.com>
- * Dual licensed under the MIT and GPL licenses.
- * http://opensource.org/licenses/MIT
- * http://www.gnu.org/licenses/gpl.html
- */
-(function(a){a.fn.shCircleLoader=function(i,e){var m="shcl",c=1,d=a(this);if(i==="destroy"){d.find("."+m).detach();return}else{if((i==="progress")&&(typeof e!=="undefined")){d.each(function(){var s=a(this),q=s.find("."+m);if(!q.get(0)){return}if(!s.find("span").get(0)){q.append("<span></span>")}var r=q.find("span").last();r.html(e).css({position:"absolute",display:"block",left:Math.round((q.width()-r.width())/2)+"px",top:Math.round((q.height()-r.height())/2)+"px"})});return}}o={namespace:m,radius:"auto",dotsRadius:"auto",color:"auto",dots:12,duration:1,clockwise:true,externalCss:false,keyframes:"0%{{prefix}transform:scale(1)}80%{{prefix}transform:scale(.3)}100%{{prefix}transform:scale(1)}",uaPrefixes:["o","ms","webkit","moz",""]};a.extend(o,i);var n=o.color,l=o.namespace,k=o.dots,f=o.externalCss,b=o.uaPrefixes,p=function(q){return q.replace(/(.*)px$/i,"$1")},j=function(t){var r,s,q="";for(r=0;r<b.length;r++){s=b[r].length?("-"+b[r]+"-"):"";q+=t.replace(/\{prefix\}/g,s)}return q},h=function(u,t){var q={};if(!u.substr){a.each(u,function(x,w){a.extend(q,h(x,w))})}else{var r,s;for(r=0;r<b.length;r++){s=b[r].length?("-"+b[r]+"-"):"";q[s+u]=t}}return q};while(a("#"+l+c).get(0)){c++}if(!f){var g=o.keyframes.replace(/\s+$/,"").replace(/^\s+/,"");if(!/(\;|\{)\s*visibility\s*\:/gi.test(g)){g=/^(0+\%|from)\s*\{/i.test(g)?g.replace(/^((0+\%|from)\s*\{)(.*)$/i,"$1visibility:visible;$3"):(/\s+(0+\%|from)\s*\{/i.test(g)?g.replace(/(\s+(0+\%|from)\s*\{)/i,"$1visibility:visible;"):("0%{visibility:visible}"+g))}a(a("head").get(0)?"head":"body").append('<style id="'+l+c+'" type="text/css">'+j("@{prefix}keyframes "+l+c+"_bounce{"+g+"}")+"</style>")}d.each(function(){var q,u,z,s,D,F,E,A,w,C,B={},t=a(this),v=t.find("."+m);if(v.get(0)){v.shCircleLoader("destroy")}t.html('<div class="'+l+((l!=m)?(" "+m):"")+'"></div>');if(f){t=t.find("div")}F=t.innerWidth()-p(t.css("padding-left"))-p(t.css("padding-right"));E=t.innerHeight()-p(t.css("padding-top"))-p(t.css("padding-bottom"));q=(o.radius=="auto")?((F<E)?(F/2):(E/2)):o.radius;if(!f){q--;if(o.dotsRadius=="auto"){u=Math.abs(Math.sin(Math.PI/(1*k)))*q;u=(u*q)/(u+q)-1}else{u=o.dotsRadius}t=t.find("div");z=Math.ceil(q*2);C={position:"relative",width:z+"px",height:z+"px"};if(z<F){C.marginLeft=Math.round((F-z)/2)}if(z<E){C.marginTop=Math.round((E-z)/2)}t.css(C);z=Math.ceil(u*2)+"px";B={position:"absolute",visibility:"hidden",width:z,height:z};if(n!==null){B.background=(n=="auto")?t.css("color"):n}a.extend(B,h({"border-radius":Math.ceil(u)+"px","animation-name":l+c+"_bounce","animation-duration":o.duration+"s","animation-iteration-count":"infinite","animation-direction":"normal"}))}for(z=0;z<k;z++){t.append("<div></div>");if(f&&(typeof u==="undefined")){u=(p(t.find("div").css("width"))/2)}s=t.find("div").last();A=(o.duration/k)*z;D=(2*Math.PI*z)/k;w=q-u;F=w*Math.sin(D);E=w*Math.cos(D);if(o.clockwise){E=-E}C={left:Math.round(F+w)+"px",top:Math.round(E+w)+"px"};if(A){a.extend(C,h("animation-delay",A+"s"))}a.extend(C,B);s.css(C)}})}})(jQuery);
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/scrollrun.js b/nemo-ui/src/main/resources/nemo/js/scrollrun.js
deleted file mode 100644 (file)
index 42fe68b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-\r
-jQuery(document).ready(function ($) {\r
-    $("#ser_init,#SI_Save,#SI_Delete,#node_save,#connection_save,#flow_save,#NE_Delete,#sp_save,#policy_delete").click(function () {\r
-        $("#tabs ul li:nth-child(1) a").trigger("click");\r
-        var nemo_show = $("#nemo_str_show").get(0);\r
-        nemo_show.scrollTop = nemo_show.scrollHeight;\r
-    });\r
-    \r
-});
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/submit.js b/nemo-ui/src/main/resources/nemo/js/submit.js
deleted file mode 100644 (file)
index 3a5c787..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-var suce_count=0; //ajax get ok count \r
-var exec_count=0;//exec ajax count\r
-var restful_exec_flag=0;\r
-\r
-jQuery(document).ready(function($){\r
-\r
-       function validate_success(length,callback_count,ok_count)\r
-       {\r
-               if (callback_count == (length+2)) \r
-               {\r
-                       if(ok_count == (length+2))\r
-                       {\r
-                               alert("提交成功");\r
-                               //intterval_id = setInterval("query_status_exec()",200);\r
-                       }\r
-                       else\r
-                       {\r
-                               alert("提交失败");\r
-                       }\r
-               }\r
-       }\r
-       function validate_failure(length,callback_count,ok_count)\r
-       {\r
-               if (callback_count == (length+2)) \r
-               {\r
-                       alert("提交失败");\r
-               }\r
-       }\r
-\r
-       jQuery.valid_exec=function() {\r
-       console.log("suce_count:"+suce_count);\r
-       console.log("exec_count:"+exec_count);\r
-   if(suce_count==exec_count){\r
-       exec_success();\r
-       exec_after("Current transaction exec successfully");\r
-    }\r
-    else\r
-    {\r
-       exec_after("Current transaction failed to exec,please try again later...");\r
-    }\r
-}\r
-\r
-       function exec_before(){\r
-       //$("#show_status").show();\r
-          //$('#loader').shCircleLoader();\r
-        //show tran_info window \r
-                $("#tabs ul li:nth-child(2) a").trigger("click");\r
-           //write tran_info string\r
-                $info = $("<p>Current transaction is running...</p>");\r
-           $("#trans_info").append($info);\r
-        //scroll go down \r
-                var nemo_show = $("#trans_info").get(0);\r
-                nemo_show.scrollTop = nemo_show.scrollHeight;\r
-       }\r
-    function exec_success()\r
-       {\r
-                $("#nemo_str_show").find("p").each(function () {\r
-                    $(this).addClass("grey_background").children().removeClass("key");\r
-                });\r
-                $("#sel_2,#policy_name_list").find("option").each(function () {\r
-                    $(this).addClass("grey_background");\r
-\r
-                    var sevice_name = "";\r
-                    sevice_name = $("#sel_1").children('option:selected').val().trim();\r
-                    if (sevice_name) {\r
-                        current_entity_instance_list = "";\r
-                        localStorage.setItem(sevice_name + "_entity_instance_list_", $(".NE_up #sel_2").html());\r
-                        console.log($(".NE_up #sel_2").html());\r
-                    }\r
-                    sevice_name = $("#sel_1").children('option:selected').val().trim();\r
-                    if (sevice_name) {\r
-                        current_entity_instance_list = "";\r
-                        localStorage.setItem(sevice_name + "_policy_list_", $("#policy_name_list").html());\r
-                        console.log($("#policy_name_list").html());\r
-                    }\r
-                });\r
-\r
-                var service_name = "";\r
-           //get service_name ,should use real name\r
-                service_name = $(".select_item").children("option:selected").val();\r
-\r
-                if (!service_name || typeof (service_name) == "undefined") return;\r
-                var str = localStorage.setItem(service_name + "_nemo_str", $("#nemo_str_show").html());\r
-       }\r
-   function exec_after(info){\r
-          restful_exec_flag = 0;\r
-       //$("#show_status").hide();\r
-        //show tran_info window \r
-                $("#tabs ul li:nth-child(2) a").trigger("click");\r
-           //write tran_info string\r
-                $info = $("<p>"+info+"</p>");\r
-           $("#trans_info").append($info);\r
-        //scroll go down \r
-                var nemo_show = $("#trans_info").get(0);\r
-                nemo_show.scrollTop = nemo_show.scrollHeight;\r
-                suce_count=0; //ajax get ok count \r
-                exec_count=0;//exec ajax count\r
-       }\r
-\r
-       $("#submit").click(function(){\r
-               //just for test\r
-    //exec_before();\r
-    //exec_success();\r
-    //exec_after("sucess!");\r
-    //return;\r
-\r
-       if(restful_exec_flag == 1)\r
-               {\r
-                       alert("The last transaction has not been finished,Please Wait...");\r
-                       return 0;\r
-               }\r
-               else\r
-               {\r
-                       exec_before();\r
-                       setTimeout('jQuery.valid_exec()', 6000);\r
-                       \r
-                       var ok_count = 0;\r
-                       var callback_count = 0;\r
-                       var service_name = $(".NE_up #sel_1").children('option:selected').val();\r
-                       create_json(service_name);\r
-                       var json_exec_temp = restful_json[service_name];\r
-                       var so_str = '{"input":{"user-id":"'+user_id+'","user-name":"'+user_name+'","user-password":"'+user_password+'","user-role":"'+user_role+'"}}';\r
-                       //var so_json = jQuery.parseJSON(so_str);\r
-                       console.log(so_str);\r
-                       //var so_str = {"input":{"user-id":user_id,"user-name":user_name,"user-password":user_password,"user-role":user_role}};\r
-                        //console.log(so_str);\r
-            exec_count++;\r
-            restful_exec_flag = 1;\r
-                       $.ajax({ \r
-                           url: "/restconf/operations/nemo-intent:begin-transaction/", \r
-                               type:"POST",\r
-                               //data:JSON.stringify(so_str),\r
-                               data:so_str,\r
-                               async: false,\r
-                               dataType:"json",\r
-                               contentType:"application/json",\r
-                               success: function(data){\r
-                                       console.log(data);\r
-                                       callback_count++;\r
-                                       if(data["output"]["result-code"] == "ok")\r
-                                       {\r
-                                               //$("#show_status").show();\r
-                                               //$('#loader').shCircleLoader();\r
-                                               ok_count++;\r
-                                               suce_count++;\r
-                        for(var i=0;i<json_exec_temp.length;i++)\r
-                           {\r
-                           exec_count++;\r
-                               $.ajax({ \r
-                           url: "/restconf/operations/nemo-intent:structure-style-nemo-update", \r
-                               type:"POST",\r
-                               async: false,\r
-                               data:json_exec_temp[i],\r
-                               dataType:"json",\r
-                               contentType:"application/json; charset=UTF-8",\r
-                               success: function(data){\r
-                                       console.log(data);\r
-                                       callback_count++;\r
-                                       if(data["output"]["result-code"] == "ok")\r
-                                       {\r
-                                               ok_count++;\r
-                                               suce_count++;\r
-                                               console.log("update submit sucess!");\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               console.log("update submit fail!");\r
-                                       }\r
-\r
-                                       //validate_success(json_exec_temp.length,callback_count,ok_count);\r
-                               \r
-                               },\r
-                               error:function(data){\r
-                                       console.log(data);\r
-                                       callback_count++;\r
-                                       //validate_failure(json_exec_temp.length,callback_count,ok_count);\r
-                               }\r
-                         });\r
-                       }\r
-                                       }\r
-                                       else\r
-                                       {                       \r
-                                               alert("begin failed");\r
-                                       }\r
-                                       //validate_success(json_exec_temp.length,callback_count,ok_count);\r
-                               },\r
-                               error:function(data){\r
-                                       console.log(data);\r
-                                       callback_count++;\r
-                                       //validate_failure(json_exec_temp.length,callback_count,ok_count);\r
-                               },\r
-                       });\r
-\r
-                   exec_count++;\r
-                       $.ajax({ \r
-                           url: "/restconf/operations/nemo-intent:end-transaction", \r
-                               type:"POST",\r
-                               async: false,\r
-                               data:so_str,\r
-                               dataType:"json",\r
-                               contentType:"application/json; charset=UTF-8",\r
-                               success: function(data){\r
-                                       console.log(data);\r
-                                       callback_count++;\r
-                                       if(data["output"]["result-code"] == "ok")\r
-                                       {\r
-                                               ok_count++;\r
-                                               suce_count++;\r
-                                       }\r
-                                       //validate_success(json_exec_temp.length,callback_count,ok_count);\r
-                               },\r
-                               error:function(data){\r
-                                       console.log(data);\r
-                                       callback_count++;\r
-                                       //validate_failure(json_exec_temp.length,callback_count,ok_count);\r
-                               }\r
-                       });\r
-               }\r
-\r
-       \r
-       });\r
-\r
-});\r
diff --git a/nemo-ui/src/main/resources/nemo/js/submit2.js b/nemo-ui/src/main/resources/nemo/js/submit2.js
deleted file mode 100644 (file)
index 949f57c..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-\r
-jQuery(document).ready(function ($) {\r
-       $("#submit").click(function(){\r
-                $("#show_status").show();\r
-                $('#loader').shCircleLoader();\r
-        //show tran_info window \r
-                $("#tabs ul li:nth-child(2) a").trigger("click");\r
-           //write tran_info string\r
-                $info = $("<p>当前事务正在运行中</p>");\r
-           $("#trans_info").append($info);\r
-                //var obj = document.getElementById("trans_info");\r
-                //obj.innerHTML = "<p>"+"事务"+"</p>";\r
-                //alert(obj.innerHTML);\r
-        //scroll go down \r
-                var nemo_show = $("#trans_info").get(0);\r
-                nemo_show.scrollTop = nemo_show.scrollHeight;\r
-\r
-                $("#nemo_str_show").find("p").each(function () {\r
-                    $(this).addClass("grey_background").children().removeClass("key");\r
-                });\r
-                $("#sel_2,#policy_name_list").find("option").each(function () {\r
-                    $(this).addClass("grey_background");\r
-\r
-                    var sevice_name = "";\r
-                    sevice_name = $("#sel_1").children('option:selected').val().trim();\r
-                    if (sevice_name) {\r
-                        current_entity_instance_list = "";\r
-                        localStorage.setItem(sevice_name + "_entity_instance_list_", $(".NE_up #sel_2").html());\r
-                        console.log($(".NE_up #sel_2").html());\r
-                    }\r
-                    sevice_name = $("#sel_1").children('option:selected').val().trim();\r
-                    if (sevice_name) {\r
-                        current_entity_instance_list = "";\r
-                        localStorage.setItem(sevice_name + "_policy_list_", $("#policy_name_list").html());\r
-                        console.log($("#policy_name_list").html());\r
-                    }\r
-                });\r
-\r
-                var service_name = "";\r
-           //get service_name ,should use real name\r
-                service_name = $(".select_item").children("option:selected").val();\r
-\r
-                if (!service_name || typeof (service_name) == "undefined") return;\r
-                var str = localStorage.setItem(service_name + "_nemo_str", $("#nemo_str_show").html());\r
-\r
-       });\r
-\r
-});
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/topo_data.js b/nemo-ui/src/main/resources/nemo/js/topo_data.js
deleted file mode 100644 (file)
index 2ac304e..0000000
+++ /dev/null
@@ -1,922 +0,0 @@
-       function lead_policy(src_group,dest_group,flow_count_temp,color,id,chain_name,src_name,dest_name)\r
-               {\r
-                       var cir_r = parseInt(jQuery("#"+src_group+" circle:eq(0)").attr("r"));\r
-                       \r
-                       //get circle cx cy\r
-                       src_cx = parseInt(jQuery("#"+src_group+" circle:eq(0)").attr("cx"));\r
-                       src_cy = parseInt(jQuery("#"+src_group+" circle:eq(0)").attr("cy"));\r
-                       dest_cx = parseInt(jQuery("#"+dest_group+" circle:eq(0)").attr("cx"));\r
-                       dest_cy = parseInt(jQuery("#"+dest_group+" circle:eq(0)").attr("cy"));\r
-                       console.log(src_cx+"  "+src_cy+"  "+dest_cx+"   "+dest_cy);\r
-                       \r
-                       //calculate deg\r
-                       var tri_h = dest_cx-src_cx;\r
-                       var tri_l = src_cy-dest_cy;\r
-                       var tri_s = Math.sqrt(tri_l*tri_l + tri_h*tri_h);\r
-                       var deg = Math.asin(tri_l/tri_s);\r
-                       console.log(tri_h+"  "+tri_l+"  "+tri_s);\r
-                       //alert(deg);\r
-                       console.log(deg);\r
-                       \r
-                       \r
-                       //calculate offset\r
-                       var offset = ((20+(15*parseInt(flow_count_temp)))/180)*Math.PI;\r
-                       console.log("temp: "+flow_count_temp+" offset:  "+offset);\r
-                       \r
-                       //calculate path possition\r
-                       var path_src_x,path_src_y,path_dest_x,path_dest_y,mid_x,mid_y,b_x,b_y;\r
-                       if(tri_h >= 0)\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx + cir_r*(Math.cos(offset+deg));\r
-                               path_src_y = src_cy - cir_r*(Math.sin(offset+deg));\r
-                               path_dest_x = dest_cx - (cir_r+14)*(Math.cos(offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));;\r
-                                       b_y = mid_y - (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y - (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       else\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx - cir_r*(Math.cos(offset-deg));\r
-                               path_src_y = src_cy + cir_r*(Math.sin(offset-deg));\r
-                               path_dest_x = dest_cx + (cir_r+14)*(Math.cos(-offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(-offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*parseInt(flow_count_temp))*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*parseInt(flow_count_temp))*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       //path title\r
-                       var path_title = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       \r
-                       \r
-                       \r
-                       //create path\r
-                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       var path_main = jQuery(path).attr({\r
-                               id: id,\r
-                               node_start:src_name,\r
-                               node_end:dest_name,\r
-                               type:"flow",\r
-                               sx:path_src_x,\r
-                               sy:path_src_y,\r
-                               mx:b_x,\r
-                               my:b_y,\r
-                               ex:path_dest_x,\r
-                               ey:path_dest_y,\r
-                               count:flow_count_temp,\r
-                               via:chain_name,\r
-                               d: 'M'+path_src_x + " " + path_src_y+' Q'+b_x+' '+b_y+' '+path_dest_x+' '+path_dest_y,\r
-                               'stroke':color,\r
-                               'stroke-width':3,\r
-                               fill:"none",\r
-                               'stroke-dasharray':"6,6" ,\r
-                               'marker-end':"url(#idArrow2)",\r
-                               'marker-mid':"url(#idtext2)"            \r
-                       });\r
-                               jQuery('#service_svg2').prepend(path_main);             \r
-\r
-               }\r
-       function get_path_color(){\r
-               while(1)\r
-               {\r
-                  var num1 = Math.floor(Math.random()*256);\r
-                  if(num1>220 )\r
-                          continue;\r
-                  return num1.toString();\r
-               }\r
-       }\r
-       function flow_get_end_name(src_ip,dest_ip)\r
-       {\r
-               var host_name = ['',''];\r
-               if(typeof(phy_host_ip[src_ip]) != "undefined")\r
-                       host_name[0] = phy_host_ip[src_ip];\r
-               else\r
-               {\r
-                       for(var find_ip_cursor = 0;find_ip_cursor<jQuery("#service_svg2 g").length;find_ip_cursor++)\r
-                       {\r
-                               if(jQuery("#service_svg2 g:eq("+find_ip_cursor+")").attr("ip-prefix") == src_ip)\r
-                               {\r
-                                       host_name[0] = jQuery("#service_svg2 g:eq("+find_ip_cursor+")").attr("id");\r
-                               }       \r
-                               \r
-                       }\r
-               }\r
-               if(typeof(phy_host_ip[dest_ip]) != "undefined")\r
-                       host_name[1] = phy_host_ip[dest_ip];\r
-               else\r
-               {\r
-                       for(var find_ip_cursor = 0;find_ip_cursor<jQuery("#service_svg2 g").length;find_ip_cursor++)\r
-                       {\r
-                               if(jQuery("#service_svg2 g:eq("+find_ip_cursor+")").attr("ip-prefix") == dest_ip)\r
-                               {\r
-                                       host_name[1] = jQuery("#service_svg2 g:eq("+find_ip_cursor+")").attr("id");\r
-                               }       \r
-                               \r
-                       }\r
-               }               \r
-               console.log(host_name[0]+" "+host_name[1]);\r
-               return host_name;\r
-               \r
-               \r
-       }\r
-       function flow_get_group(src_ip,dest_ip)\r
-       {\r
-               var src_host_name = flow_get_end_name(src_ip,dest_ip)[0];\r
-               var dest_host_name = flow_get_end_name(src_ip,dest_ip)[1];\r
-               var group_node = ['',''];               \r
-               for(var i = 0;i<jQuery("#service_svg2 g").length;i++)\r
-               {       \r
-                       host_list = jQuery("#service_svg2 g:eq("+i+")").attr("sub").split(",");\r
-                       console.log(host_list);\r
-                       if(host_list[0] == '')\r
-                       {\r
-                               continue;\r
-                       }                                       \r
-                       for(var j =0;j<host_list.length;j++)\r
-                       {\r
-                               if(host_list[j] == src_host_name)\r
-                               {\r
-                                       group_node[0] = jQuery("#service_svg2 g:eq("+i+")").attr("id");\r
-                               }\r
-                               if(host_list[j] == dest_host_name)\r
-                               {\r
-                                       group_node[1] = jQuery("#service_svg2 g:eq("+i+")").attr("id");\r
-                               }       \r
-                       }\r
-                       if(group_node[0] != '' && group_node[1] != '')\r
-                               break;\r
-               }\r
-               console.log("node: "+group_node[0]+"  "+group_node[1]);\r
-               return group_node;\r
-       }\r
-       function draw_flow_data(src_ip,dest_ip,flow_name)\r
-       {\r
-                       var src_group=flow_get_group(src_ip,dest_ip)[0];\r
-                       var dest_group=flow_get_group(src_ip,dest_ip)[1];\r
-                       //get flow count\r
-                       var flow_count_temp = 0;\r
-                       while(1)\r
-                       {\r
-                               var end_flag = 0;\r
-                               for(var find_count = 0;find_count<jQuery("#service_svg2 path").length;find_count++)\r
-                               {\r
-                                       if(jQuery("#service_svg2 path:eq("+find_count+")").attr("type") != "flow")\r
-                                               continue;\r
-                                       if(jQuery("#service_svg2 path:eq("+find_count+")").attr("node_start") == src_group && jQuery("#service_svg2 path:eq("+find_count+")").attr("node_end") == dest_group)\r
-                                       {\r
-                                               if(flow_count_temp == jQuery("#service_svg2 path:eq("+find_count+")").attr("count"))\r
-                                               {\r
-                                                       end_flag = 1;\r
-                                                       flow_count_temp++;\r
-                                                       break;\r
-                                               }\r
-               \r
-                                       }\r
-                               }\r
-                               if(end_flag != 1)\r
-                                       break;  \r
-                       }\r
-               \r
-                       \r
-                               \r
-                       \r
-                       //get Radio\r
-                       var cir_r = parseInt(jQuery("#"+src_group+" circle:eq(0)").attr("r"));\r
-                       \r
-                       \r
-                       //get circle cx cy\r
-                       src_cx = parseInt(jQuery("#"+src_group+" circle:eq(0)").attr("cx"));\r
-                       src_cy = parseInt(jQuery("#"+src_group+" circle:eq(0)").attr("cy"));\r
-                       dest_cx = parseInt(jQuery("#"+dest_group+" circle:eq(0)").attr("cx"));\r
-                       dest_cy = parseInt(jQuery("#"+dest_group+" circle:eq(0)").attr("cy"));\r
-                       console.log(src_cx+"  "+src_cy+"  "+dest_cx+"   "+dest_cy);\r
-                       \r
-                       //calculate deg\r
-                       var tri_h = dest_cx-src_cx;\r
-                       var tri_l = src_cy-dest_cy;\r
-                       var tri_s = Math.sqrt(tri_l*tri_l + tri_h*tri_h);\r
-                       var deg = Math.asin(tri_l/tri_s);\r
-                       console.log(tri_h+"  "+tri_l+"  "+tri_s);\r
-                       //alert(deg);\r
-                       console.log(deg);\r
-                       \r
-                       \r
-                       //calculate offset\r
-                       var offset = ((20+(15*flow_count_temp))/180)*Math.PI;\r
-                       console.log("offset:  "+offset);\r
-                       \r
-                       //calculate path possition\r
-                       var path_src_x,path_src_y,path_dest_x,path_dest_y,mid_x,mid_y,b_x,b_y;\r
-                       if(tri_h >= 0)\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx + cir_r*(Math.cos(offset+deg));\r
-                               path_src_y = src_cy - cir_r*(Math.sin(offset+deg));\r
-                               path_dest_x = dest_cx - (cir_r+14)*(Math.cos(offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*flow_count_temp)*Math.abs(Math.sin(deg));;\r
-                                       b_y = mid_y - (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*flow_count_temp)*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y - (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       else\r
-                       {\r
-                               mid_x = src_cx + tri_h/2;\r
-                               mid_y = src_cy - tri_l/2;\r
-                               path_src_x = src_cx - cir_r*(Math.cos(offset-deg));\r
-                               path_src_y = src_cy + cir_r*(Math.sin(offset-deg));\r
-                               path_dest_x = dest_cx + (cir_r+14)*(Math.cos(-offset-deg));\r
-                               path_dest_y = dest_cy - (cir_r+14)*(Math.sin(-offset-deg));\r
-                               if(tri_l >= 0)\r
-                               {                       \r
-                                       b_x = mid_x - (80+30*flow_count_temp)*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               else\r
-                               {\r
-                                       b_x = mid_x + (80+30*flow_count_temp)*Math.abs(Math.sin(deg));\r
-                                       b_y = mid_y + (80+30*flow_count_temp)*Math.abs(Math.cos(deg));\r
-                               }\r
-                               \r
-                       }\r
-                       //path title\r
-                       var path_title = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       \r
-                       \r
-                       \r
-                       //create path\r
-                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       var path_main = jQuery(path).attr({\r
-                               id: flow_name,\r
-                               node_start:src_group,\r
-                               node_end:dest_group,\r
-                               type:"flow",\r
-                               sx:path_src_x,\r
-                               sy:path_src_y,\r
-                               mx:b_x,\r
-                               my:b_y,\r
-                               ex:path_dest_x,\r
-                               ey:path_dest_y,\r
-                               via:"none",\r
-                               count:flow_count_temp,\r
-                               d: 'M'+path_src_x + " " + path_src_y+' Q'+b_x+' '+b_y+' '+path_dest_x+' '+path_dest_y,\r
-                               'stroke':"rgb("+get_path_color()+","+get_path_color()+","+get_path_color()+")",\r
-                               'stroke-width':3,\r
-                               fill:"none",\r
-                               'stroke-dasharray':"6,6" ,\r
-                               'marker-end':"url(#idArrow2)",\r
-                               'marker-mid':"url(#idtext2)"            \r
-                       });\r
-                       if(ne_flag == 0)\r
-                               jQuery(path).attr("stroke","rgb("+get_path_color()+","+get_path_color()+","+get_path_color()+")");\r
-                       else if(ne_flag == 1)\r
-                               jQuery(path).attr("stroke",old_color);\r
-                       jQuery('#service_svg2').prepend(path_main);     \r
-               \r
-               \r
-       }\r
-       \r
-       function draw_connection_data(conn_name,node_name_1,node_name_2,bandwidth)\r
-       {\r
-        if(conn_name!=null && typeof(conn_name)!="undefined")\r
-        jQuery("#"+conn_name).remove();\r
-         try \r
-               {\r
-                       var node_cx_1 = jQuery("#"+node_name_1+"_group").attr("cx");\r
-                       var node_cy_1 = jQuery("#"+node_name_1+"_group").attr("cy");\r
-                       var node_cx_2 = jQuery("#"+node_name_2+"_group").attr("cx");\r
-                       var node_cy_2 = jQuery("#"+node_name_2+"_group").attr("cy");\r
-                       //var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r
-                       var path_main = jQuery(path).attr({\r
-                               id: conn_name,\r
-                               node_start:node_name_1,\r
-                               node_end:node_name_2,\r
-                               type:"connection",\r
-                               d: 'M'+node_cx_1 + " " + node_cy_1+' L'+node_cx_2+' '+node_cy_2,\r
-                               'stroke':"black",\r
-                               'stroke-width':parseInt(bandwidth),\r
-                               fill:"black"\r
-                               });\r
-                       jQuery('#service_svg2').prepend(path_main);                                             \r
-        }\r
-\r
-        catch (err) {\r
-             alert(err);\r
-        }                      \r
-       }\r
-       function redraw_node_possition_data()\r
-       {\r
-               node_count = jQuery("#service_svg2 g").length;\r
-               if(node_count == 1)\r
-               {\r
-                       var x = 550;\r
-            var y = 450;\r
-                       dis_x = x-jQuery("#service_svg2 g:eq(0) circle:eq(0)").attr("cx");\r
-                       dis_y = y-jQuery("#service_svg2 g:eq(0) circle:eq(0)").attr("cy");\r
-                       jQuery("#service_svg2 g:eq(0) circle:eq(0)").attr("cx",x);\r
-                       jQuery("#service_svg2 g:eq(0) circle:eq(0)").attr("cy",y);\r
-                       for(var j =0;j<jQuery("#service_svg2 g:eq(0) rect").length;j++)\r
-                       {\r
-                               var last_x = parseInt(jQuery("#service_svg2 g:eq(0) rect:eq("+j+")").attr("x"));\r
-                               var last_y = parseInt(jQuery("#service_svg2 g:eq(0) rect:eq("+j+")").attr("y"));\r
-                               jQuery("#service_svg2 g:eq(0) rect:eq("+j+")").attr("x",last_x+dis_x);\r
-                               jQuery("#service_svg2 g:eq(0) rect:eq("+j+")").attr("y",last_y+dis_y);\r
-                       }\r
-                       for(var j =0;j<jQuery("#service_svg2 g:eq(0) text").length;j++)\r
-                       {\r
-                               jQuery("#service_svg2 g:eq(0) text:eq("+j+")").attr("x",parseInt(jQuery("#service_svg2 g:eq(0) text:eq("+j+")").attr("x"))+dis_x);\r
-                               jQuery("#service_svg2 g:eq(0) text:eq("+j+")").attr("y",parseInt(jQuery("#service_svg2 g:eq(0) text:eq("+j+")").attr("y"))+dis_y);                      \r
-                       }\r
-                       \r
-                        return;\r
-                       \r
-               }\r
-               var res = calculatePos(node_count);\r
-        var r = 300;\r
-               for(var i =0;i<node_count;i++)\r
-               {\r
-                       var deg = res[i];\r
-            var x = 550 + Math.cos(deg) * r;\r
-            var y = 450 - Math.sin(deg) * r;\r
-                       dis_x = x-parseInt(jQuery("#service_svg2 g:eq("+i+") circle:eq(0)").attr("cx"));\r
-                       dis_y = y-parseInt(jQuery("#service_svg2 g:eq("+i+") circle:eq(0)").attr("cy"));\r
-                       jQuery("#service_svg2 g:eq("+i+") circle:eq(0)").attr("cx",x);\r
-                       jQuery("#service_svg2 g:eq("+i+") circle:eq(0)").attr("cy",y);\r
-                       for(var j =0;j<jQuery("#service_svg2 g:eq("+i+") rect").length;j++)\r
-                       {\r
-                               jQuery("#service_svg2 g:eq("+i+") rect:eq("+j+")").attr("x",parseInt(jQuery("#service_svg2 g:eq("+i+") rect:eq("+j+")").attr("x"))+dis_x);\r
-                               jQuery("#service_svg2 g:eq("+i+") rect:eq("+j+")").attr("y",parseInt(jQuery("#service_svg2 g:eq("+i+") rect:eq("+j+")").attr("y"))+dis_y);\r
-                       }\r
-                       for(var j =0;j<jQuery("#service_svg2 g:eq("+i+") text").length;j++)\r
-                       {\r
-                               jQuery("#service_svg2 g:eq("+i+") text:eq("+j+")").attr("x",parseInt(jQuery("#service_svg2 g:eq("+i+") text:eq("+j+")").attr("x"))+dis_x);\r
-                               jQuery("#service_svg2 g:eq("+i+") text:eq("+j+")").attr("y",parseInt(jQuery("#service_svg2 g:eq("+i+") text:eq("+j+")").attr("y"))+dis_y);                      \r
-                       }\r
-                       \r
-               }\r
-\r
-       }\r
-       function draw_group_data(node_name,node_number,node_list,node_type,ip)\r
-       {\r
-               //alert("type:"+node_type)\r
-               var circle_x = 550;\r
-               var circle_y = 450;\r
-               if(node_number == 0)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = jQuery(circle_main).attr({\r
-                               id: node_name + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = jQuery(text1).attr({\r
-                               id: node_name + "_title1",\r
-                               x: circle_x,\r
-                               y: circle_y-8,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                               \r
-                       });\r
-                       jQuery(text1).text(node_type);\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = jQuery(text2).attr({\r
-                               id: node_name + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y+10,\r
-                               fill:"                       ",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text2).text(node_name);\r
-                       var g_main = jQuery(g).append(inCircle1_main);\r
-                       jQuery(g).append(text1_main);\r
-                       jQuery(g).append(text2_main);\r
-                       jQuery(g).attr("id",node_name);\r
-                       jQuery(g).attr("type",node_type);\r
-                       if(node_type != "ext-group")\r
-                               jQuery(g).attr("sub","");\r
-                       else\r
-                       {\r
-                               jQuery(g).attr("sub",node_name);\r
-                               jQuery(g).attr("ip-prefix",ip);\r
-                               //ext_ip[jQuery("#ext-group_ip-prefix").val().trim()] = jQuery("#node_name").val().trim();\r
-               \r
-                       }\r
-                       if(node_type.indexOf("chain") > -1)\r
-                               jQuery(g).attr("flow",0);\r
-                       jQuery('#service_svg2').append(g_main); \r
-               }\r
-               else if(node_number == 1)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = jQuery(circle_main).attr({\r
-                               id: node_name + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var host1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');\r
-                       var host1_main = jQuery(host1).attr({\r
-                               id: node_list[0],\r
-                               x: circle_x-57,\r
-                               y: circle_y-25,\r
-                               width:114,\r
-                               height:50,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = jQuery(text1).attr({\r
-                               id: node_name + "_title1",\r
-                               x: circle_x,\r
-                               y: circle_y-48,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                       });\r
-                       jQuery(text1).text(node_type);\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = jQuery(text2).attr({\r
-                               id: node_name + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y-30,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text2).text(node_name);\r
-                       var text3 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text3_main = jQuery(text3).attr({\r
-                               id: node_list[0]+'_text',\r
-                               x: circle_x,\r
-                               y: circle_y,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text3).text(node_list[0]);\r
-                       var g_main = jQuery(g).append(inCircle1_main);\r
-                       jQuery(g).append(host1_main);\r
-                       jQuery(g).append(text1_main);\r
-                       jQuery(g).append(text2_main);\r
-                       jQuery(g).append(text3_main);\r
-                       jQuery(g).attr("id",node_name);\r
-                       jQuery(g).attr("type",node_type);\r
-                       jQuery(g).attr("sub",node_list[0]);\r
-                       if(node_type.indexOf("chain") > -1)\r
-                               jQuery(g).attr("flow",0);\r
-                       jQuery('#service_svg2').append(g_main);                         \r
-               }\r
-               else if(node_number == 2)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = jQuery(circle_main).attr({\r
-                               id: node_name + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var host1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host1_main = jQuery(host1).attr({\r
-                               id:node_list[0],\r
-                               x: circle_x-55,\r
-                               y: circle_y-25,\r
-                               width:110,\r
-                               height:34,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var host2 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host2_main = jQuery(host2).attr({\r
-                               id: node_list[1],\r
-                               x: circle_x-55,\r
-                               y: circle_y+18,\r
-                               width:110,\r
-                               height:34,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = jQuery(text1).attr({\r
-                               id: node_name + "_title1",\r
-                               x: circle_x,\r
-                               y: circle_y-48,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                       });\r
-                       jQuery(text1).text(node_type);\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = jQuery(text2).attr({\r
-                               id:  node_name + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y-31,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text2).text(node_name);\r
-                       var text3 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text3_main = jQuery(text3).attr({\r
-                               id: node_list[0] + "_text",\r
-                               x: circle_x,\r
-                               y: circle_y-5,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text3).text(node_list[0]);\r
-                       var text4 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text4_main = jQuery(text4).attr({\r
-                               id:node_list[1] + "_text",\r
-                               x: circle_x,\r
-                               y: circle_y+40,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text4).text(node_list[1]);\r
-                       var g_main = jQuery(g).append(inCircle1_main);\r
-                       jQuery(g).append(host1_main);\r
-                       jQuery(g).append(host2_main);\r
-                       jQuery(g).append(text1_main);\r
-                       jQuery(g).append(text2_main);\r
-                       jQuery(g).append(text3_main);\r
-                       jQuery(g).append(text4_main);\r
-                       jQuery(g).attr("id",node_name);\r
-                       jQuery(g).attr("type",node_type);\r
-                       jQuery(g).attr("sub",node_list[0]+","+node_list[1]);\r
-                       if(node_type.indexOf("chain") > -1)\r
-                               jQuery(g).attr("flow",0);\r
-                       jQuery('#service_svg2').append(g);\r
-                       \r
-               }\r
-               else if(node_number == 3)\r
-               {\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\r
-                       var circle_main = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\r
-                       var inCircle1_main = jQuery(circle_main).attr({\r
-                               id: node_name + "_group",\r
-                               cx: circle_x,\r
-                               cy: circle_y,\r
-                               r:90,\r
-                               'stroke':"black",\r
-                               'stroke-width':3,\r
-                               fill:"white"\r
-                       });\r
-                       var host1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host1_main = jQuery(host1).attr({\r
-                               id: node_list[0],\r
-                               x: circle_x-55,\r
-                               y: circle_y-31,\r
-                               width:110,\r
-                               height:25,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var host2 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host2_main = jQuery(host2).attr({\r
-                               id: node_list[1],\r
-                               x: circle_x-55,\r
-                               y: circle_y-3,\r
-                               width:110,\r
-                               height:25,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var host3 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');                                                             \r
-                       var host3_main = jQuery(host3).attr({\r
-                               id: node_list[2],\r
-                               x: circle_x-55,\r
-                               y: circle_y+27,\r
-                               width:110,\r
-                               height:25,\r
-                               'stroke':"black",\r
-                               'stroke-width':1,\r
-                               fill:"white"\r
-                       });\r
-                       var text1 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text1_main = jQuery(text1).attr({\r
-                               id: node_name + "_title1",\r
-                               x: circle_x,\r
-                               y: circle_y-51,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle',\r
-                               "stroke":"black",\r
-                               "stroke-width":0.8\r
-                       });\r
-                       jQuery(text1).text(node_type);\r
-                       var text2 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text2_main = jQuery(text2).attr({\r
-                               id: node_name + "_title2",\r
-                               x: circle_x,\r
-                               y: circle_y-36,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text2).text(node_name);\r
-                       var text3 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text3_main = jQuery(text3).attr({\r
-                               id: node_list[0] + '_text',\r
-                               x: circle_x,\r
-                               y: circle_y-13,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text3).text(node_list[0]);\r
-                       var text4 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text4_main = jQuery(text4).attr({\r
-                               id: node_list[1] + '_text',\r
-                               x: circle_x,\r
-                               y: circle_y+13,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text4).text(node_list[1]);\r
-                       var text5 = document.createElementNS('http://www.w3.org/2000/svg', 'text');\r
-                       var text5_main = jQuery(text5).attr({\r
-                               id: node_list[2] + '_text',\r
-                               x: circle_x,\r
-                               y: circle_y+43,\r
-                               fill:"black",\r
-                               'text-anchor': 'middle'\r
-                       });\r
-                       jQuery(text5).text(node_list[2]);\r
-                       var g_main = jQuery(g).append(inCircle1_main);\r
-                       jQuery(g).append(host1_main);\r
-                       jQuery(g).append(host2_main);\r
-                       jQuery(g).append(host3_main);\r
-                       jQuery(g).append(text1_main);\r
-                       jQuery(g).append(text2_main);\r
-                       jQuery(g).append(text3_main);\r
-                       jQuery(g).append(text4_main);\r
-                       jQuery(g).append(text5_main);\r
-                       jQuery(g).attr("id",node_name);\r
-                       jQuery(g).attr("type",node_type);\r
-                       jQuery(g).attr("sub",node_list[0]+","+node_list[1]+","+node_list[2]);\r
-                       if(node_type.indexOf("chain") > -1)\r
-                               jQuery(g).attr("flow",0);\r
-                       jQuery('#service_svg2').append(g);      \r
-               }               \r
-       }\r
-function analyjson_topo()\r
-{\r
-       jQuery("#service_svg2").show();       \r
-    jQuery("#service_svg").hide();  \r
-    jQuery("#graph").hide();  \r
-       jQuery("#service_svg").empty();\r
-       var username = jQuery("#getUserName").val();\r
-       //alert(username);\r
-       var html_init = '<defs><marker id="idArrow2" viewBox="0 0 20 20" refX="0" refY="10" markerUnits="strokeWidth" markerWidth="6" markerHeight="15" orient="auto"><path d="M 0 0 L 20 10 L0 20 z"fill="purple"stroke="black"/> </marker>\\r
-                    <marker id="idtext2" viewBox="0 0 120 50" refX="0" refY="0" markerUnits="strokeWidth" markerWidth="20" markerHeight="20"  orient="auto"><text style="font-family:sans-serif; font-size:14pt;"  x="20" y="20">text</text></marker></defs>';\r
-       jQuery("#service_svg2").html(html_init);\r
-       var topo_data;\r
-       jQuery.ajax({ \r
-                           url: "/restconf/config/nemo-intent:users/", \r
-                               type:"GET",\r
-                               async: false,\r
-                               dataType:"json",\r
-                               success: function(data){\r
-                                       console.log(data);      \r
-                               topo_data= data;\r
-                               },\r
-                               error:function(data){\r
-                                       console.log(data);\r
-                               }\r
-                       });\r
-\r
-       var name_data_list = topo_data["users"]["user"];\r
-       \r
-       var user_json_data,user_data;\r
-       for(var i in name_data_list) \r
-       {\r
-               if(name_data_list[i]["user-name"] == username )\r
-               {\r
-                       user_data = name_data_list[i];\r
-                       user_json_data = name_data_list[i]["objects"];\r
-                       break;\r
-               }       \r
-       }\r
-       \r
-       if(user_json_data == null)\r
-               return;\r
-       \r
-\r
-       //host\r
-       var host_list = [];\r
-       for(var host_cursor in user_json_data["node"])\r
-       {\r
-               if(user_json_data["node"][host_cursor]["node-type"] != "host")\r
-                       continue;\r
-               host_list[user_json_data["node"][host_cursor]["node-id"]] = user_json_data["node"][host_cursor]["node-name"];\r
-       \r
-       }\r
-                               \r
-       //vas\r
-       var vas_list = [];\r
-       for(var vas_cursor in user_json_data["node"])\r
-       {\r
-               if(user_json_data["node"][vas_cursor]["node-type"] != "cache" && user_json_data["node"][vas_cursor]["node-type"] != "fw" && user_json_data["node"][vas_cursor]["node-type"] != "lb")\r
-                       continue;\r
-               \r
-               vas_list[user_json_data["node"][vas_cursor]["node-id"]] = user_json_data["node"][vas_cursor]["node-name"];\r
-       \r
-       }\r
-       \r
-       \r
-       //group\r
-       var node_list = [];\r
-       \r
-       //l2/l3-group\r
-       for(var lgroup_cursor in user_json_data["node"])\r
-       {\r
-               if(user_json_data["node"][lgroup_cursor]["node-type"] != "l2-group" && user_json_data["node"][lgroup_cursor]["node-type"] != "l3-group" )\r
-                       continue;\r
-               var sub_count = 0;\r
-               var sub_list = [];\r
-               for(var sub_cursor in user_json_data["node"][lgroup_cursor]["sub-node"])\r
-               {\r
-                       sub_list[sub_count] = host_list[user_json_data["node"][lgroup_cursor]["sub-node"][sub_cursor]["node-id"]];\r
-                       sub_count++;            \r
-               }\r
-               draw_group_data(user_json_data["node"][lgroup_cursor]["node-name"],sub_list.length,sub_list,user_json_data["node"][lgroup_cursor]["node-type"],"");\r
-               redraw_node_possition_data();\r
-               node_list[user_json_data["node"][lgroup_cursor]["node-id"]] = user_json_data["node"][lgroup_cursor]["node-name"];\r
-       }\r
-       \r
-       //chain_group\r
-       for(var cgroup_cursor in user_json_data["node"])\r
-       {\r
-               \r
-               if(user_json_data["node"][cgroup_cursor]["node-type"] != "chain-group")\r
-                       continue;\r
-               //alert("chain");\r
-               var sub_count = 0;\r
-               var sub_list = [];\r
-               for(var sub_cursor in user_json_data["node"][cgroup_cursor]["sub-node"])\r
-               {\r
-                       //alert(user_json_data["node"][cgroup_cursor]["sub-node"][sub_cursor]["node-id"]);\r
-                       sub_list[sub_count] = vas_list[user_json_data["node"][cgroup_cursor]["sub-node"][sub_cursor]["node-id"]];\r
-                       sub_count++;            \r
-               }\r
-               //alert();\r
-               draw_group_data(user_json_data["node"][cgroup_cursor]["node-name"],sub_list.length,sub_list,user_json_data["node"][cgroup_cursor]["node-type"],"");\r
-               redraw_node_possition_data();\r
-               node_list[user_json_data["node"][cgroup_cursor]["node-id"]] = user_json_data["node"][cgroup_cursor]["node-name"];\r
-       }\r
-       \r
-       //ext-group\r
-       for(var egroup_cursor in user_json_data["node"])\r
-       {\r
-               if(user_json_data["node"][egroup_cursor]["node-type"] != "ext-group")\r
-                       continue;\r
-               //alert("ext");\r
-               var ip;\r
-               for(var ip_cursor in user_json_data["node"][egroup_cursor]["property"])\r
-               {\r
-                       if(user_json_data["node"][egroup_cursor]["property"][ip_cursor]["property-name"] == "ip-prefix")\r
-                       {\r
-                               ip = user_json_data["node"][egroup_cursor]["property"][ip_cursor]["property-values"]["string-value"][0]["value"];       \r
-                       }\r
-               }\r
-               draw_group_data(user_json_data["node"][egroup_cursor]["node-name"],0,'',user_json_data["node"][egroup_cursor]["node-type"],ip);\r
-               redraw_node_possition_data();\r
-               node_list[user_json_data["node"][egroup_cursor]["node-id"]] = user_json_data["node"][egroup_cursor]["node-name"];\r
-       }\r
-       \r
-       //connection\r
-       for(var conn_cursor in user_json_data["connection"])\r
-       {\r
-               var start_name = node_list[user_json_data["connection"][conn_cursor]["end-node"][0]["node-id"]];\r
-               var end_name = node_list[user_json_data["connection"][conn_cursor]["end-node"][1]["node-id"]];\r
-               var bandwidth\r
-               if( user_json_data["connection"][conn_cursor]["property"]!=null)\r
-                       bandwidth = user_json_data["connection"][conn_cursor]["property"][0]["property-values"]["int-value"][0]["value"];\r
-               else\r
-                       bandwidth = 100;\r
-               draw_connection_data(user_json_data["connection"][conn_cursor]["connection-name"],start_name,end_name,bandwidth/100);\r
-       }\r
-       \r
-       //flow\r
-       if(user_json_data["flow"] != null)\r
-       {\r
-               var flow_list = [];\r
-               for(var flow_cursor in user_json_data["flow"])\r
-               {\r
-                       var src_ip,dst_ip;\r
-                       for(var match_cursor in user_json_data["flow"][flow_cursor]["match-item"])\r
-                       {\r
-                               if(user_json_data["flow"][flow_cursor]["match-item"][match_cursor]["match-item-name"] == "dst-ip")\r
-                               {\r
-                                       dst_ip = user_json_data["flow"][flow_cursor]["match-item"][match_cursor]["match-item-value"]["string-value"];           \r
-                               }\r
-                               if(user_json_data["flow"][flow_cursor]["match-item"][match_cursor]["match-item-name"] == "src-ip")\r
-                               {\r
-                                       src_ip = user_json_data["flow"][flow_cursor]["match-item"][match_cursor]["match-item-value"]["string-value"];           \r
-                               }\r
-                       }       \r
-                       draw_flow_data(src_ip,dst_ip,user_json_data["flow"][flow_cursor]["flow-name"]);\r
-                       flow_list[user_json_data["flow"][flow_cursor]["flow-id"]] =  user_json_data["flow"][flow_cursor]["flow-name"]\r
-               }\r
-\r
-       }\r
-       //operation\r
-       if(user_data["operations"] != null)\r
-       {\r
-               for(var operation_cursor in user_data["operations"]["operation"])\r
-               {       \r
-                       var flow_name = flow_list[user_data["operations"]["operation"][operation_cursor]["target-object"]];\r
-                       var chain_name =node_list[user_data["operations"]["operation"][operation_cursor]["action"][0]["parameter-values"]["string-value"][0]["value"]];\r
-                       var node_start = jQuery("#"+flow_name).attr("node_start");\r
-                       var node_end = jQuery("#"+flow_name).attr("node_end");\r
-                       var c1_flag = 0;\r
-                       var c2_flag = 0;\r
-                       for(var i=0; i<jQuery("#service_svg2 path").length;i++)\r
-                       {\r
-                               if(jQuery("#service_svg2 path:eq("+i+")").attr("type") == "connection")\r
-                               {\r
-                                       var node_name_old_1 = jQuery("#service_svg2 path:eq("+i+")").attr("node_start");\r
-                                       var node_name_old_2 = jQuery("#service_svg2 path:eq("+i+")").attr("node_end");\r
-                                       console.log("old:"+node_name_old_1+"  "+node_name_old_2);\r
-                                       if(((node_start == node_name_old_1)&&(chain_name == node_name_old_2))||((node_start == node_name_old_2)&&(chain_name == node_name_old_1)))\r
-                                       {\r
-                                               c1_flag = 1;\r
-                                       }               \r
-                               }       \r
-                       }\r
-                       for(var i=0; i<jQuery("#service_svg2 path").length;i++)\r
-                       {\r
-                               if(jQuery("#service_svg2 path:eq("+i+")").attr("type") == "connection")\r
-                               {\r
-                                       var node_name_old_1 = jQuery("#service_svg2 path:eq("+i+")").attr("node_start");\r
-                                       var node_name_old_2 = jQuery("#service_svg2 path:eq("+i+")").attr("node_end");\r
-                                       console.log("old:"+node_name_old_1+"  "+node_name_old_2);\r
-                                       if(((node_end == node_name_old_1)&&(chain_name == node_name_old_2))||((node_end == node_name_old_2)&&(chain_name == node_name_old_1)))\r
-                                       {\r
-                                               c2_flag = 1;\r
-                                       }               \r
-                               }       \r
-                       }\r
-                       if(c2_flag == 0 || c2_flag == 0)\r
-                       {\r
-                                       alert("No connection!");\r
-                                       return;\r
-                       }               \r
-                       lead_policy(node_start,chain_name,parseInt(jQuery("#"+flow_name).attr("count")),jQuery("#"+flow_name).attr("stroke"),flow_name+"_1",chain_name,node_start,node_end)\r
-                       lead_policy(chain_name,node_end,parseInt(jQuery("#"+flow_name).attr("count")),jQuery("#"+flow_name).attr("stroke"),flow_name+"_2",chain_name,node_start,node_end)\r
-                       jQuery("#"+flow_name).remove();         \r
-               \r
-               \r
-               \r
-               }\r
-\r
-       }\r
-\r
-}
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/js/vis.js b/nemo-ui/src/main/resources/nemo/js/vis.js
deleted file mode 100644 (file)
index 71d4820..0000000
+++ /dev/null
@@ -1,26689 +0,0 @@
-/**
- * vis.js
- * https://github.com/almende/vis
- *
- * A dynamic, browser-based visualization library.
- *
- * @version 2.0.0
- * @date    2014-06-19
- *
- * @license
- * Copyright (C) 2011-2014 Almende B.V, http://almende.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.vis=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-/**
- * vis.js module imports
- */
-
-// Try to load dependencies from the global window object.
-// If not available there, load via require.
-
-var moment = (typeof window !== 'undefined') && window['moment'] || require('moment');
-var Emitter = require('emitter-component');
-
-var Hammer;
-if (typeof window !== 'undefined') {
-  // load hammer.js only when running in a browser (where window is available)
-  Hammer = window['Hammer'] || require('hammerjs');
-}
-else {
-  Hammer = function () {
-    throw Error('hammer.js is only available in a browser, not in node.js.');
-  }
-}
-
-var mousetrap;
-if (typeof window !== 'undefined') {
-  // load mousetrap.js only when running in a browser (where window is available)
-  mousetrap = window['mousetrap'] || require('mousetrap');
-}
-else {
-  mousetrap = function () {
-    throw Error('mouseTrap is only available in a browser, not in node.js.');
-  }
-}
-
-
-// Internet Explorer 8 and older does not support Array.indexOf, so we define
-// it here in that case.
-// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/
-if(!Array.prototype.indexOf) {
-  Array.prototype.indexOf = function(obj){
-    for(var i = 0; i < this.length; i++){
-      if(this[i] == obj){
-        return i;
-      }
-    }
-    return -1;
-  };
-
-  try {
-    console.log("Warning: Ancient browser detected. Please update your browser");
-  }
-  catch (err) {
-  }
-}
-
-// Internet Explorer 8 and older does not support Array.forEach, so we define
-// it here in that case.
-// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
-if (!Array.prototype.forEach) {
-  Array.prototype.forEach = function(fn, scope) {
-    for(var i = 0, len = this.length; i < len; ++i) {
-      fn.call(scope || this, this[i], i, this);
-    }
-  }
-}
-
-// Internet Explorer 8 and older does not support Array.map, so we define it
-// here in that case.
-// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
-// Production steps of ECMA-262, Edition 5, 15.4.4.19
-// Reference: http://es5.github.com/#x15.4.4.19
-if (!Array.prototype.map) {
-  Array.prototype.map = function(callback, thisArg) {
-
-    var T, A, k;
-
-    if (this == null) {
-      throw new TypeError(" this is null or not defined");
-    }
-
-    // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
-    var O = Object(this);
-
-    // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
-    // 3. Let len be ToUint32(lenValue).
-    var len = O.length >>> 0;
-
-    // 4. If IsCallable(callback) is false, throw a TypeError exception.
-    // See: http://es5.github.com/#x9.11
-    if (typeof callback !== "function") {
-      throw new TypeError(callback + " is not a function");
-    }
-
-    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
-    if (thisArg) {
-      T = thisArg;
-    }
-
-    // 6. Let A be a new array created as if by the expression new Array(len) where Array is
-    // the standard built-in constructor with that name and len is the value of len.
-    A = new Array(len);
-
-    // 7. Let k be 0
-    k = 0;
-
-    // 8. Repeat, while k < len
-    while(k < len) {
-
-      var kValue, mappedValue;
-
-      // a. Let Pk be ToString(k).
-      //   This is implicit for LHS operands of the in operator
-      // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
-      //   This step can be combined with c
-      // c. If kPresent is true, then
-      if (k in O) {
-
-        // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
-        kValue = O[ k ];
-
-        // ii. Let mappedValue be the result of calling the Call internal method of callback
-        // with T as the this value and argument list containing kValue, k, and O.
-        mappedValue = callback.call(T, kValue, k, O);
-
-        // iii. Call the DefineOwnProperty internal method of A with arguments
-        // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
-        // and false.
-
-        // In browsers that support Object.defineProperty, use the following:
-        // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
-
-        // For best browser support, use the following:
-        A[ k ] = mappedValue;
-      }
-      // d. Increase k by 1.
-      k++;
-    }
-
-    // 9. return A
-    return A;
-  };
-}
-
-// Internet Explorer 8 and older does not support Array.filter, so we define it
-// here in that case.
-// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter
-if (!Array.prototype.filter) {
-  Array.prototype.filter = function(fun /*, thisp */) {
-    "use strict";
-
-    if (this == null) {
-      throw new TypeError();
-    }
-
-    var t = Object(this);
-    var len = t.length >>> 0;
-    if (typeof fun != "function") {
-      throw new TypeError();
-    }
-
-    var res = [];
-    var thisp = arguments[1];
-    for (var i = 0; i < len; i++) {
-      if (i in t) {
-        var val = t[i]; // in case fun mutates this
-        if (fun.call(thisp, val, i, t))
-          res.push(val);
-      }
-    }
-
-    return res;
-  };
-}
-
-
-// Internet Explorer 8 and older does not support Object.keys, so we define it
-// here in that case.
-// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
-if (!Object.keys) {
-  Object.keys = (function () {
-    var hasOwnProperty = Object.prototype.hasOwnProperty,
-        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
-        dontEnums = [
-          'toString',
-          'toLocaleString',
-          'valueOf',
-          'hasOwnProperty',
-          'isPrototypeOf',
-          'propertyIsEnumerable',
-          'constructor'
-        ],
-        dontEnumsLength = dontEnums.length;
-
-    return function (obj) {
-      if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) {
-        throw new TypeError('Object.keys called on non-object');
-      }
-
-      var result = [];
-
-      for (var prop in obj) {
-        if (hasOwnProperty.call(obj, prop)) result.push(prop);
-      }
-
-      if (hasDontEnumBug) {
-        for (var i=0; i < dontEnumsLength; i++) {
-          if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
-        }
-      }
-      return result;
-    }
-  })()
-}
-
-// Internet Explorer 8 and older does not support Array.isArray,
-// so we define it here in that case.
-// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray
-if(!Array.isArray) {
-  Array.isArray = function (vArg) {
-    return Object.prototype.toString.call(vArg) === "[object Array]";
-  };
-}
-
-// Internet Explorer 8 and older does not support Function.bind,
-// so we define it here in that case.
-// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
-if (!Function.prototype.bind) {
-  Function.prototype.bind = function (oThis) {
-    if (typeof this !== "function") {
-      // closest thing possible to the ECMAScript 5 internal IsCallable function
-      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
-    }
-
-    var aArgs = Array.prototype.slice.call(arguments, 1),
-        fToBind = this,
-        fNOP = function () {},
-        fBound = function () {
-          return fToBind.apply(this instanceof fNOP && oThis
-              ? this
-              : oThis,
-              aArgs.concat(Array.prototype.slice.call(arguments)));
-        };
-
-    fNOP.prototype = this.prototype;
-    fBound.prototype = new fNOP();
-
-    return fBound;
-  };
-}
-
-// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
-if (!Object.create) {
-  Object.create = function (o) {
-    if (arguments.length > 1) {
-      throw new Error('Object.create implementation only accepts the first parameter.');
-    }
-    function F() {}
-    F.prototype = o;
-    return new F();
-  };
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
-if (!Function.prototype.bind) {
-  Function.prototype.bind = function (oThis) {
-    if (typeof this !== "function") {
-      // closest thing possible to the ECMAScript 5 internal IsCallable function
-      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
-    }
-
-    var aArgs = Array.prototype.slice.call(arguments, 1),
-        fToBind = this,
-        fNOP = function () {},
-        fBound = function () {
-          return fToBind.apply(this instanceof fNOP && oThis
-              ? this
-              : oThis,
-              aArgs.concat(Array.prototype.slice.call(arguments)));
-        };
-
-    fNOP.prototype = this.prototype;
-    fBound.prototype = new fNOP();
-
-    return fBound;
-  };
-}
-
-/**
- * utility functions
- */
-var util = {};
-
-/**
- * Test whether given object is a number
- * @param {*} object
- * @return {Boolean} isNumber
- */
-util.isNumber = function(object) {
-  return (object instanceof Number || typeof object == 'number');
-};
-
-/**
- * Test whether given object is a string
- * @param {*} object
- * @return {Boolean} isString
- */
-util.isString = function(object) {
-  return (object instanceof String || typeof object == 'string');
-};
-
-/**
- * Test whether given object is a Date, or a String containing a Date
- * @param {Date | String} object
- * @return {Boolean} isDate
- */
-util.isDate = function(object) {
-  if (object instanceof Date) {
-    return true;
-  }
-  else if (util.isString(object)) {
-    // test whether this string contains a date
-    var match = ASPDateRegex.exec(object);
-    if (match) {
-      return true;
-    }
-    else if (!isNaN(Date.parse(object))) {
-      return true;
-    }
-  }
-
-  return false;
-};
-
-/**
- * Test whether given object is an instance of google.visualization.DataTable
- * @param {*} object
- * @return {Boolean} isDataTable
- */
-util.isDataTable = function(object) {
-  return (typeof (google) !== 'undefined') &&
-      (google.visualization) &&
-      (google.visualization.DataTable) &&
-      (object instanceof google.visualization.DataTable);
-};
-
-/**
- * Create a semi UUID
- * source: http://stackoverflow.com/a/105074/1262753
- * @return {String} uuid
- */
-util.randomUUID = function() {
-  var S4 = function () {
-    return Math.floor(
-        Math.random() * 0x10000 /* 65536 */
-    ).toString(16);
-  };
-
-  return (
-      S4() + S4() + '-' +
-          S4() + '-' +
-          S4() + '-' +
-          S4() + '-' +
-          S4() + S4() + S4()
-      );
-};
-
-/**
- * Extend object a with the properties of object b or a series of objects
- * Only properties with defined values are copied
- * @param {Object} a
- * @param {... Object} b
- * @return {Object} a
- */
-util.extend = function (a, b) {
-  for (var i = 1, len = arguments.length; i < len; i++) {
-    var other = arguments[i];
-    for (var prop in other) {
-      if (other.hasOwnProperty(prop)) {
-        a[prop] = other[prop];
-      }
-    }
-  }
-
-  return a;
-};
-
-/**
- * Extend object a with selected properties of object b or a series of objects
- * Only properties with defined values are copied
- * @param {Array.<String>} props
- * @param {Object} a
- * @param {... Object} b
- * @return {Object} a
- */
-util.selectiveExtend = function (props, a, b) {
-  if (!Array.isArray(props)) {
-    throw new Error('Array with property names expected as first argument');
-  }
-
-  for (var i = 1, len = arguments.length; i < len; i++) {
-    var other = arguments[i];
-
-    for (var p = 0, pp = props.length; p < pp; p++) {
-      var prop = props[p];
-      if (other.hasOwnProperty(prop)) {
-        a[prop] = other[prop];
-      }
-    }
-  }
-
-  return a;
-};
-
-/**
- * Deep extend an object a with the properties of object b
- * @param {Object} a
- * @param {Object} b
- * @returns {Object}
- */
-util.deepExtend = function(a, b) {
-  // TODO: add support for Arrays to deepExtend
-  if (Array.isArray(b)) {
-    throw new TypeError('Arrays are not supported by deepExtend');
-  }
-
-  for (var prop in b) {
-    if (b.hasOwnProperty(prop)) {
-      if (b[prop] && b[prop].constructor === Object) {
-        if (a[prop] === undefined) {
-          a[prop] = {};
-        }
-        if (a[prop].constructor === Object) {
-          util.deepExtend(a[prop], b[prop]);
-        }
-        else {
-          a[prop] = b[prop];
-        }
-      } else if (Array.isArray(b[prop])) {
-        throw new TypeError('Arrays are not supported by deepExtend');
-      } else {
-        a[prop] = b[prop];
-      }
-    }
-  }
-  return a;
-};
-
-/**
- * Test whether all elements in two arrays are equal.
- * @param {Array} a
- * @param {Array} b
- * @return {boolean} Returns true if both arrays have the same length and same
- *                   elements.
- */
-util.equalArray = function (a, b) {
-  if (a.length != b.length) return false;
-
-  for (var i = 0, len = a.length; i < len; i++) {
-    if (a[i] != b[i]) return false;
-  }
-
-  return true;
-};
-
-/**
- * Convert an object to another type
- * @param {Boolean | Number | String | Date | Moment | Null | undefined} object
- * @param {String | undefined} type   Name of the type. Available types:
- *                                    'Boolean', 'Number', 'String',
- *                                    'Date', 'Moment', ISODate', 'ASPDate'.
- * @return {*} object
- * @throws Error
- */
-util.convert = function(object, type) {
-  var match;
-
-  if (object === undefined) {
-    return undefined;
-  }
-  if (object === null) {
-    return null;
-  }
-
-  if (!type) {
-    return object;
-  }
-  if (!(typeof type === 'string') && !(type instanceof String)) {
-    throw new Error('Type must be a string');
-  }
-
-  //noinspection FallthroughInSwitchStatementJS
-  switch (type) {
-    case 'boolean':
-    case 'Boolean':
-      return Boolean(object);
-
-    case 'number':
-    case 'Number':
-      return Number(object.valueOf());
-
-    case 'string':
-    case 'String':
-      return String(object);
-
-    case 'Date':
-      if (util.isNumber(object)) {
-        return new Date(object);
-      }
-      if (object instanceof Date) {
-        return new Date(object.valueOf());
-      }
-      else if (moment.isMoment(object)) {
-        return new Date(object.valueOf());
-      }
-      if (util.isString(object)) {
-        match = ASPDateRegex.exec(object);
-        if (match) {
-          // object is an ASP date
-          return new Date(Number(match[1])); // parse number
-        }
-        else {
-          return moment(object).toDate(); // parse string
-        }
-      }
-      else {
-        throw new Error(
-            'Cannot convert object of type ' + util.getType(object) +
-                ' to type Date');
-      }
-
-    case 'Moment':
-      if (util.isNumber(object)) {
-        return moment(object);
-      }
-      if (object instanceof Date) {
-        return moment(object.valueOf());
-      }
-      else if (moment.isMoment(object)) {
-        return moment(object);
-      }
-      if (util.isString(object)) {
-        match = ASPDateRegex.exec(object);
-        if (match) {
-          // object is an ASP date
-          return moment(Number(match[1])); // parse number
-        }
-        else {
-          return moment(object); // parse string
-        }
-      }
-      else {
-        throw new Error(
-            'Cannot convert object of type ' + util.getType(object) +
-                ' to type Date');
-      }
-
-    case 'ISODate':
-      if (util.isNumber(object)) {
-        return new Date(object);
-      }
-      else if (object instanceof Date) {
-        return object.toISOString();
-      }
-      else if (moment.isMoment(object)) {
-        return object.toDate().toISOString();
-      }
-      else if (util.isString(object)) {
-        match = ASPDateRegex.exec(object);
-        if (match) {
-          // object is an ASP date
-          return new Date(Number(match[1])).toISOString(); // parse number
-        }
-        else {
-          return new Date(object).toISOString(); // parse string
-        }
-      }
-      else {
-        throw new Error(
-            'Cannot convert object of type ' + util.getType(object) +
-                ' to type ISODate');
-      }
-
-    case 'ASPDate':
-      if (util.isNumber(object)) {
-        return '/Date(' + object + ')/';
-      }
-      else if (object instanceof Date) {
-        return '/Date(' + object.valueOf() + ')/';
-      }
-      else if (util.isString(object)) {
-        match = ASPDateRegex.exec(object);
-        var value;
-        if (match) {
-          // object is an ASP date
-          value = new Date(Number(match[1])).valueOf(); // parse number
-        }
-        else {
-          value = new Date(object).valueOf(); // parse string
-        }
-        return '/Date(' + value + ')/';
-      }
-      else {
-        throw new Error(
-            'Cannot convert object of type ' + util.getType(object) +
-                ' to type ASPDate');
-      }
-
-    default:
-      throw new Error('Unknown type "' + type + '"');
-  }
-};
-
-// parse ASP.Net Date pattern,
-// for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
-// code from http://momentjs.com/
-var ASPDateRegex = /^\/?Date\((\-?\d+)/i;
-
-/**
- * Get the type of an object, for example util.getType([]) returns 'Array'
- * @param {*} object
- * @return {String} type
- */
-util.getType = function(object) {
-  var type = typeof object;
-
-  if (type == 'object') {
-    if (object == null) {
-      return 'null';
-    }
-    if (object instanceof Boolean) {
-      return 'Boolean';
-    }
-    if (object instanceof Number) {
-      return 'Number';
-    }
-    if (object instanceof String) {
-      return 'String';
-    }
-    if (object instanceof Array) {
-      return 'Array';
-    }
-    if (object instanceof Date) {
-      return 'Date';
-    }
-    return 'Object';
-  }
-  else if (type == 'number') {
-    return 'Number';
-  }
-  else if (type == 'boolean') {
-    return 'Boolean';
-  }
-  else if (type == 'string') {
-    return 'String';
-  }
-
-  return type;
-};
-
-/**
- * Retrieve the absolute left value of a DOM element
- * @param {Element} elem        A dom element, for example a div
- * @return {number} left        The absolute left position of this element
- *                              in the browser page.
- */
-util.getAbsoluteLeft = function(elem) {
-  var doc = document.documentElement;
-  var body = document.body;
-
-  var left = elem.offsetLeft;
-  var e = elem.offsetParent;
-  while (e != null && e != body && e != doc) {
-    left += e.offsetLeft;
-    left -= e.scrollLeft;
-    e = e.offsetParent;
-  }
-  return left;
-};
-
-/**
- * Retrieve the absolute top value of a DOM element
- * @param {Element} elem        A dom element, for example a div
- * @return {number} top        The absolute top position of this element
- *                              in the browser page.
- */
-util.getAbsoluteTop = function(elem) {
-  var doc = document.documentElement;
-  var body = document.body;
-
-  var top = elem.offsetTop;
-  var e = elem.offsetParent;
-  while (e != null && e != body && e != doc) {
-    top += e.offsetTop;
-    top -= e.scrollTop;
-    e = e.offsetParent;
-  }
-  return top;
-};
-
-/**
- * Get the absolute, vertical mouse position from an event.
- * @param {Event} event
- * @return {Number} pageY
- */
-util.getPageY = function(event) {
-  if ('pageY' in event) {
-    return event.pageY;
-  }
-  else {
-    var clientY;
-    if (('targetTouches' in event) && event.targetTouches.length) {
-      clientY = event.targetTouches[0].clientY;
-    }
-    else {
-      clientY = event.clientY;
-    }
-
-    var doc = document.documentElement;
-    var body = document.body;
-    return clientY +
-        ( doc && doc.scrollTop || body && body.scrollTop || 0 ) -
-        ( doc && doc.clientTop || body && body.clientTop || 0 );
-  }
-};
-
-/**
- * Get the absolute, horizontal mouse position from an event.
- * @param {Event} event
- * @return {Number} pageX
- */
-util.getPageX = function(event) {
-  if ('pageY' in event) {
-    return event.pageX;
-  }
-  else {
-    var clientX;
-    if (('targetTouches' in event) && event.targetTouches.length) {
-      clientX = event.targetTouches[0].clientX;
-    }
-    else {
-      clientX = event.clientX;
-    }
-
-    var doc = document.documentElement;
-    var body = document.body;
-    return clientX +
-        ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
-        ( doc && doc.clientLeft || body && body.clientLeft || 0 );
-  }
-};
-
-/**
- * add a className to the given elements style
- * @param {Element} elem
- * @param {String} className
- */
-util.addClassName = function(elem, className) {
-  var classes = elem.className.split(' ');
-  if (classes.indexOf(className) == -1) {
-    classes.push(className); // add the class to the array
-    elem.className = classes.join(' ');
-  }
-};
-
-/**
- * add a className to the given elements style
- * @param {Element} elem
- * @param {String} className
- */
-util.removeClassName = function(elem, className) {
-  var classes = elem.className.split(' ');
-  var index = classes.indexOf(className);
-  if (index != -1) {
-    classes.splice(index, 1); // remove the class from the array
-    elem.className = classes.join(' ');
-  }
-};
-
-/**
- * For each method for both arrays and objects.
- * In case of an array, the built-in Array.forEach() is applied.
- * In case of an Object, the method loops over all properties of the object.
- * @param {Object | Array} object   An Object or Array
- * @param {function} callback       Callback method, called for each item in
- *                                  the object or array with three parameters:
- *                                  callback(value, index, object)
- */
-util.forEach = function(object, callback) {
-  var i,
-      len;
-  if (object instanceof Array) {
-    // array
-    for (i = 0, len = object.length; i < len; i++) {
-      callback(object[i], i, object);
-    }
-  }
-  else {
-    // object
-    for (i in object) {
-      if (object.hasOwnProperty(i)) {
-        callback(object[i], i, object);
-      }
-    }
-  }
-};
-
-/**
- * Convert an object into an array: all objects properties are put into the
- * array. The resulting array is unordered.
- * @param {Object} object
- * @param {Array} array
- */
-util.toArray = function(object) {
-  var array = [];
-
-  for (var prop in object) {
-    if (object.hasOwnProperty(prop)) array.push(object[prop]);
-  }
-
-  return array;
-}
-
-/**
- * Update a property in an object
- * @param {Object} object
- * @param {String} key
- * @param {*} value
- * @return {Boolean} changed
- */
-util.updateProperty = function(object, key, value) {
-  if (object[key] !== value) {
-    object[key] = value;
-    return true;
-  }
-  else {
-    return false;
-  }
-};
-
-/**
- * Add and event listener. Works for all browsers
- * @param {Element}     element    An html element
- * @param {string}      action     The action, for example "click",
- *                                 without the prefix "on"
- * @param {function}    listener   The callback function to be executed
- * @param {boolean}     [useCapture]
- */
-util.addEventListener = function(element, action, listener, useCapture) {
-  if (element.addEventListener) {
-    if (useCapture === undefined)
-      useCapture = false;
-
-    if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
-      action = "DOMMouseScroll";  // For Firefox
-    }
-
-    element.addEventListener(action, listener, useCapture);
-  } else {
-    element.attachEvent("on" + action, listener);  // IE browsers
-  }
-};
-
-/**
- * Remove an event listener from an element
- * @param {Element}     element         An html dom element
- * @param {string}      action          The name of the event, for example "mousedown"
- * @param {function}    listener        The listener function
- * @param {boolean}     [useCapture]
- */
-util.removeEventListener = function(element, action, listener, useCapture) {
-  if (element.removeEventListener) {
-    // non-IE browsers
-    if (useCapture === undefined)
-      useCapture = false;
-
-    if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
-      action = "DOMMouseScroll";  // For Firefox
-    }
-
-    element.removeEventListener(action, listener, useCapture);
-  } else {
-    // IE browsers
-    element.detachEvent("on" + action, listener);
-  }
-};
-
-
-/**
- * Get HTML element which is the target of the event
- * @param {Event} event
- * @return {Element} target element
- */
-util.getTarget = function(event) {
-  // code from http://www.quirksmode.org/js/events_properties.html
-  if (!event) {
-    event = window.event;
-  }
-
-  var target;
-
-  if (event.target) {
-    target = event.target;
-  }
-  else if (event.srcElement) {
-    target = event.srcElement;
-  }
-
-  if (target.nodeType != undefined && target.nodeType == 3) {
-    // defeat Safari bug
-    target = target.parentNode;
-  }
-
-  return target;
-};
-
-/**
- * Fake a hammer.js gesture. Event can be a ScrollEvent or MouseMoveEvent
- * @param {Element} element
- * @param {Event} event
- */
-util.fakeGesture = function(element, event) {
-  var eventType = null;
-
-  // for hammer.js 1.0.5
-  var gesture = Hammer.event.collectEventData(this, eventType, event);
-
-  // for hammer.js 1.0.6
-  //var touches = Hammer.event.getTouchList(event, eventType);
-  // var gesture = Hammer.event.collectEventData(this, eventType, touches, event);
-
-  // on IE in standards mode, no touches are recognized by hammer.js,
-  // resulting in NaN values for center.pageX and center.pageY
-  if (isNaN(gesture.center.pageX)) {
-    gesture.center.pageX = event.pageX;
-  }
-  if (isNaN(gesture.center.pageY)) {
-    gesture.center.pageY = event.pageY;
-  }
-
-  return gesture;
-};
-
-util.option = {};
-
-/**
- * Convert a value into a boolean
- * @param {Boolean | function | undefined} value
- * @param {Boolean} [defaultValue]
- * @returns {Boolean} bool
- */
-util.option.asBoolean = function (value, defaultValue) {
-  if (typeof value == 'function') {
-    value = value();
-  }
-
-  if (value != null) {
-    return (value != false);
-  }
-
-  return defaultValue || null;
-};
-
-/**
- * Convert a value into a number
- * @param {Boolean | function | undefined} value
- * @param {Number} [defaultValue]
- * @returns {Number} number
- */
-util.option.asNumber = function (value, defaultValue) {
-  if (typeof value == 'function') {
-    value = value();
-  }
-
-  if (value != null) {
-    return Number(value) || defaultValue || null;
-  }
-
-  return defaultValue || null;
-};
-
-/**
- * Convert a value into a string
- * @param {String | function | undefined} value
- * @param {String} [defaultValue]
- * @returns {String} str
- */
-util.option.asString = function (value, defaultValue) {
-  if (typeof value == 'function') {
-    value = value();
-  }
-
-  if (value != null) {
-    return String(value);
-  }
-
-  return defaultValue || null;
-};
-
-/**
- * Convert a size or location into a string with pixels or a percentage
- * @param {String | Number | function | undefined} value
- * @param {String} [defaultValue]
- * @returns {String} size
- */
-util.option.asSize = function (value, defaultValue) {
-  if (typeof value == 'function') {
-    value = value();
-  }
-
-  if (util.isString(value)) {
-    return value;
-  }
-  else if (util.isNumber(value)) {
-    return value + 'px';
-  }
-  else {
-    return defaultValue || null;
-  }
-};
-
-/**
- * Convert a value into a DOM element
- * @param {HTMLElement | function | undefined} value
- * @param {HTMLElement} [defaultValue]
- * @returns {HTMLElement | null} dom
- */
-util.option.asElement = function (value, defaultValue) {
-  if (typeof value == 'function') {
-    value = value();
-  }
-
-  return value || defaultValue || null;
-};
-
-
-
-util.GiveDec = function(Hex) {
-  var Value;
-
-  if (Hex == "A")
-    Value = 10;
-  else if (Hex == "B")
-    Value = 11;
-  else if (Hex == "C")
-    Value = 12;
-  else if (Hex == "D")
-    Value = 13;
-  else if (Hex == "E")
-    Value = 14;
-  else if (Hex == "F")
-    Value = 15;
-  else
-    Value = eval(Hex);
-
-  return Value;
-};
-
-util.GiveHex = function(Dec) {
-  var Value;
-
-  if(Dec == 10)
-    Value = "A";
-  else if (Dec == 11)
-    Value = "B";
-  else if (Dec == 12)
-    Value = "C";
-  else if (Dec == 13)
-    Value = "D";
-  else if (Dec == 14)
-    Value = "E";
-  else if (Dec == 15)
-    Value = "F";
-  else
-    Value = "" + Dec;
-
-  return Value;
-};
-
-/**
- * Parse a color property into an object with border, background, and
- * highlight colors
- * @param {Object | String} color
- * @return {Object} colorObject
- */
-util.parseColor = function(color) {
-  var c;
-  if (util.isString(color)) {
-    if (util.isValidHex(color)) {
-      var hsv = util.hexToHSV(color);
-      var lighterColorHSV = {h:hsv.h,s:hsv.s * 0.45,v:Math.min(1,hsv.v * 1.05)};
-      var darkerColorHSV  = {h:hsv.h,s:Math.min(1,hsv.v * 1.25),v:hsv.v*0.6};
-      var darkerColorHex  = util.HSVToHex(darkerColorHSV.h ,darkerColorHSV.h ,darkerColorHSV.v);
-      var lighterColorHex = util.HSVToHex(lighterColorHSV.h,lighterColorHSV.s,lighterColorHSV.v);
-
-      c = {
-        background: color,
-        border:darkerColorHex,
-        highlight: {
-          background:lighterColorHex,
-          border:darkerColorHex
-        },
-        hover: {
-          background:lighterColorHex,
-          border:darkerColorHex
-        }
-      };
-    }
-    else {
-      c = {
-        background:color,
-        border:color,
-        highlight: {
-          background:color,
-          border:color
-        },
-        hover: {
-          background:color,
-          border:color
-        }
-      };
-    }
-  }
-  else {
-    c = {};
-    c.background = color.background || 'white';
-    c.border = color.border || c.background;
-
-    if (util.isString(color.highlight)) {
-      c.highlight = {
-        border: color.highlight,
-        background: color.highlight
-      }
-    }
-    else {
-      c.highlight = {};
-      c.highlight.background = color.highlight && color.highlight.background || c.background;
-      c.highlight.border = color.highlight && color.highlight.border || c.border;
-    }
-
-    if (util.isString(color.hover)) {
-      c.hover = {
-        border: color.hover,
-        background: color.hover
-      }
-    }
-    else {
-      c.hover = {};
-      c.hover.background = color.hover && color.hover.background || c.background;
-      c.hover.border = color.hover && color.hover.border || c.border;
-    }
-  }
-
-  return c;
-};
-
-/**
- * http://www.yellowpipe.com/yis/tools/hex-to-rgb/color-converter.php
- *
- * @param {String} hex
- * @returns {{r: *, g: *, b: *}}
- */
-util.hexToRGB = function(hex) {
-  hex = hex.replace("#","").toUpperCase();
-
-  var a = util.GiveDec(hex.substring(0, 1));
-  var b = util.GiveDec(hex.substring(1, 2));
-  var c = util.GiveDec(hex.substring(2, 3));
-  var d = util.GiveDec(hex.substring(3, 4));
-  var e = util.GiveDec(hex.substring(4, 5));
-  var f = util.GiveDec(hex.substring(5, 6));
-
-  var r = (a * 16) + b;
-  var g = (c * 16) + d;
-  var b = (e * 16) + f;
-
-  return {r:r,g:g,b:b};
-};
-
-util.RGBToHex = function(red,green,blue) {
-  var a = util.GiveHex(Math.floor(red / 16));
-  var b = util.GiveHex(red % 16);
-  var c = util.GiveHex(Math.floor(green / 16));
-  var d = util.GiveHex(green % 16);
-  var e = util.GiveHex(Math.floor(blue / 16));
-  var f = util.GiveHex(blue % 16);
-
-  var hex = a + b + c + d + e + f;
-  return "#" + hex;
-};
-
-
-/**
- * http://www.javascripter.net/faq/rgb2hsv.htm
- *
- * @param red
- * @param green
- * @param blue
- * @returns {*}
- * @constructor
- */
-util.RGBToHSV = function(red,green,blue) {
-  red=red/255; green=green/255; blue=blue/255;
-  var minRGB = Math.min(red,Math.min(green,blue));
-  var maxRGB = Math.max(red,Math.max(green,blue));
-
-  // Black-gray-white
-  if (minRGB == maxRGB) {
-    return {h:0,s:0,v:minRGB};
-  }
-
-  // Colors other than black-gray-white:
-  var d = (red==minRGB) ? green-blue : ((blue==minRGB) ? red-green : blue-red);
-  var h = (red==minRGB) ? 3 : ((blue==minRGB) ? 1 : 5);
-  var hue = 60*(h - d/(maxRGB - minRGB))/360;
-  var saturation = (maxRGB - minRGB)/maxRGB;
-  var value = maxRGB;
-  return {h:hue,s:saturation,v:value};
-};
-
-
-/**
- * https://gist.github.com/mjijackson/5311256
- * @param hue
- * @param saturation
- * @param value
- * @returns {{r: number, g: number, b: number}}
- * @constructor
- */
-util.HSVToRGB = function(h, s, v) {
-  var r, g, b;
-
-  var i = Math.floor(h * 6);
-  var f = h * 6 - i;
-  var p = v * (1 - s);
-  var q = v * (1 - f * s);
-  var t = v * (1 - (1 - f) * s);
-
-  switch (i % 6) {
-    case 0: r = v, g = t, b = p; break;
-    case 1: r = q, g = v, b = p; break;
-    case 2: r = p, g = v, b = t; break;
-    case 3: r = p, g = q, b = v; break;
-    case 4: r = t, g = p, b = v; break;
-    case 5: r = v, g = p, b = q; break;
-  }
-
-  return {r:Math.floor(r * 255), g:Math.floor(g * 255), b:Math.floor(b * 255) };
-};
-
-util.HSVToHex = function(h, s, v) {
-  var rgb = util.HSVToRGB(h, s, v);
-  return util.RGBToHex(rgb.r, rgb.g, rgb.b);
-};
-
-util.hexToHSV = function(hex) {
-  var rgb = util.hexToRGB(hex);
-  return util.RGBToHSV(rgb.r, rgb.g, rgb.b);
-};
-
-util.isValidHex = function(hex) {
-  var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
-  return isOk;
-};
-
-util.copyObject = function(objectFrom, objectTo) {
-  for (var i in objectFrom) {
-    if (objectFrom.hasOwnProperty(i)) {
-      if (typeof objectFrom[i] == "object") {
-        objectTo[i] = {};
-        util.copyObject(objectFrom[i], objectTo[i]);
-      }
-      else {
-        objectTo[i] = objectFrom[i];
-      }
-    }
-  }
-};
-
-/**
- * DataSet
- *
- * Usage:
- *     var dataSet = new DataSet({
- *         fieldId: '_id',
- *         type: {
- *             // ...
- *         }
- *     });
- *
- *     dataSet.add(item);
- *     dataSet.add(data);
- *     dataSet.update(item);
- *     dataSet.update(data);
- *     dataSet.remove(id);
- *     dataSet.remove(ids);
- *     var data = dataSet.get();
- *     var data = dataSet.get(id);
- *     var data = dataSet.get(ids);
- *     var data = dataSet.get(ids, options, data);
- *     dataSet.clear();
- *
- * A data set can:
- * - add/remove/update data
- * - gives triggers upon changes in the data
- * - can  import/export data in various data formats
- *
- * @param {Array | DataTable} [data]    Optional array with initial data
- * @param {Object} [options]   Available options:
- *                             {String} fieldId Field name of the id in the
- *                                              items, 'id' by default.
- *                             {Object.<String, String} type
- *                                              A map with field names as key,
- *                                              and the field type as value.
- * @constructor DataSet
- */
-// TODO: add a DataSet constructor DataSet(data, options)
-function DataSet (data, options) {
-  // correctly read optional arguments
-  if (data && !Array.isArray(data) && !util.isDataTable(data)) {
-    options = data;
-    data = null;
-  }
-
-  this._options = options || {};
-  this._data = {};                                 // map with data indexed by id
-  this._fieldId = this._options.fieldId || 'id';   // name of the field containing id
-  this._type = {};                                 // internal field types (NOTE: this can differ from this._options.type)
-
-  // all variants of a Date are internally stored as Date, so we can convert
-  // from everything to everything (also from ISODate to Number for example)
-  if (this._options.type) {
-    for (var field in this._options.type) {
-      if (this._options.type.hasOwnProperty(field)) {
-        var value = this._options.type[field];
-        if (value == 'Date' || value == 'ISODate' || value == 'ASPDate') {
-          this._type[field] = 'Date';
-        }
-        else {
-          this._type[field] = value;
-        }
-      }
-    }
-  }
-
-  // TODO: deprecated since version 1.1.1 (or 2.0.0?)
-  if (this._options.convert) {
-    throw new Error('Option "convert" is deprecated. Use "type" instead.');
-  }
-
-  this._subscribers = {};  // event subscribers
-
-  // add initial data when provided
-  if (data) {
-    this.add(data);
-  }
-}
-
-/**
- * Subscribe to an event, add an event listener
- * @param {String} event        Event name. Available events: 'put', 'update',
- *                              'remove'
- * @param {function} callback   Callback method. Called with three parameters:
- *                                  {String} event
- *                                  {Object | null} params
- *                                  {String | Number} senderId
- */
-DataSet.prototype.on = function(event, callback) {
-  var subscribers = this._subscribers[event];
-  if (!subscribers) {
-    subscribers = [];
-    this._subscribers[event] = subscribers;
-  }
-
-  subscribers.push({
-    callback: callback
-  });
-};
-
-// TODO: make this function deprecated (replaced with `on` since version 0.5)
-DataSet.prototype.subscribe = DataSet.prototype.on;
-
-/**
- * Unsubscribe from an event, remove an event listener
- * @param {String} event
- * @param {function} callback
- */
-DataSet.prototype.off = function(event, callback) {
-  var subscribers = this._subscribers[event];
-  if (subscribers) {
-    this._subscribers[event] = subscribers.filter(function (listener) {
-      return (listener.callback != callback);
-    });
-  }
-};
-
-// TODO: make this function deprecated (replaced with `on` since version 0.5)
-DataSet.prototype.unsubscribe = DataSet.prototype.off;
-
-/**
- * Trigger an event
- * @param {String} event
- * @param {Object | null} params
- * @param {String} [senderId]       Optional id of the sender.
- * @private
- */
-DataSet.prototype._trigger = function (event, params, senderId) {
-  if (event == '*') {
-    throw new Error('Cannot trigger event *');
-  }
-
-  var subscribers = [];
-  if (event in this._subscribers) {
-    subscribers = subscribers.concat(this._subscribers[event]);
-  }
-  if ('*' in this._subscribers) {
-    subscribers = subscribers.concat(this._subscribers['*']);
-  }
-
-  for (var i = 0; i < subscribers.length; i++) {
-    var subscriber = subscribers[i];
-    if (subscriber.callback) {
-      subscriber.callback(event, params, senderId || null);
-    }
-  }
-};
-
-/**
- * Add data.
- * Adding an item will fail when there already is an item with the same id.
- * @param {Object | Array | DataTable} data
- * @param {String} [senderId] Optional sender id
- * @return {Array} addedIds      Array with the ids of the added items
- */
-DataSet.prototype.add = function (data, senderId) {
-  var addedIds = [],
-      id,
-      me = this;
-
-  if (Array.isArray(data)) {
-    // Array
-    for (var i = 0, len = data.length; i < len; i++) {
-      id = me._addItem(data[i]);
-      addedIds.push(id);
-    }
-  }
-  else if (util.isDataTable(data)) {
-    // Google DataTable
-    var columns = this._getColumnNames(data);
-    for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) {
-      var item = {};
-      for (var col = 0, cols = columns.length; col < cols; col++) {
-        var field = columns[col];
-        item[field] = data.getValue(row, col);
-      }
-
-      id = me._addItem(item);
-      addedIds.push(id);
-    }
-  }
-  else if (data instanceof Object) {
-    // Single item
-    id = me._addItem(data);
-    addedIds.push(id);
-  }
-  else {
-    throw new Error('Unknown dataType');
-  }
-
-  if (addedIds.length) {
-    this._trigger('add', {items: addedIds}, senderId);
-  }
-
-  return addedIds;
-};
-
-/**
- * Update existing items. When an item does not exist, it will be created
- * @param {Object | Array | DataTable} data
- * @param {String} [senderId] Optional sender id
- * @return {Array} updatedIds     The ids of the added or updated items
- */
-DataSet.prototype.update = function (data, senderId) {
-  var addedIds = [],
-      updatedIds = [],
-      me = this,
-      fieldId = me._fieldId;
-
-  var addOrUpdate = function (item) {
-    var id = item[fieldId];
-    if (me._data[id]) {
-      // update item
-      id = me._updateItem(item);
-      updatedIds.push(id);
-    }
-    else {
-      // add new item
-      id = me._addItem(item);
-      addedIds.push(id);
-    }
-  };
-
-  if (Array.isArray(data)) {
-    // Array
-    for (var i = 0, len = data.length; i < len; i++) {
-      addOrUpdate(data[i]);
-    }
-  }
-  else if (util.isDataTable(data)) {
-    // Google DataTable
-    var columns = this._getColumnNames(data);
-    for (var row = 0, rows = data.getNumberOfRows(); row < rows; row++) {
-      var item = {};
-      for (var col = 0, cols = columns.length; col < cols; col++) {
-        var field = columns[col];
-        item[field] = data.getValue(row, col);
-      }
-
-      addOrUpdate(item);
-    }
-  }
-  else if (data instanceof Object) {
-    // Single item
-    addOrUpdate(data);
-  }
-  else {
-    throw new Error('Unknown dataType');
-  }
-
-  if (addedIds.length) {
-    this._trigger('add', {items: addedIds}, senderId);
-  }
-  if (updatedIds.length) {
-    this._trigger('update', {items: updatedIds}, senderId);
-  }
-
-  return addedIds.concat(updatedIds);
-};
-
-/**
- * Get a data item or multiple items.
- *
- * Usage:
- *
- *     get()
- *     get(options: Object)
- *     get(options: Object, data: Array | DataTable)
- *
- *     get(id: Number | String)
- *     get(id: Number | String, options: Object)
- *     get(id: Number | String, options: Object, data: Array | DataTable)
- *
- *     get(ids: Number[] | String[])
- *     get(ids: Number[] | String[], options: Object)
- *     get(ids: Number[] | String[], options: Object, data: Array | DataTable)
- *
- * Where:
- *
- * {Number | String} id         The id of an item
- * {Number[] | String{}} ids    An array with ids of items
- * {Object} options             An Object with options. Available options:
- *                              {String} [returnType] Type of data to be
- *                                  returned. Can be 'DataTable' or 'Array' (default)
- *                              {Object.<String, String>} [type]
- *                              {String[]} [fields] field names to be returned
- *                              {function} [filter] filter items
- *                              {String | function} [order] Order the items by
- *                                  a field name or custom sort function.
- * {Array | DataTable} [data]   If provided, items will be appended to this
- *                              array or table. Required in case of Google
- *                              DataTable.
- *
- * @throws Error
- */
-DataSet.prototype.get = function (args) {
-  var me = this;
-
-  // parse the arguments
-  var id, ids, options, data;
-  var firstType = util.getType(arguments[0]);
-  if (firstType == 'String' || firstType == 'Number') {
-    // get(id [, options] [, data])
-    id = arguments[0];
-    options = arguments[1];
-    data = arguments[2];
-  }
-  else if (firstType == 'Array') {
-    // get(ids [, options] [, data])
-    ids = arguments[0];
-    options = arguments[1];
-    data = arguments[2];
-  }
-  else {
-    // get([, options] [, data])
-    options = arguments[0];
-    data = arguments[1];
-  }
-
-  // determine the return type
-  var returnType;
-  if (options && options.returnType) {
-    returnType = (options.returnType == 'DataTable') ? 'DataTable' : 'Array';
-
-    if (data && (returnType != util.getType(data))) {
-      throw new Error('Type of parameter "data" (' + util.getType(data) + ') ' +
-          'does not correspond with specified options.type (' + options.type + ')');
-    }
-    if (returnType == 'DataTable' && !util.isDataTable(data)) {
-      throw new Error('Parameter "data" must be a DataTable ' +
-          'when options.type is "DataTable"');
-    }
-  }
-  else if (data) {
-    returnType = (util.getType(data) == 'DataTable') ? 'DataTable' : 'Array';
-  }
-  else {
-    returnType = 'Array';
-  }
-
-  // build options
-  var type = options && options.type || this._options.type;
-  var filter = options && options.filter;
-  var items = [], item, itemId, i, len;
-
-  // convert items
-  if (id != undefined) {
-    // return a single item
-    item = me._getItem(id, type);
-    if (filter && !filter(item)) {
-      item = null;
-    }
-  }
-  else if (ids != undefined) {
-    // return a subset of items
-    for (i = 0, len = ids.length; i < len; i++) {
-      item = me._getItem(ids[i], type);
-      if (!filter || filter(item)) {
-        items.push(item);
-      }
-    }
-  }
-  else {
-    // return all items
-    for (itemId in this._data) {
-      if (this._data.hasOwnProperty(itemId)) {
-        item = me._getItem(itemId, type);
-        if (!filter || filter(item)) {
-          items.push(item);
-        }
-      }
-    }
-  }
-
-  // order the results
-  if (options && options.order && id == undefined) {
-    this._sort(items, options.order);
-  }
-
-  // filter fields of the items
-  if (options && options.fields) {
-    var fields = options.fields;
-    if (id != undefined) {
-      item = this._filterFields(item, fields);
-    }
-    else {
-      for (i = 0, len = items.length; i < len; i++) {
-        items[i] = this._filterFields(items[i], fields);
-      }
-    }
-  }
-
-  // return the results
-  if (returnType == 'DataTable') {
-    var columns = this._getColumnNames(data);
-    if (id != undefined) {
-      // append a single item to the data table
-      me._appendRow(data, columns, item);
-    }
-    else {
-      // copy the items to the provided data table
-      for (i = 0, len = items.length; i < len; i++) {
-        me._appendRow(data, columns, items[i]);
-      }
-    }
-    return data;
-  }
-  else {
-    // return an array
-    if (id != undefined) {
-      // a single item
-      return item;
-    }
-    else {
-      // multiple items
-      if (data) {
-        // copy the items to the provided array
-        for (i = 0, len = items.length; i < len; i++) {
-          data.push(items[i]);
-        }
-        return data;
-      }
-      else {
-        // just return our array
-        return items;
-      }
-    }
-  }
-};
-
-/**
- * Get ids of all items or from a filtered set of items.
- * @param {Object} [options]    An Object with options. Available options:
- *                              {function} [filter] filter items
- *                              {String | function} [order] Order the items by
- *                                  a field name or custom sort function.
- * @return {Array} ids
- */
-DataSet.prototype.getIds = function (options) {
-  var data = this._data,
-      filter = options && options.filter,
-      order = options && options.order,
-      type = options && options.type || this._options.type,
-      i,
-      len,
-      id,
-      item,
-      items,
-      ids = [];
-
-  if (filter) {
-    // get filtered items
-    if (order) {
-      // create ordered list
-      items = [];
-      for (id in data) {
-        if (data.hasOwnProperty(id)) {
-          item = this._getItem(id, type);
-          if (filter(item)) {
-            items.push(item);
-          }
-        }
-      }
-
-      this._sort(items, order);
-
-      for (i = 0, len = items.length; i < len; i++) {
-        ids[i] = items[i][this._fieldId];
-      }
-    }
-    else {
-      // create unordered list
-      for (id in data) {
-        if (data.hasOwnProperty(id)) {
-          item = this._getItem(id, type);
-          if (filter(item)) {
-            ids.push(item[this._fieldId]);
-          }
-        }
-      }
-    }
-  }
-  else {
-    // get all items
-    if (order) {
-      // create an ordered list
-      items = [];
-      for (id in data) {
-        if (data.hasOwnProperty(id)) {
-          items.push(data[id]);
-        }
-      }
-
-      this._sort(items, order);
-
-      for (i = 0, len = items.length; i < len; i++) {
-        ids[i] = items[i][this._fieldId];
-      }
-    }
-    else {
-      // create unordered list
-      for (id in data) {
-        if (data.hasOwnProperty(id)) {
-          item = data[id];
-          ids.push(item[this._fieldId]);
-        }
-      }
-    }
-  }
-
-  return ids;
-};
-
-/**
- * Execute a callback function for every item in the dataset.
- * @param {function} callback
- * @param {Object} [options]    Available options:
- *                              {Object.<String, String>} [type]
- *                              {String[]} [fields] filter fields
- *                              {function} [filter] filter items
- *                              {String | function} [order] Order the items by
- *                                  a field name or custom sort function.
- */
-DataSet.prototype.forEach = function (callback, options) {
-  var filter = options && options.filter,
-      type = options && options.type || this._options.type,
-      data = this._data,
-      item,
-      id;
-
-  if (options && options.order) {
-    // execute forEach on ordered list
-    var items = this.get(options);
-
-    for (var i = 0, len = items.length; i < len; i++) {
-      item = items[i];
-      id = item[this._fieldId];
-      callback(item, id);
-    }
-  }
-  else {
-    // unordered
-    for (id in data) {
-      if (data.hasOwnProperty(id)) {
-        item = this._getItem(id, type);
-        if (!filter || filter(item)) {
-          callback(item, id);
-        }
-      }
-    }
-  }
-};
-
-/**
- * Map every item in the dataset.
- * @param {function} callback
- * @param {Object} [options]    Available options:
- *                              {Object.<String, String>} [type]
- *                              {String[]} [fields] filter fields
- *                              {function} [filter] filter items
- *                              {String | function} [order] Order the items by
- *                                  a field name or custom sort function.
- * @return {Object[]} mappedItems
- */
-DataSet.prototype.map = function (callback, options) {
-  var filter = options && options.filter,
-      type = options && options.type || this._options.type,
-      mappedItems = [],
-      data = this._data,
-      item;
-
-  // convert and filter items
-  for (var id in data) {
-    if (data.hasOwnProperty(id)) {
-      item = this._getItem(id, type);
-      if (!filter || filter(item)) {
-        mappedItems.push(callback(item, id));
-      }
-    }
-  }
-
-  // order items
-  if (options && options.order) {
-    this._sort(mappedItems, options.order);
-  }
-
-  return mappedItems;
-};
-
-/**
- * Filter the fields of an item
- * @param {Object} item
- * @param {String[]} fields     Field names
- * @return {Object} filteredItem
- * @private
- */
-DataSet.prototype._filterFields = function (item, fields) {
-  var filteredItem = {};
-
-  for (var field in item) {
-    if (item.hasOwnProperty(field) && (fields.indexOf(field) != -1)) {
-      filteredItem[field] = item[field];
-    }
-  }
-
-  return filteredItem;
-};
-
-/**
- * Sort the provided array with items
- * @param {Object[]} items
- * @param {String | function} order      A field name or custom sort function.
- * @private
- */
-DataSet.prototype._sort = function (items, order) {
-  if (util.isString(order)) {
-    // order by provided field name
-    var name = order; // field name
-    items.sort(function (a, b) {
-      var av = a[name];
-      var bv = b[name];
-      return (av > bv) ? 1 : ((av < bv) ? -1 : 0);
-    });
-  }
-  else if (typeof order === 'function') {
-    // order by sort function
-    items.sort(order);
-  }
-  // TODO: extend order by an Object {field:String, direction:String}
-  //       where direction can be 'asc' or 'desc'
-  else {
-    throw new TypeError('Order must be a function or a string');
-  }
-};
-
-/**
- * Remove an object by pointer or by id
- * @param {String | Number | Object | Array} id Object or id, or an array with
- *                                              objects or ids to be removed
- * @param {String} [senderId] Optional sender id
- * @return {Array} removedIds
- */
-DataSet.prototype.remove = function (id, senderId) {
-  var removedIds = [],
-      i, len, removedId;
-
-  if (Array.isArray(id)) {
-    for (i = 0, len = id.length; i < len; i++) {
-      removedId = this._remove(id[i]);
-      if (removedId != null) {
-        removedIds.push(removedId);
-      }
-    }
-  }
-  else {
-    removedId = this._remove(id);
-    if (removedId != null) {
-      removedIds.push(removedId);
-    }
-  }
-
-  if (removedIds.length) {
-    this._trigger('remove', {items: removedIds}, senderId);
-  }
-
-  return removedIds;
-};
-
-/**
- * Remove an item by its id
- * @param {Number | String | Object} id   id or item
- * @returns {Number | String | null} id
- * @private
- */
-DataSet.prototype._remove = function (id) {
-  if (util.isNumber(id) || util.isString(id)) {
-    if (this._data[id]) {
-      delete this._data[id];
-      return id;
-    }
-  }
-  else if (id instanceof Object) {
-    var itemId = id[this._fieldId];
-    if (itemId && this._data[itemId]) {
-      delete this._data[itemId];
-      return itemId;
-    }
-  }
-  return null;
-};
-
-/**
- * Clear the data
- * @param {String} [senderId] Optional sender id
- * @return {Array} removedIds    The ids of all removed items
- */
-DataSet.prototype.clear = function (senderId) {
-  var ids = Object.keys(this._data);
-
-  this._data = {};
-
-  this._trigger('remove', {items: ids}, senderId);
-
-  return ids;
-};
-
-/**
- * Find the item with maximum value of a specified field
- * @param {String} field
- * @return {Object | null} item  Item containing max value, or null if no items
- */
-DataSet.prototype.max = function (field) {
-  var data = this._data,
-      max = null,
-      maxField = null;
-
-  for (var id in data) {
-    if (data.hasOwnProperty(id)) {
-      var item = data[id];
-      var itemField = item[field];
-      if (itemField != null && (!max || itemField > maxField)) {
-        max = item;
-        maxField = itemField;
-      }
-    }
-  }
-
-  return max;
-};
-
-/**
- * Find the item with minimum value of a specified field
- * @param {String} field
- * @return {Object | null} item  Item containing max value, or null if no items
- */
-DataSet.prototype.min = function (field) {
-  var data = this._data,
-      min = null,
-      minField = null;
-
-  for (var id in data) {
-    if (data.hasOwnProperty(id)) {
-      var item = data[id];
-      var itemField = item[field];
-      if (itemField != null && (!min || itemField < minField)) {
-        min = item;
-        minField = itemField;
-      }
-    }
-  }
-
-  return min;
-};
-
-/**
- * Find all distinct values of a specified field
- * @param {String} field
- * @return {Array} values  Array containing all distinct values. If data items
- *                         do not contain the specified field are ignored.
- *                         The returned array is unordered.
- */
-DataSet.prototype.distinct = function (field) {
-  var data = this._data;
-  var values = [];
-  var fieldType = this._options.type && this._options.type[field] || null;
-  var count = 0;
-  var i;
-
-  for (var prop in data) {
-    if (data.hasOwnProperty(prop)) {
-      var item = data[prop];
-      var value = item[field];
-      var exists = false;
-      for (i = 0; i < count; i++) {
-        if (values[i] == value) {
-          exists = true;
-          break;
-        }
-      }
-      if (!exists && (value !== undefined)) {
-        values[count] = value;
-        count++;
-      }
-    }
-  }
-
-  if (fieldType) {
-    for (i = 0; i < values.length; i++) {
-      values[i] = util.convert(values[i], fieldType);
-    }
-  }
-
-  return values;
-};
-
-/**
- * Add a single item. Will fail when an item with the same id already exists.
- * @param {Object} item
- * @return {String} id
- * @private
- */
-DataSet.prototype._addItem = function (item) {
-  var id = item[this._fieldId];
-
-  if (id != undefined) {
-    // check whether this id is already taken
-    if (this._data[id]) {
-      // item already exists
-      throw new Error('Cannot add item: item with id ' + id + ' already exists');
-    }
-  }
-  else {
-    // generate an id
-    id = util.randomUUID();
-    item[this._fieldId] = id;
-  }
-
-  var d = {};
-  for (var field in item) {
-    if (item.hasOwnProperty(field)) {
-      var fieldType = this._type[field];  // type may be undefined
-      d[field] = util.convert(item[field], fieldType);
-    }
-  }
-  this._data[id] = d;
-
-  return id;
-};
-
-/**
- * Get an item. Fields can be converted to a specific type
- * @param {String} id
- * @param {Object.<String, String>} [types]  field types to convert
- * @return {Object | null} item
- * @private
- */
-DataSet.prototype._getItem = function (id, types) {
-  var field, value;
-
-  // get the item from the dataset
-  var raw = this._data[id];
-  if (!raw) {
-    return null;
-  }
-
-  // convert the items field types
-  var converted = {};
-  if (types) {
-    for (field in raw) {
-      if (raw.hasOwnProperty(field)) {
-        value = raw[field];
-        converted[field] = util.convert(value, types[field]);
-      }
-    }
-  }
-  else {
-    // no field types specified, no converting needed
-    for (field in raw) {
-      if (raw.hasOwnProperty(field)) {
-        value = raw[field];
-        converted[field] = value;
-      }
-    }
-  }
-  return converted;
-};
-
-/**
- * Update a single item: merge with existing item.
- * Will fail when the item has no id, or when there does not exist an item
- * with the same id.
- * @param {Object} item
- * @return {String} id
- * @private
- */
-DataSet.prototype._updateItem = function (item) {
-  var id = item[this._fieldId];
-  if (id == undefined) {
-    throw new Error('Cannot update item: item has no id (item: ' + JSON.stringify(item) + ')');
-  }
-  var d = this._data[id];
-  if (!d) {
-    // item doesn't exist
-    throw new Error('Cannot update item: no item with id ' + id + ' found');
-  }
-
-  // merge with current item
-  for (var field in item) {
-    if (item.hasOwnProperty(field)) {
-      var fieldType = this._type[field];  // type may be undefined
-      d[field] = util.convert(item[field], fieldType);
-    }
-  }
-
-  return id;
-};
-
-/**
- * Get an array with the column names of a Google DataTable
- * @param {DataTable} dataTable
- * @return {String[]} columnNames
- * @private
- */
-DataSet.prototype._getColumnNames = function (dataTable) {
-  var columns = [];
-  for (var col = 0, cols = dataTable.getNumberOfColumns(); col < cols; col++) {
-    columns[col] = dataTable.getColumnId(col) || dataTable.getColumnLabel(col);
-  }
-  return columns;
-};
-
-/**
- * Append an item as a row to the dataTable
- * @param dataTable
- * @param columns
- * @param item
- * @private
- */
-DataSet.prototype._appendRow = function (dataTable, columns, item) {
-  var row = dataTable.addRow();
-
-  for (var col = 0, cols = columns.length; col < cols; col++) {
-    var field = columns[col];
-    dataTable.setValue(row, col, item[field]);
-  }
-};
-
-/**
- * DataView
- *
- * a dataview offers a filtered view on a dataset or an other dataview.
- *
- * @param {DataSet | DataView} data
- * @param {Object} [options]   Available options: see method get
- *
- * @constructor DataView
- */
-function DataView (data, options) {
-  this._data = null;
-  this._ids = {}; // ids of the items currently in memory (just contains a boolean true)
-  this._options = options || {};
-  this._fieldId = 'id'; // name of the field containing id
-  this._subscribers = {}; // event subscribers
-
-  var me = this;
-  this.listener = function () {
-    me._onEvent.apply(me, arguments);
-  };
-
-  this.setData(data);
-}
-
-// TODO: implement a function .config() to dynamically update things like configured filter
-// and trigger changes accordingly
-
-/**
- * Set a data source for the view
- * @param {DataSet | DataView} data
- */
-DataView.prototype.setData = function (data) {
-  var ids, i, len;
-
-  if (this._data) {
-    // unsubscribe from current dataset
-    if (this._data.unsubscribe) {
-      this._data.unsubscribe('*', this.listener);
-    }
-
-    // trigger a remove of all items in memory
-    ids = [];
-    for (var id in this._ids) {
-      if (this._ids.hasOwnProperty(id)) {
-        ids.push(id);
-      }
-    }
-    this._ids = {};
-    this._trigger('remove', {items: ids});
-  }
-
-  this._data = data;
-
-  if (this._data) {
-    // update fieldId
-    this._fieldId = this._options.fieldId ||
-        (this._data && this._data.options && this._data.options.fieldId) ||
-        'id';
-
-    // trigger an add of all added items
-    ids = this._data.getIds({filter: this._options && this._options.filter});
-    for (i = 0, len = ids.length; i < len; i++) {
-      id = ids[i];
-      this._ids[id] = true;
-    }
-    this._trigger('add', {items: ids});
-
-    // subscribe to new dataset
-    if (this._data.on) {
-      this._data.on('*', this.listener);
-    }
-  }
-};
-
-/**
- * Get data from the data view
- *
- * Usage:
- *
- *     get()
- *     get(options: Object)
- *     get(options: Object, data: Array | DataTable)
- *
- *     get(id: Number)
- *     get(id: Number, options: Object)
- *     get(id: Number, options: Object, data: Array | DataTable)
- *
- *     get(ids: Number[])
- *     get(ids: Number[], options: Object)
- *     get(ids: Number[], options: Object, data: Array | DataTable)
- *
- * Where:
- *
- * {Number | String} id         The id of an item
- * {Number[] | String{}} ids    An array with ids of items
- * {Object} options             An Object with options. Available options:
- *                              {String} [type] Type of data to be returned. Can
- *                                              be 'DataTable' or 'Array' (default)
- *                              {Object.<String, String>} [convert]
- *                              {String[]} [fields] field names to be returned
- *                              {function} [filter] filter items
- *                              {String | function} [order] Order the items by
- *                                  a field name or custom sort function.
- * {Array | DataTable} [data]   If provided, items will be appended to this
- *                              array or table. Required in case of Google
- *                              DataTable.
- * @param args
- */
-DataView.prototype.get = function (args) {
-  var me = this;
-
-  // parse the arguments
-  var ids, options, data;
-  var firstType = util.getType(arguments[0]);
-  if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') {
-    // get(id(s) [, options] [, data])
-    ids = arguments[0];  // can be a single id or an array with ids
-    options = arguments[1];
-    data = arguments[2];
-  }
-  else {
-    // get([, options] [, data])
-    options = arguments[0];
-    data = arguments[1];
-  }
-
-  // extend the options with the default options and provided options
-  var viewOptions = util.extend({}, this._options, options);
-
-  // create a combined filter method when needed
-  if (this._options.filter && options && options.filter) {
-    viewOptions.filter = function (item) {
-      return me._options.filter(item) && options.filter(item);
-    }
-  }
-
-  // build up the call to the linked data set
-  var getArguments = [];
-  if (ids != undefined) {
-    getArguments.push(ids);
-  }
-  getArguments.push(viewOptions);
-  getArguments.push(data);
-
-  return this._data && this._data.get.apply(this._data, getArguments);
-};
-
-/**
- * Get ids of all items or from a filtered set of items.
- * @param {Object} [options]    An Object with options. Available options:
- *                              {function} [filter] filter items
- *                              {String | function} [order] Order the items by
- *                                  a field name or custom sort function.
- * @return {Array} ids
- */
-DataView.prototype.getIds = function (options) {
-  var ids;
-
-  if (this._data) {
-    var defaultFilter = this._options.filter;
-    var filter;
-
-    if (options && options.filter) {
-      if (defaultFilter) {
-        filter = function (item) {
-          return defaultFilter(item) && options.filter(item);
-        }
-      }
-      else {
-        filter = options.filter;
-      }
-    }
-    else {
-      filter = defaultFilter;
-    }
-
-    ids = this._data.getIds({
-      filter: filter,
-      order: options && options.order
-    });
-  }
-  else {
-    ids = [];
-  }
-
-  return ids;
-};
-
-/**
- * Event listener. Will propagate all events from the connected data set to
- * the subscribers of the DataView, but will filter the items and only trigger
- * when there are changes in the filtered data set.
- * @param {String} event
- * @param {Object | null} params
- * @param {String} senderId
- * @private
- */
-DataView.prototype._onEvent = function (event, params, senderId) {
-  var i, len, id, item,
-      ids = params && params.items,
-      data = this._data,
-      added = [],
-      updated = [],
-      removed = [];
-
-  if (ids && data) {
-    switch (event) {
-      case 'add':
-        // filter the ids of the added items
-        for (i = 0, len = ids.length; i < len; i++) {
-          id = ids[i];
-          item = this.get(id);
-          if (item) {
-            this._ids[id] = true;
-            added.push(id);
-          }
-        }
-
-        break;
-
-      case 'update':
-        // determine the event from the views viewpoint: an updated
-        // item can be added, updated, or removed from this view.
-        for (i = 0, len = ids.length; i < len; i++) {
-          id = ids[i];
-          item = this.get(id);
-
-          if (item) {
-            if (this._ids[id]) {
-              updated.push(id);
-            }
-            else {
-              this._ids[id] = true;
-              added.push(id);
-            }
-          }
-          else {
-            if (this._ids[id]) {
-              delete this._ids[id];
-              removed.push(id);
-            }
-            else {
-              // nothing interesting for me :-(
-            }
-          }
-        }
-
-        break;
-
-      case 'remove':
-        // filter the ids of the removed items
-        for (i = 0, len = ids.length; i < len; i++) {
-          id = ids[i];
-          if (this._ids[id]) {
-            delete this._ids[id];
-            removed.push(id);
-          }
-        }
-
-        break;
-    }
-
-    if (added.length) {
-      this._trigger('add', {items: added}, senderId);
-    }
-    if (updated.length) {
-      this._trigger('update', {items: updated}, senderId);
-    }
-    if (removed.length) {
-      this._trigger('remove', {items: removed}, senderId);
-    }
-  }
-};
-
-// copy subscription functionality from DataSet
-DataView.prototype.on = DataSet.prototype.on;
-DataView.prototype.off = DataSet.prototype.off;
-DataView.prototype._trigger = DataSet.prototype._trigger;
-
-// TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5)
-DataView.prototype.subscribe = DataView.prototype.on;
-DataView.prototype.unsubscribe = DataView.prototype.off;
-
-/**
- * Utility functions for ordering and stacking of items
- */
-var stack = {};
-
-/**
- * Order items by their start data
- * @param {Item[]} items
- */
-stack.orderByStart = function(items) {
-  items.sort(function (a, b) {
-    return a.data.start - b.data.start;
-  });
-};
-
-/**
- * Order items by their end date. If they have no end date, their start date
- * is used.
- * @param {Item[]} items
- */
-stack.orderByEnd = function(items) {
-  items.sort(function (a, b) {
-    var aTime = ('end' in a.data) ? a.data.end : a.data.start,
-        bTime = ('end' in b.data) ? b.data.end : b.data.start;
-
-    return aTime - bTime;
-  });
-};
-
-/**
- * Adjust vertical positions of the items such that they don't overlap each
- * other.
- * @param {Item[]} items
- *            All visible items
- * @param {{item: number, axis: number}} margin
- *            Margins between items and between items and the axis.
- * @param {boolean} [force=false]
- *            If true, all items will be repositioned. If false (default), only
- *            items having a top===null will be re-stacked
- */
-stack.stack = function(items, margin, force) {
-  var i, iMax;
-
-  if (force) {
-    // reset top position of all items
-    for (i = 0, iMax = items.length; i < iMax; i++) {
-      items[i].top = null;
-    }
-  }
-
-  // calculate new, non-overlapping positions
-  for (i = 0, iMax = items.length; i < iMax; i++) {
-    var item = items[i];
-    if (item.top === null) {
-      // initialize top position
-      item.top = margin.axis;
-
-      do {
-        // TODO: optimize checking for overlap. when there is a gap without items,
-        //       you only need to check for items from the next item on, not from zero
-        var collidingItem = null;
-        for (var j = 0, jj = items.length; j < jj; j++) {
-          var other = items[j];
-          if (other.top !== null && other !== item && stack.collision(item, other, margin.item)) {
-            collidingItem = other;
-            break;
-          }
-        }
-
-        if (collidingItem != null) {
-          // There is a collision. Reposition the items above the colliding element
-          item.top = collidingItem.top + collidingItem.height + margin.item;
-        }
-      } while (collidingItem);
-    }
-  }
-};
-
-/**
- * Adjust vertical positions of the items without stacking them
- * @param {Item[]} items
- *            All visible items
- * @param {{item: number, axis: number}} margin
- *            Margins between items and between items and the axis.
- */
-stack.nostack = function(items, margin) {
-  var i, iMax;
-
-  // reset top position of all items
-  for (i = 0, iMax = items.length; i < iMax; i++) {
-    items[i].top = margin.axis;
-  }
-};
-
-/**
- * Test if the two provided items collide
- * The items must have parameters left, width, top, and height.
- * @param {Item} a          The first item
- * @param {Item} b          The second item
- * @param {Number} margin   A minimum required margin.
- *                          If margin is provided, the two items will be
- *                          marked colliding when they overlap or
- *                          when the margin between the two is smaller than
- *                          the requested margin.
- * @return {boolean}        true if a and b collide, else false
- */
-stack.collision = function(a, b, margin) {
-  return ((a.left - margin) < (b.left + b.width) &&
-      (a.left + a.width + margin) > b.left &&
-      (a.top - margin) < (b.top + b.height) &&
-      (a.top + a.height + margin) > b.top);
-};
-
-/**
- * @constructor  TimeStep
- * The class TimeStep is an iterator for dates. You provide a start date and an
- * end date. The class itself determines the best scale (step size) based on the
- * provided start Date, end Date, and minimumStep.
- *
- * If minimumStep is provided, the step size is chosen as close as possible
- * to the minimumStep but larger than minimumStep. If minimumStep is not
- * provided, the scale is set to 1 DAY.
- * The minimumStep should correspond with the onscreen size of about 6 characters
- *
- * Alternatively, you can set a scale by hand.
- * After creation, you can initialize the class by executing first(). Then you
- * can iterate from the start date to the end date via next(). You can check if
- * the end date is reached with the function hasNext(). After each step, you can
- * retrieve the current date via getCurrent().
- * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours,
- * days, to years.
- *
- * Version: 1.2
- *
- * @param {Date} [start]         The start date, for example new Date(2010, 9, 21)
- *                               or new Date(2010, 9, 21, 23, 45, 00)
- * @param {Date} [end]           The end date
- * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
- */
-function TimeStep(start, end, minimumStep) {
-  // variables
-  this.current = new Date();
-  this._start = new Date();
-  this._end = new Date();
-
-  this.autoScale  = true;
-  this.scale = TimeStep.SCALE.DAY;
-  this.step = 1;
-
-  // initialize the range
-  this.setRange(start, end, minimumStep);
-}
-
-/// enum scale
-TimeStep.SCALE = {
-  MILLISECOND: 1,
-  SECOND: 2,
-  MINUTE: 3,
-  HOUR: 4,
-  DAY: 5,
-  WEEKDAY: 6,
-  MONTH: 7,
-  YEAR: 8
-};
-
-
-/**
- * Set a new range
- * If minimumStep is provided, the step size is chosen as close as possible
- * to the minimumStep but larger than minimumStep. If minimumStep is not
- * provided, the scale is set to 1 DAY.
- * The minimumStep should correspond with the onscreen size of about 6 characters
- * @param {Date} [start]      The start date and time.
- * @param {Date} [end]        The end date and time.
- * @param {int} [minimumStep] Optional. Minimum step size in milliseconds
- */
-TimeStep.prototype.setRange = function(start, end, minimumStep) {
-  if (!(start instanceof Date) || !(end instanceof Date)) {
-    throw  "No legal start or end date in method setRange";
-  }
-
-  this._start = (start != undefined) ? new Date(start.valueOf()) : new Date();
-  this._end = (end != undefined) ? new Date(end.valueOf()) : new Date();
-
-  if (this.autoScale) {
-    this.setMinimumStep(minimumStep);
-  }
-};
-
-/**
- * Set the range iterator to the start date.
- */
-TimeStep.prototype.first = function() {
-  this.current = new Date(this._start.valueOf());
-  this.roundToMinor();
-};
-
-/**
- * Round the current date to the first minor date value
- * This must be executed once when the current date is set to start Date
- */
-TimeStep.prototype.roundToMinor = function() {
-  // round to floor
-  // IMPORTANT: we have no breaks in this switch! (this is no bug)
-  //noinspection FallthroughInSwitchStatementJS
-  switch (this.scale) {
-    case TimeStep.SCALE.YEAR:
-      this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step));
-      this.current.setMonth(0);
-    case TimeStep.SCALE.MONTH:        this.current.setDate(1);
-    case TimeStep.SCALE.DAY:          // intentional fall through
-    case TimeStep.SCALE.WEEKDAY:      this.current.setHours(0);
-    case TimeStep.SCALE.HOUR:         this.current.setMinutes(0);
-    case TimeStep.SCALE.MINUTE:       this.current.setSeconds(0);
-    case TimeStep.SCALE.SECOND:       this.current.setMilliseconds(0);
-    //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds
-  }
-
-  if (this.step != 1) {
-    // round down to the first minor value that is a multiple of the current step size
-    switch (this.scale) {
-      case TimeStep.SCALE.MILLISECOND:  this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step);  break;
-      case TimeStep.SCALE.SECOND:       this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break;
-      case TimeStep.SCALE.MINUTE:       this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break;
-      case TimeStep.SCALE.HOUR:         this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break;
-      case TimeStep.SCALE.WEEKDAY:      // intentional fall through
-      case TimeStep.SCALE.DAY:          this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break;
-      case TimeStep.SCALE.MONTH:        this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step);  break;
-      case TimeStep.SCALE.YEAR:         this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break;
-      default: break;
-    }
-  }
-};
-
-/**
- * Check if the there is a next step
- * @return {boolean}  true if the current date has not passed the end date
- */
-TimeStep.prototype.hasNext = function () {
-  return (this.current.valueOf() <= this._end.valueOf());
-};
-
-/**
- * Do the next step
- */
-TimeStep.prototype.next = function() {
-  var prev = this.current.valueOf();
-
-  // Two cases, needed to prevent issues with switching daylight savings
-  // (end of March and end of October)
-  if (this.current.getMonth() < 6)   {
-    switch (this.scale) {
-      case TimeStep.SCALE.MILLISECOND:
-
-        this.current = new Date(this.current.valueOf() + this.step); break;
-      case TimeStep.SCALE.SECOND:       this.current = new Date(this.current.valueOf() + this.step * 1000); break;
-      case TimeStep.SCALE.MINUTE:       this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break;
-      case TimeStep.SCALE.HOUR:
-        this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60);
-        // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...)
-        var h = this.current.getHours();
-        this.current.setHours(h - (h % this.step));
-        break;
-      case TimeStep.SCALE.WEEKDAY:      // intentional fall through
-      case TimeStep.SCALE.DAY:          this.current.setDate(this.current.getDate() + this.step); break;
-      case TimeStep.SCALE.MONTH:        this.current.setMonth(this.current.getMonth() + this.step); break;
-      case TimeStep.SCALE.YEAR:         this.current.setFullYear(this.current.getFullYear() + this.step); break;
-      default:                      break;
-    }
-  }
-  else {
-    switch (this.scale) {
-      case TimeStep.SCALE.MILLISECOND:  this.current = new Date(this.current.valueOf() + this.step); break;
-      case TimeStep.SCALE.SECOND:       this.current.setSeconds(this.current.getSeconds() + this.step); break;
-      case TimeStep.SCALE.MINUTE:       this.current.setMinutes(this.current.getMinutes() + this.step); break;
-      case TimeStep.SCALE.HOUR:         this.current.setHours(this.current.getHours() + this.step); break;
-      case TimeStep.SCALE.WEEKDAY:      // intentional fall through
-      case TimeStep.SCALE.DAY:          this.current.setDate(this.current.getDate() + this.step); break;
-      case TimeStep.SCALE.MONTH:        this.current.setMonth(this.current.getMonth() + this.step); break;
-      case TimeStep.SCALE.YEAR:         this.current.setFullYear(this.current.getFullYear() + this.step); break;
-      default:                      break;
-    }
-  }
-
-  if (this.step != 1) {
-    // round down to the correct major value
-    switch (this.scale) {
-      case TimeStep.SCALE.MILLISECOND:  if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0);  break;
-      case TimeStep.SCALE.SECOND:       if(this.current.getSeconds() < this.step) this.current.setSeconds(0);  break;
-      case TimeStep.SCALE.MINUTE:       if(this.current.getMinutes() < this.step) this.current.setMinutes(0);  break;
-      case TimeStep.SCALE.HOUR:         if(this.current.getHours() < this.step) this.current.setHours(0);  break;
-      case TimeStep.SCALE.WEEKDAY:      // intentional fall through
-      case TimeStep.SCALE.DAY:          if(this.current.getDate() < this.step+1) this.current.setDate(1); break;
-      case TimeStep.SCALE.MONTH:        if(this.current.getMonth() < this.step) this.current.setMonth(0);  break;
-      case TimeStep.SCALE.YEAR:         break; // nothing to do for year
-      default:                break;
-    }
-  }
-
-  // safety mechanism: if current time is still unchanged, move to the end
-  if (this.current.valueOf() == prev) {
-    this.current = new Date(this._end.valueOf());
-  }
-};
-
-
-/**
- * Get the current datetime
- * @return {Date}  current The current date
- */
-TimeStep.prototype.getCurrent = function() {
-  return this.current;
-};
-
-/**
- * Set a custom scale. Autoscaling will be disabled.
- * For example setScale(SCALE.MINUTES, 5) will result
- * in minor steps of 5 minutes, and major steps of an hour.
- *
- * @param {TimeStep.SCALE} newScale
- *                               A scale. Choose from SCALE.MILLISECOND,
- *                               SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR,
- *                               SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH,
- *                               SCALE.YEAR.
- * @param {Number}     newStep   A step size, by default 1. Choose for
- *                               example 1, 2, 5, or 10.
- */
-TimeStep.prototype.setScale = function(newScale, newStep) {
-  this.scale = newScale;
-
-  if (newStep > 0) {
-    this.step = newStep;
-  }
-
-  this.autoScale = false;
-};
-
-/**
- * Enable or disable autoscaling
- * @param {boolean} enable  If true, autoascaling is set true
- */
-TimeStep.prototype.setAutoScale = function (enable) {
-  this.autoScale = enable;
-};
-
-
-/**
- * Automatically determine the scale that bests fits the provided minimum step
- * @param {Number} [minimumStep]  The minimum step size in milliseconds
- */
-TimeStep.prototype.setMinimumStep = function(minimumStep) {
-  if (minimumStep == undefined) {
-    return;
-  }
-
-  var stepYear       = (1000 * 60 * 60 * 24 * 30 * 12);
-  var stepMonth      = (1000 * 60 * 60 * 24 * 30);
-  var stepDay        = (1000 * 60 * 60 * 24);
-  var stepHour       = (1000 * 60 * 60);
-  var stepMinute     = (1000 * 60);
-  var stepSecond     = (1000);
-  var stepMillisecond= (1);
-
-  // find the smallest step that is larger than the provided minimumStep
-  if (stepYear*1000 > minimumStep)        {this.scale = TimeStep.SCALE.YEAR;        this.step = 1000;}
-  if (stepYear*500 > minimumStep)         {this.scale = TimeStep.SCALE.YEAR;        this.step = 500;}
-  if (stepYear*100 > minimumStep)         {this.scale = TimeStep.SCALE.YEAR;        this.step = 100;}
-  if (stepYear*50 > minimumStep)          {this.scale = TimeStep.SCALE.YEAR;        this.step = 50;}
-  if (stepYear*10 > minimumStep)          {this.scale = TimeStep.SCALE.YEAR;        this.step = 10;}
-  if (stepYear*5 > minimumStep)           {this.scale = TimeStep.SCALE.YEAR;        this.step = 5;}
-  if (stepYear > minimumStep)             {this.scale = TimeStep.SCALE.YEAR;        this.step = 1;}
-  if (stepMonth*3 > minimumStep)          {this.scale = TimeStep.SCALE.MONTH;       this.step = 3;}
-  if (stepMonth > minimumStep)            {this.scale = TimeStep.SCALE.MONTH;       this.step = 1;}
-  if (stepDay*5 > minimumStep)            {this.scale = TimeStep.SCALE.DAY;         this.step = 5;}
-  if (stepDay*2 > minimumStep)            {this.scale = TimeStep.SCALE.DAY;         this.step = 2;}
-  if (stepDay > minimumStep)              {this.scale = TimeStep.SCALE.DAY;         this.step = 1;}
-  if (stepDay/2 > minimumStep)            {this.scale = TimeStep.SCALE.WEEKDAY;     this.step = 1;}
-  if (stepHour*4 > minimumStep)           {this.scale = TimeStep.SCALE.HOUR;        this.step = 4;}
-  if (stepHour > minimumStep)             {this.scale = TimeStep.SCALE.HOUR;        this.step = 1;}
-  if (stepMinute*15 > minimumStep)        {this.scale = TimeStep.SCALE.MINUTE;      this.step = 15;}
-  if (stepMinute*10 > minimumStep)        {this.scale = TimeStep.SCALE.MINUTE;      this.step = 10;}
-  if (stepMinute*5 > minimumStep)         {this.scale = TimeStep.SCALE.MINUTE;      this.step = 5;}
-  if (stepMinute > minimumStep)           {this.scale = TimeStep.SCALE.MINUTE;      this.step = 1;}
-  if (stepSecond*15 > minimumStep)        {this.scale = TimeStep.SCALE.SECOND;      this.step = 15;}
-  if (stepSecond*10 > minimumStep)        {this.scale = TimeStep.SCALE.SECOND;      this.step = 10;}
-  if (stepSecond*5 > minimumStep)         {this.scale = TimeStep.SCALE.SECOND;      this.step = 5;}
-  if (stepSecond > minimumStep)           {this.scale = TimeStep.SCALE.SECOND;      this.step = 1;}
-  if (stepMillisecond*200 > minimumStep)  {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;}
-  if (stepMillisecond*100 > minimumStep)  {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;}
-  if (stepMillisecond*50 > minimumStep)   {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;}
-  if (stepMillisecond*10 > minimumStep)   {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;}
-  if (stepMillisecond*5 > minimumStep)    {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;}
-  if (stepMillisecond > minimumStep)      {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;}
-};
-
-/**
- * Snap a date to a rounded value.
- * The snap intervals are dependent on the current scale and step.
- * @param {Date} date   the date to be snapped.
- * @return {Date} snappedDate
- */
-TimeStep.prototype.snap = function(date) {
-  var clone = new Date(date.valueOf());
-
-  if (this.scale == TimeStep.SCALE.YEAR) {
-    var year = clone.getFullYear() + Math.round(clone.getMonth() / 12);
-    clone.setFullYear(Math.round(year / this.step) * this.step);
-    clone.setMonth(0);
-    clone.setDate(0);
-    clone.setHours(0);
-    clone.setMinutes(0);
-    clone.setSeconds(0);
-    clone.setMilliseconds(0);
-  }
-  else if (this.scale == TimeStep.SCALE.MONTH) {
-    if (clone.getDate() > 15) {
-      clone.setDate(1);
-      clone.setMonth(clone.getMonth() + 1);
-      // important: first set Date to 1, after that change the month.
-    }
-    else {
-      clone.setDate(1);
-    }
-
-    clone.setHours(0);
-    clone.setMinutes(0);
-    clone.setSeconds(0);
-    clone.setMilliseconds(0);
-  }
-  else if (this.scale == TimeStep.SCALE.DAY) {
-    //noinspection FallthroughInSwitchStatementJS
-    switch (this.step) {
-      case 5:
-      case 2:
-        clone.setHours(Math.round(clone.getHours() / 24) * 24); break;
-      default:
-        clone.setHours(Math.round(clone.getHours() / 12) * 12); break;
-    }
-    clone.setMinutes(0);
-    clone.setSeconds(0);
-    clone.setMilliseconds(0);
-  }
-  else if (this.scale == TimeStep.SCALE.WEEKDAY) {
-    //noinspection FallthroughInSwitchStatementJS
-    switch (this.step) {
-      case 5:
-      case 2:
-        clone.setHours(Math.round(clone.getHours() / 12) * 12); break;
-      default:
-        clone.setHours(Math.round(clone.getHours() / 6) * 6); break;
-    }
-    clone.setMinutes(0);
-    clone.setSeconds(0);
-    clone.setMilliseconds(0);
-  }
-  else if (this.scale == TimeStep.SCALE.HOUR) {
-    switch (this.step) {
-      case 4:
-        clone.setMinutes(Math.round(clone.getMinutes() / 60) * 60); break;
-      default:
-        clone.setMinutes(Math.round(clone.getMinutes() / 30) * 30); break;
-    }
-    clone.setSeconds(0);
-    clone.setMilliseconds(0);
-  } else if (this.scale == TimeStep.SCALE.MINUTE) {
-    //noinspection FallthroughInSwitchStatementJS
-    switch (this.step) {
-      case 15:
-      case 10:
-        clone.setMinutes(Math.round(clone.getMinutes() / 5) * 5);
-        clone.setSeconds(0);
-        break;
-      case 5:
-        clone.setSeconds(Math.round(clone.getSeconds() / 60) * 60); break;
-      default:
-        clone.setSeconds(Math.round(clone.getSeconds() / 30) * 30); break;
-    }
-    clone.setMilliseconds(0);
-  }
-  else if (this.scale == TimeStep.SCALE.SECOND) {
-    //noinspection FallthroughInSwitchStatementJS
-    switch (this.step) {
-      case 15:
-      case 10:
-        clone.setSeconds(Math.round(clone.getSeconds() / 5) * 5);
-        clone.setMilliseconds(0);
-        break;
-      case 5:
-        clone.setMilliseconds(Math.round(clone.getMilliseconds() / 1000) * 1000); break;
-      default:
-        clone.setMilliseconds(Math.round(clone.getMilliseconds() / 500) * 500); break;
-    }
-  }
-  else if (this.scale == TimeStep.SCALE.MILLISECOND) {
-    var step = this.step > 5 ? this.step / 2 : 1;
-    clone.setMilliseconds(Math.round(clone.getMilliseconds() / step) * step);
-  }
-  
-  return clone;
-};
-
-/**
- * Check if the current value is a major value (for example when the step
- * is DAY, a major value is each first day of the MONTH)
- * @return {boolean} true if current date is major, else false.
- */
-TimeStep.prototype.isMajor = function() {
-  switch (this.scale) {
-    case TimeStep.SCALE.MILLISECOND:
-      return (this.current.getMilliseconds() == 0);
-    case TimeStep.SCALE.SECOND:
-      return (this.current.getSeconds() == 0);
-    case TimeStep.SCALE.MINUTE:
-      return (this.current.getHours() == 0) && (this.current.getMinutes() == 0);
-    // Note: this is no bug. Major label is equal for both minute and hour scale
-    case TimeStep.SCALE.HOUR:
-      return (this.current.getHours() == 0);
-    case TimeStep.SCALE.WEEKDAY: // intentional fall through
-    case TimeStep.SCALE.DAY:
-      return (this.current.getDate() == 1);
-    case TimeStep.SCALE.MONTH:
-      return (this.current.getMonth() == 0);
-    case TimeStep.SCALE.YEAR:
-      return false;
-    default:
-      return false;
-  }
-};
-
-
-/**
- * Returns formatted text for the minor axislabel, depending on the current
- * date and the scale. For example when scale is MINUTE, the current time is
- * formatted as "hh:mm".
- * @param {Date} [date] custom date. if not provided, current date is taken
- */
-TimeStep.prototype.getLabelMinor = function(date) {
-  if (date == undefined) {
-    date = this.current;
-  }
-
-  switch (this.scale) {
-    case TimeStep.SCALE.MILLISECOND:  return moment(date).format('SSS');
-    case TimeStep.SCALE.SECOND:       return moment(date).format('s');
-    case TimeStep.SCALE.MINUTE:       return moment(date).format('HH:mm');
-    case TimeStep.SCALE.HOUR:         return moment(date).format('HH:mm');
-    case TimeStep.SCALE.WEEKDAY:      return moment(date).format('ddd D');
-    case TimeStep.SCALE.DAY:          return moment(date).format('D');
-    case TimeStep.SCALE.MONTH:        return moment(date).format('MMM');
-    case TimeStep.SCALE.YEAR:         return moment(date).format('YYYY');
-    default:                          return '';
-  }
-};
-
-
-/**
- * Returns formatted text for the major axis label, depending on the current
- * date and the scale. For example when scale is MINUTE, the major scale is
- * hours, and the hour will be formatted as "hh".
- * @param {Date} [date] custom date. if not provided, current date is taken
- */
-TimeStep.prototype.getLabelMajor = function(date) {
-  if (date == undefined) {
-    date = this.current;
-  }
-
-  //noinspection FallthroughInSwitchStatementJS
-  switch (this.scale) {
-    case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss');
-    case TimeStep.SCALE.SECOND:     return moment(date).format('D MMMM HH:mm');
-    case TimeStep.SCALE.MINUTE:
-    case TimeStep.SCALE.HOUR:       return moment(date).format('ddd D MMMM');
-    case TimeStep.SCALE.WEEKDAY:
-    case TimeStep.SCALE.DAY:        return moment(date).format('MMMM YYYY');
-    case TimeStep.SCALE.MONTH:      return moment(date).format('YYYY');
-    case TimeStep.SCALE.YEAR:       return '';
-    default:                        return '';
-  }
-};
-
-/**
- * @constructor Range
- * A Range controls a numeric range with a start and end value.
- * The Range adjusts the range based on mouse events or programmatic changes,
- * and triggers events when the range is changing or has been changed.
- * @param {{dom: Object, domProps: Object, emitter: Emitter}} body
- * @param {Object} [options]    See description at Range.setOptions
- */
-function Range(body, options) {
-  var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0);
-  this.start = now.clone().add('days', -3).valueOf(); // Number
-  this.end = now.clone().add('days', 4).valueOf();   // Number
-
-  this.body = body;
-
-  // default options
-  this.defaultOptions = {
-    start: null,
-    end: null,
-    direction: 'horizontal', // 'horizontal' or 'vertical'
-    moveable: true,
-    zoomable: true,
-    min: null,
-    max: null,
-    zoomMin: 10,                                // milliseconds
-    zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000  // milliseconds
-  };
-  this.options = util.extend({}, this.defaultOptions);
-
-  this.props = {
-    touch: {}
-  };
-
-  // drag listeners for dragging
-  this.body.emitter.on('dragstart', this._onDragStart.bind(this));
-  this.body.emitter.on('drag',      this._onDrag.bind(this));
-  this.body.emitter.on('dragend',   this._onDragEnd.bind(this));
-
-  // ignore dragging when holding
-  this.body.emitter.on('hold', this._onHold.bind(this));
-
-  // mouse wheel for zooming
-  this.body.emitter.on('mousewheel',      this._onMouseWheel.bind(this));
-  this.body.emitter.on('DOMMouseScroll',  this._onMouseWheel.bind(this)); // For FF
-
-  // pinch to zoom
-  this.body.emitter.on('touch', this._onTouch.bind(this));
-  this.body.emitter.on('pinch', this._onPinch.bind(this));
-
-  this.setOptions(options);
-}
-
-Range.prototype = new Component();
-
-/**
- * Set options for the range controller
- * @param {Object} options      Available options:
- *                              {Number | Date | String} start  Start date for the range
- *                              {Number | Date | String} end    End date for the range
- *                              {Number} min    Minimum value for start
- *                              {Number} max    Maximum value for end
- *                              {Number} zoomMin    Set a minimum value for
- *                                                  (end - start).
- *                              {Number} zoomMax    Set a maximum value for
- *                                                  (end - start).
- *                              {Boolean} moveable Enable moving of the range
- *                                                 by dragging. True by default
- *                              {Boolean} zoomable Enable zooming of the range
- *                                                 by pinching/scrolling. True by default
- */
-Range.prototype.setOptions = function (options) {
-  if (options) {
-    // copy the options that we know
-    var fields = ['direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable'];
-    util.selectiveExtend(fields, this.options, options);
-
-    if ('start' in options || 'end' in options) {
-      // apply a new range. both start and end are optional
-      this.setRange(options.start, options.end);
-    }
-  }
-};
-
-/**
- * Test whether direction has a valid value
- * @param {String} direction    'horizontal' or 'vertical'
- */
-function validateDirection (direction) {
-  if (direction != 'horizontal' && direction != 'vertical') {
-    throw new TypeError('Unknown direction "' + direction + '". ' +
-        'Choose "horizontal" or "vertical".');
-  }
-}
-
-/**
- * Set a new start and end range
- * @param {Number} [start]
- * @param {Number} [end]
- */
-Range.prototype.setRange = function(start, end) {
-  var changed = this._applyRange(start, end);
-  if (changed) {
-    var params = {
-      start: new Date(this.start),
-      end: new Date(this.end)
-    };
-    this.body.emitter.emit('rangechange', params);
-    this.body.emitter.emit('rangechanged', params);
-  }
-};
-
-/**
- * Set a new start and end range. This method is the same as setRange, but
- * does not trigger a range change and range changed event, and it returns
- * true when the range is changed
- * @param {Number} [start]
- * @param {Number} [end]
- * @return {Boolean} changed
- * @private
- */
-Range.prototype._applyRange = function(start, end) {
-  var newStart = (start != null) ? util.convert(start, 'Date').valueOf() : this.start,
-      newEnd   = (end != null)   ? util.convert(end, 'Date').valueOf()   : this.end,
-      max = (this.options.max != null) ? util.convert(this.options.max, 'Date').valueOf() : null,
-      min = (this.options.min != null) ? util.convert(this.options.min, 'Date').valueOf() : null,
-      diff;
-
-  // check for valid number
-  if (isNaN(newStart) || newStart === null) {
-    throw new Error('Invalid start "' + start + '"');
-  }
-  if (isNaN(newEnd) || newEnd === null) {
-    throw new Error('Invalid end "' + end + '"');
-  }
-
-  // prevent start < end
-  if (newEnd < newStart) {
-    newEnd = newStart;
-  }
-
-  // prevent start < min
-  if (min !== null) {
-    if (newStart < min) {
-      diff = (min - newStart);
-      newStart += diff;
-      newEnd += diff;
-
-      // prevent end > max
-      if (max != null) {
-        if (newEnd > max) {
-          newEnd = max;
-        }
-      }
-    }
-  }
-
-  // prevent end > max
-  if (max !== null) {
-    if (newEnd > max) {
-      diff = (newEnd - max);
-      newStart -= diff;
-      newEnd -= diff;
-
-      // prevent start < min
-      if (min != null) {
-        if (newStart < min) {
-          newStart = min;
-        }
-      }
-    }
-  }
-
-  // prevent (end-start) < zoomMin
-  if (this.options.zoomMin !== null) {
-    var zoomMin = parseFloat(this.options.zoomMin);
-    if (zoomMin < 0) {
-      zoomMin = 0;
-    }
-    if ((newEnd - newStart) < zoomMin) {
-      if ((this.end - this.start) === zoomMin) {
-        // ignore this action, we are already zoomed to the minimum
-        newStart = this.start;
-        newEnd = this.end;
-      }
-      else {
-        // zoom to the minimum
-        diff = (zoomMin - (newEnd - newStart));
-        newStart -= diff / 2;
-        newEnd += diff / 2;
-      }
-    }
-  }
-
-  // prevent (end-start) > zoomMax
-  if (this.options.zoomMax !== null) {
-    var zoomMax = parseFloat(this.options.zoomMax);
-    if (zoomMax < 0) {
-      zoomMax = 0;
-    }
-    if ((newEnd - newStart) > zoomMax) {
-      if ((this.end - this.start) === zoomMax) {
-        // ignore this action, we are already zoomed to the maximum
-        newStart = this.start;
-        newEnd = this.end;
-      }
-      else {
-        // zoom to the maximum
-        diff = ((newEnd - newStart) - zoomMax);
-        newStart += diff / 2;
-        newEnd -= diff / 2;
-      }
-    }
-  }
-
-  var changed = (this.start != newStart || this.end != newEnd);
-
-  this.start = newStart;
-  this.end = newEnd;
-
-  return changed;
-};
-
-/**
- * Retrieve the current range.
- * @return {Object} An object with start and end properties
- */
-Range.prototype.getRange = function() {
-  return {
-    start: this.start,
-    end: this.end
-  };
-};
-
-/**
- * Calculate the conversion offset and scale for current range, based on
- * the provided width
- * @param {Number} width
- * @returns {{offset: number, scale: number}} conversion
- */
-Range.prototype.conversion = function (width) {
-  return Range.conversion(this.start, this.end, width);
-};
-
-/**
- * Static method to calculate the conversion offset and scale for a range,
- * based on the provided start, end, and width
- * @param {Number} start
- * @param {Number} end
- * @param {Number} width
- * @returns {{offset: number, scale: number}} conversion
- */
-Range.conversion = function (start, end, width) {
-  if (width != 0 && (end - start != 0)) {
-    return {
-      offset: start,
-      scale: width / (end - start)
-    }
-  }
-  else {
-    return {
-      offset: 0,
-      scale: 1
-    };
-  }
-};
-
-/**
- * Start dragging horizontally or vertically
- * @param {Event} event
- * @private
- */
-Range.prototype._onDragStart = function(event) {
-  // only allow dragging when configured as movable
-  if (!this.options.moveable) return;
-
-  // refuse to drag when we where pinching to prevent the timeline make a jump
-  // when releasing the fingers in opposite order from the touch screen
-  if (!this.props.touch.allowDragging) return;
-
-  this.props.touch.start = this.start;
-  this.props.touch.end = this.end;
-
-  if (this.body.dom.root) {
-    this.body.dom.root.style.cursor = 'move';
-  }
-};
-
-/**
- * Perform dragging operation
- * @param {Event} event
- * @private
- */
-Range.prototype._onDrag = function (event) {
-  // only allow dragging when configured as movable
-  if (!this.options.moveable) return;
-
-  var direction = this.options.direction;
-  validateDirection(direction);
-
-  // refuse to drag when we where pinching to prevent the timeline make a jump
-  // when releasing the fingers in opposite order from the touch screen
-  if (!this.props.touch.allowDragging) return;
-
-  var delta = (direction == 'horizontal') ? event.gesture.deltaX : event.gesture.deltaY,
-      interval = (this.props.touch.end - this.props.touch.start),
-      width = (direction == 'horizontal') ? this.body.domProps.center.width : this.body.domProps.center.height,
-      diffRange = -delta / width * interval;
-
-  this._applyRange(this.props.touch.start + diffRange, this.props.touch.end + diffRange);
-
-  this.body.emitter.emit('rangechange', {
-    start: new Date(this.start),
-    end:   new Date(this.end)
-  });
-};
-
-/**
- * Stop dragging operation
- * @param {event} event
- * @private
- */
-Range.prototype._onDragEnd = function (event) {
-  // only allow dragging when configured as movable
-  if (!this.options.moveable) return;
-
-  // refuse to drag when we where pinching to prevent the timeline make a jump
-  // when releasing the fingers in opposite order from the touch screen
-  if (!this.props.touch.allowDragging) return;
-
-  if (this.body.dom.root) {
-    this.body.dom.root.style.cursor = 'auto';
-  }
-
-  // fire a rangechanged event
-  this.body.emitter.emit('rangechanged', {
-    start: new Date(this.start),
-    end:   new Date(this.end)
-  });
-};
-
-/**
- * Event handler for mouse wheel event, used to zoom
- * Code from http://adomas.org/javascript-mouse-wheel/
- * @param {Event} event
- * @private
- */
-Range.prototype._onMouseWheel = function(event) {
-  // only allow zooming when configured as zoomable and moveable
-  if (!(this.options.zoomable && this.options.moveable)) return;
-
-  // retrieve delta
-  var delta = 0;
-  if (event.wheelDelta) { /* IE/Opera. */
-    delta = event.wheelDelta / 120;
-  } else if (event.detail) { /* Mozilla case. */
-    // In Mozilla, sign of delta is different than in IE.
-    // Also, delta is multiple of 3.
-    delta = -event.detail / 3;
-  }
-
-  // If delta is nonzero, handle it.
-  // Basically, delta is now positive if wheel was scrolled up,
-  // and negative, if wheel was scrolled down.
-  if (delta) {
-    // perform the zoom action. Delta is normally 1 or -1
-
-    // adjust a negative delta such that zooming in with delta 0.1
-    // equals zooming out with a delta -0.1
-    var scale;
-    if (delta < 0) {
-      scale = 1 - (delta / 5);
-    }
-    else {
-      scale = 1 / (1 + (delta / 5)) ;
-    }
-
-    // calculate center, the date to zoom around
-    var gesture = util.fakeGesture(this, event),
-        pointer = getPointer(gesture.center, this.body.dom.center),
-        pointerDate = this._pointerToDate(pointer);
-
-    this.zoom(scale, pointerDate);
-  }
-
-  // Prevent default actions caused by mouse wheel
-  // (else the page and timeline both zoom and scroll)
-  event.preventDefault();
-};
-
-/**
- * Start of a touch gesture
- * @private
- */
-Range.prototype._onTouch = function (event) {
-  this.props.touch.start = this.start;
-  this.props.touch.end = this.end;
-  this.props.touch.allowDragging = true;
-  this.props.touch.center = null;
-};
-
-/**
- * On start of a hold gesture
- * @private
- */
-Range.prototype._onHold = function () {
-  this.props.touch.allowDragging = false;
-};
-
-/**
- * Handle pinch event
- * @param {Event} event
- * @private
- */
-Range.prototype._onPinch = function (event) {
-  // only allow zooming when configured as zoomable and moveable
-  if (!(this.options.zoomable && this.options.moveable)) return;
-
-  this.props.touch.allowDragging = false;
-
-  if (event.gesture.touches.length > 1) {
-    if (!this.props.touch.center) {
-      this.props.touch.center = getPointer(event.gesture.center, this.body.dom.center);
-    }
-
-    var scale = 1 / event.gesture.scale,
-        initDate = this._pointerToDate(this.props.touch.center);
-
-    // calculate new start and end
-    var newStart = parseInt(initDate + (this.props.touch.start - initDate) * scale);
-    var newEnd = parseInt(initDate + (this.props.touch.end - initDate) * scale);
-
-    // apply new range
-    this.setRange(newStart, newEnd);
-  }
-};
-
-/**
- * Helper function to calculate the center date for zooming
- * @param {{x: Number, y: Number}} pointer
- * @return {number} date
- * @private
- */
-Range.prototype._pointerToDate = function (pointer) {
-  var conversion;
-  var direction = this.options.direction;
-
-  validateDirection(direction);
-
-  if (direction == 'horizontal') {
-    var width = this.body.domProps.center.width;
-    conversion = this.conversion(width);
-    return pointer.x / conversion.scale + conversion.offset;
-  }
-  else {
-    var height = this.body.domProps.center.height;
-    conversion = this.conversion(height);
-    return pointer.y / conversion.scale + conversion.offset;
-  }
-};
-
-/**
- * Get the pointer location relative to the location of the dom element
- * @param {{pageX: Number, pageY: Number}} touch
- * @param {Element} element   HTML DOM element
- * @return {{x: Number, y: Number}} pointer
- * @private
- */
-function getPointer (touch, element) {
-  return {
-    x: touch.pageX - vis.util.getAbsoluteLeft(element),
-    y: touch.pageY - vis.util.getAbsoluteTop(element)
-  };
-}
-
-/**
- * Zoom the range the given scale in or out. Start and end date will
- * be adjusted, and the timeline will be redrawn. You can optionally give a
- * date around which to zoom.
- * For example, try scale = 0.9 or 1.1
- * @param {Number} scale      Scaling factor. Values above 1 will zoom out,
- *                            values below 1 will zoom in.
- * @param {Number} [center]   Value representing a date around which will
- *                            be zoomed.
- */
-Range.prototype.zoom = function(scale, center) {
-  // if centerDate is not provided, take it half between start Date and end Date
-  if (center == null) {
-    center = (this.start + this.end) / 2;
-  }
-
-  // calculate new start and end
-  var newStart = center + (this.start - center) * scale;
-  var newEnd = center + (this.end - center) * scale;
-
-  this.setRange(newStart, newEnd);
-};
-
-/**
- * Move the range with a given delta to the left or right. Start and end
- * value will be adjusted. For example, try delta = 0.1 or -0.1
- * @param {Number}  delta     Moving amount. Positive value will move right,
- *                            negative value will move left
- */
-Range.prototype.move = function(delta) {
-  // zoom start Date and end Date relative to the centerDate
-  var diff = (this.end - this.start);
-
-  // apply new values
-  var newStart = this.start + diff * delta;
-  var newEnd = this.end + diff * delta;
-
-  // TODO: reckon with min and max range
-
-  this.start = newStart;
-  this.end = newEnd;
-};
-
-/**
- * Move the range to a new center point
- * @param {Number} moveTo      New center point of the range
- */
-Range.prototype.moveTo = function(moveTo) {
-  var center = (this.start + this.end) / 2;
-
-  var diff = center - moveTo;
-
-  // calculate new start and end
-  var newStart = this.start - diff;
-  var newEnd = this.end - diff;
-
-  this.setRange(newStart, newEnd);
-};
-
-/**
- * Prototype for visual components
- * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} [body]
- * @param {Object} [options]
- */
-function Component (body, options) {
-  this.options = null;
-  this.props = null;
-}
-
-/**
- * Set options for the component. The new options will be merged into the
- * current options.
- * @param {Object} options
- */
-Component.prototype.setOptions = function(options) {
-  if (options) {
-    util.extend(this.options, options);
-  }
-};
-
-/**
- * Repaint the component
- * @return {boolean} Returns true if the component is resized
- */
-Component.prototype.redraw = function() {
-  // should be implemented by the component
-  return false;
-};
-
-/**
- * Destroy the component. Cleanup DOM and event listeners
- */
-Component.prototype.destroy = function() {
-  // should be implemented by the component
-};
-
-/**
- * Test whether the component is resized since the last time _isResized() was
- * called.
- * @return {Boolean} Returns true if the component is resized
- * @protected
- */
-Component.prototype._isResized = function() {
-  var resized = (this.props._previousWidth !== this.props.width ||
-      this.props._previousHeight !== this.props.height);
-
-  this.props._previousWidth = this.props.width;
-  this.props._previousHeight = this.props.height;
-
-  return resized;
-};
-
-/**
- * A horizontal time axis
- * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body
- * @param {Object} [options]        See TimeAxis.setOptions for the available
- *                                  options.
- * @constructor TimeAxis
- * @extends Component
- */
-function TimeAxis (body, options) {
-  this.dom = {
-    foreground: null,
-    majorLines: [],
-    majorTexts: [],
-    minorLines: [],
-    minorTexts: [],
-    redundant: {
-      majorLines: [],
-      majorTexts: [],
-      minorLines: [],
-      minorTexts: []
-    }
-  };
-  this.props = {
-    range: {
-      start: 0,
-      end: 0,
-      minimumStep: 0
-    },
-    lineTop: 0
-  };
-
-  this.defaultOptions = {
-    orientation: 'bottom',  // supported: 'top', 'bottom'
-    // TODO: implement timeaxis orientations 'left' and 'right'
-    showMinorLabels: true,
-    showMajorLabels: true
-  };
-  this.options = util.extend({}, this.defaultOptions);
-
-  this.body = body;
-
-  // create the HTML DOM
-  this._create();
-
-  this.setOptions(options);
-}
-
-TimeAxis.prototype = new Component();
-
-/**
- * Set options for the TimeAxis.
- * Parameters will be merged in current options.
- * @param {Object} options  Available options:
- *                          {string} [orientation]
- *                          {boolean} [showMinorLabels]
- *                          {boolean} [showMajorLabels]
- */
-TimeAxis.prototype.setOptions = function(options) {
-  if (options) {
-    // copy all options that we know
-    util.selectiveExtend(['orientation', 'showMinorLabels', 'showMajorLabels'], this.options, options);
-  }
-};
-
-/**
- * Create the HTML DOM for the TimeAxis
- */
-TimeAxis.prototype._create = function() {
-  this.dom.foreground = document.createElement('div');
-  this.dom.background = document.createElement('div');
-
-  this.dom.foreground.className = 'timeaxis foreground';
-  this.dom.background.className = 'timeaxis background';
-};
-
-/**
- * Destroy the TimeAxis
- */
-TimeAxis.prototype.destroy = function() {
-  // remove from DOM
-  if (this.dom.foreground.parentNode) {
-    this.dom.foreground.parentNode.removeChild(this.dom.foreground);
-  }
-  if (this.dom.background.parentNode) {
-    this.dom.background.parentNode.removeChild(this.dom.background);
-  }
-
-  this.body = null;
-};
-
-/**
- * Repaint the component
- * @return {boolean} Returns true if the component is resized
- */
-TimeAxis.prototype.redraw = function () {
-  var options = this.options,
-      props = this.props,
-      foreground = this.dom.foreground,
-      background = this.dom.background;
-
-  // determine the correct parent DOM element (depending on option orientation)
-  var parent = (options.orientation == 'top') ? this.body.dom.top : this.body.dom.bottom;
-  var parentChanged = (foreground.parentNode !== parent);
-
-  // calculate character width and height
-  this._calculateCharSize();
-
-  // TODO: recalculate sizes only needed when parent is resized or options is changed
-  var orientation = this.options.orientation,
-      showMinorLabels = this.options.showMinorLabels,
-      showMajorLabels = this.options.showMajorLabels;
-
-  // determine the width and height of the elemens for the axis
-  props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
-  props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
-  props.height = props.minorLabelHeight + props.majorLabelHeight;
-  props.width = foreground.offsetWidth;
-
-  props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight -
-      (options.orientation == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height);
-  props.minorLineWidth = 1; // TODO: really calculate width
-  props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight;
-  props.majorLineWidth = 1; // TODO: really calculate width
-
-  //  take foreground and background offline while updating (is almost twice as fast)
-  var foregroundNextSibling = foreground.nextSibling;
-  var backgroundNextSibling = background.nextSibling;
-  foreground.parentNode && foreground.parentNode.removeChild(foreground);
-  background.parentNode && background.parentNode.removeChild(background);
-
-  foreground.style.height = this.props.height + 'px';
-
-  this._repaintLabels();
-
-  // put DOM online again (at the same place)
-  if (foregroundNextSibling) {
-    parent.insertBefore(foreground, foregroundNextSibling);
-  }
-  else {
-    parent.appendChild(foreground)
-  }
-  if (backgroundNextSibling) {
-    this.body.dom.backgroundVertical.insertBefore(background, backgroundNextSibling);
-  }
-  else {
-    this.body.dom.backgroundVertical.appendChild(background)
-  }
-
-  return this._isResized() || parentChanged;
-};
-
-/**
- * Repaint major and minor text labels and vertical grid lines
- * @private
- */
-TimeAxis.prototype._repaintLabels = function () {
-  var orientation = this.options.orientation;
-
-  // calculate range and step (step such that we have space for 7 characters per label)
-  var start = util.convert(this.body.range.start, 'Number'),
-      end = util.convert(this.body.range.end, 'Number'),
-      minimumStep = this.body.util.toTime((this.props.minorCharWidth || 10) * 7).valueOf()
-          -this.body.util.toTime(0).valueOf();
-  var step = new TimeStep(new Date(start), new Date(end), minimumStep);
-  this.step = step;
-
-  // Move all DOM elements to a "redundant" list, where they
-  // can be picked for re-use, and clear the lists with lines and texts.
-  // At the end of the function _repaintLabels, left over elements will be cleaned up
-  var dom = this.dom;
-  dom.redundant.majorLines = dom.majorLines;
-  dom.redundant.majorTexts = dom.majorTexts;
-  dom.redundant.minorLines = dom.minorLines;
-  dom.redundant.minorTexts = dom.minorTexts;
-  dom.majorLines = [];
-  dom.majorTexts = [];
-  dom.minorLines = [];
-  dom.minorTexts = [];
-
-  step.first();
-  var xFirstMajorLabel = undefined;
-  var max = 0;
-  while (step.hasNext() && max < 1000) {
-    max++;
-    var cur = step.getCurrent(),
-        x = this.body.util.toScreen(cur),
-        isMajor = step.isMajor();
-
-    // TODO: lines must have a width, such that we can create css backgrounds
-
-    if (this.options.showMinorLabels) {
-      this._repaintMinorText(x, step.getLabelMinor(), orientation);
-    }
-
-    if (isMajor && this.options.showMajorLabels) {
-      if (x > 0) {
-        if (xFirstMajorLabel == undefined) {
-          xFirstMajorLabel = x;
-        }
-        this._repaintMajorText(x, step.getLabelMajor(), orientation);
-      }
-      this._repaintMajorLine(x, orientation);
-    }
-    else {
-      this._repaintMinorLine(x, orientation);
-    }
-
-    step.next();
-  }
-
-  // create a major label on the left when needed
-  if (this.options.showMajorLabels) {
-    var leftTime = this.body.util.toTime(0),
-        leftText = step.getLabelMajor(leftTime),
-        widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation
-
-    if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) {
-      this._repaintMajorText(0, leftText, orientation);
-    }
-  }
-
-  // Cleanup leftover DOM elements from the redundant list
-  util.forEach(this.dom.redundant, function (arr) {
-    while (arr.length) {
-      var elem = arr.pop();
-      if (elem && elem.parentNode) {
-        elem.parentNode.removeChild(elem);
-      }
-    }
-  });
-};
-
-/**
- * Create a minor label for the axis at position x
- * @param {Number} x
- * @param {String} text
- * @param {String} orientation   "top" or "bottom" (default)
- * @private
- */
-TimeAxis.prototype._repaintMinorText = function (x, text, orientation) {
-  // reuse redundant label
-  var label = this.dom.redundant.minorTexts.shift();
-
-  if (!label) {
-    // create new label
-    var content = document.createTextNode('');
-    label = document.createElement('div');
-    label.appendChild(content);
-    label.className = 'text minor';
-    this.dom.foreground.appendChild(label);
-  }
-  this.dom.minorTexts.push(label);
-
-  label.childNodes[0].nodeValue = text;
-
-  label.style.top = (orientation == 'top') ? (this.props.majorLabelHeight + 'px') : '0';
-  label.style.left = x + 'px';
-  //label.title = title;  // TODO: this is a heavy operation
-};
-
-/**
- * Create a Major label for the axis at position x
- * @param {Number} x
- * @param {String} text
- * @param {String} orientation   "top" or "bottom" (default)
- * @private
- */
-TimeAxis.prototype._repaintMajorText = function (x, text, orientation) {
-  // reuse redundant label
-  var label = this.dom.redundant.majorTexts.shift();
-
-  if (!label) {
-    // create label
-    var content = document.createTextNode(text);
-    label = document.createElement('div');
-    label.className = 'text major';
-    label.appendChild(content);
-    this.dom.foreground.appendChild(label);
-  }
-  this.dom.majorTexts.push(label);
-
-  label.childNodes[0].nodeValue = text;
-  //label.title = title; // TODO: this is a heavy operation
-
-  label.style.top = (orientation == 'top') ? '0' : (this.props.minorLabelHeight  + 'px');
-  label.style.left = x + 'px';
-};
-
-/**
- * Create a minor line for the axis at position x
- * @param {Number} x
- * @param {String} orientation   "top" or "bottom" (default)
- * @private
- */
-TimeAxis.prototype._repaintMinorLine = function (x, orientation) {
-  // reuse redundant line
-  var line = this.dom.redundant.minorLines.shift();
-
-  if (!line) {
-    // create vertical line
-    line = document.createElement('div');
-    line.className = 'grid vertical minor';
-    this.dom.background.appendChild(line);
-  }
-  this.dom.minorLines.push(line);
-
-  var props = this.props;
-  if (orientation == 'top') {
-    line.style.top = props.majorLabelHeight + 'px';
-  }
-  else {
-    line.style.top = this.body.domProps.top.height + 'px';
-  }
-  line.style.height = props.minorLineHeight + 'px';
-  line.style.left = (x - props.minorLineWidth / 2) + 'px';
-};
-
-/**
- * Create a Major line for the axis at position x
- * @param {Number} x
- * @param {String} orientation   "top" or "bottom" (default)
- * @private
- */
-TimeAxis.prototype._repaintMajorLine = function (x, orientation) {
-  // reuse redundant line
-  var line = this.dom.redundant.majorLines.shift();
-
-  if (!line) {
-    // create vertical line
-    line = document.createElement('DIV');
-    line.className = 'grid vertical major';
-    this.dom.background.appendChild(line);
-  }
-  this.dom.majorLines.push(line);
-
-  var props = this.props;
-  if (orientation == 'top') {
-    line.style.top = '0';
-  }
-  else {
-    line.style.top = this.body.domProps.top.height + 'px';
-  }
-  line.style.left = (x - props.majorLineWidth / 2) + 'px';
-  line.style.height = props.majorLineHeight + 'px';
-};
-
-/**
- * Determine the size of text on the axis (both major and minor axis).
- * The size is calculated only once and then cached in this.props.
- * @private
- */
-TimeAxis.prototype._calculateCharSize = function () {
-  // Note: We calculate char size with every redraw. Size may change, for
-  // example when any of the timelines parents had display:none for example.
-
-  // determine the char width and height on the minor axis
-  if (!this.dom.measureCharMinor) {
-    this.dom.measureCharMinor = document.createElement('DIV');
-    this.dom.measureCharMinor.className = 'text minor measure';
-    this.dom.measureCharMinor.style.position = 'absolute';
-
-    this.dom.measureCharMinor.appendChild(document.createTextNode('0'));
-    this.dom.foreground.appendChild(this.dom.measureCharMinor);
-  }
-  this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight;
-  this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth;
-
-  // determine the char width and height on the major axis
-  if (!this.dom.measureCharMajor) {
-    this.dom.measureCharMajor = document.createElement('DIV');
-    this.dom.measureCharMajor.className = 'text minor measure';
-    this.dom.measureCharMajor.style.position = 'absolute';
-
-    this.dom.measureCharMajor.appendChild(document.createTextNode('0'));
-    this.dom.foreground.appendChild(this.dom.measureCharMajor);
-  }
-  this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight;
-  this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth;
-};
-
-/**
- * Snap a date to a rounded value.
- * The snap intervals are dependent on the current scale and step.
- * @param {Date} date   the date to be snapped.
- * @return {Date} snappedDate
- */
-TimeAxis.prototype.snap = function(date) {
-  return this.step.snap(date);
-};
-
-/**
- * A current time bar
- * @param {{range: Range, dom: Object, domProps: Object}} body
- * @param {Object} [options]        Available parameters:
- *                                  {Boolean} [showCurrentTime]
- * @constructor CurrentTime
- * @extends Component
- */
-
-function CurrentTime (body, options) {
-  this.body = body;
-
-  // default options
-  this.defaultOptions = {
-    showCurrentTime: true
-  };
-  this.options = util.extend({}, this.defaultOptions);
-
-  this._create();
-
-  this.setOptions(options);
-}
-
-CurrentTime.prototype = new Component();
-
-/**
- * Create the HTML DOM for the current time bar
- * @private
- */
-CurrentTime.prototype._create = function() {
-  var bar = document.createElement('div');
-  bar.className = 'currenttime';
-  bar.style.position = 'absolute';
-  bar.style.top = '0px';
-  bar.style.height = '100%';
-
-  this.bar = bar;
-};
-
-/**
- * Destroy the CurrentTime bar
- */
-CurrentTime.prototype.destroy = function () {
-  this.options.showCurrentTime = false;
-  this.redraw(); // will remove the bar from the DOM and stop refreshing
-
-  this.body = null;
-};
-
-/**
- * Set options for the component. Options will be merged in current options.
- * @param {Object} options  Available parameters:
- *                          {boolean} [showCurrentTime]
- */
-CurrentTime.prototype.setOptions = function(options) {
-  if (options) {
-    // copy all options that we know
-    util.selectiveExtend(['showCurrentTime'], this.options, options);
-  }
-};
-
-/**
- * Repaint the component
- * @return {boolean} Returns true if the component is resized
- */
-CurrentTime.prototype.redraw = function() {
-  if (this.options.showCurrentTime) {
-    var parent = this.body.dom.backgroundVertical;
-    if (this.bar.parentNode != parent) {
-      // attach to the dom
-      if (this.bar.parentNode) {
-        this.bar.parentNode.removeChild(this.bar);
-      }
-      parent.appendChild(this.bar);
-
-      this.start();
-    }
-
-    var now = new Date();
-    var x = this.body.util.toScreen(now);
-
-    this.bar.style.left = x + 'px';
-    this.bar.title = 'Current time: ' + now;
-  }
-  else {
-    // remove the line from the DOM
-    if (this.bar.parentNode) {
-      this.bar.parentNode.removeChild(this.bar);
-    }
-    this.stop();
-  }
-
-  return false;
-};
-
-/**
- * Start auto refreshing the current time bar
- */
-CurrentTime.prototype.start = function() {
-  var me = this;
-
-  function update () {
-    me.stop();
-
-    // determine interval to refresh
-    var scale = me.body.range.conversion(me.body.domProps.center.width).scale;
-    var interval = 1 / scale / 10;
-    if (interval < 30)   interval = 30;
-    if (interval > 1000) interval = 1000;
-
-    me.redraw();
-
-    // start a timer to adjust for the new time
-    me.currentTimeTimer = setTimeout(update, interval);
-  }
-
-  update();
-};
-
-/**
- * Stop auto refreshing the current time bar
- */
-CurrentTime.prototype.stop = function() {
-  if (this.currentTimeTimer !== undefined) {
-    clearTimeout(this.currentTimeTimer);
-    delete this.currentTimeTimer;
-  }
-};
-
-/**
- * A custom time bar
- * @param {{range: Range, dom: Object}} body
- * @param {Object} [options]        Available parameters:
- *                                  {Boolean} [showCustomTime]
- * @constructor CustomTime
- * @extends Component
- */
-
-function CustomTime (body, options) {
-  this.body = body;
-
-  // default options
-  this.defaultOptions = {
-    showCustomTime: false
-  };
-  this.options = util.extend({}, this.defaultOptions);
-
-  this.customTime = new Date();
-  this.eventParams = {}; // stores state parameters while dragging the bar
-
-  // create the DOM
-  this._create();
-
-  this.setOptions(options);
-}
-
-CustomTime.prototype = new Component();
-
-/**
- * Set options for the component. Options will be merged in current options.
- * @param {Object} options  Available parameters:
- *                          {boolean} [showCustomTime]
- */
-CustomTime.prototype.setOptions = function(options) {
-  if (options) {
-    // copy all options that we know
-    util.selectiveExtend(['showCustomTime'], this.options, options);
-  }
-};
-
-/**
- * Create the DOM for the custom time
- * @private
- */
-CustomTime.prototype._create = function() {
-  var bar = document.createElement('div');
-  bar.className = 'customtime';
-  bar.style.position = 'absolute';
-  bar.style.top = '0px';
-  bar.style.height = '100%';
-  this.bar = bar;
-
-  var drag = document.createElement('div');
-  drag.style.position = 'relative';
-  drag.style.top = '0px';
-  drag.style.left = '-10px';
-  drag.style.height = '100%';
-  drag.style.width = '20px';
-  bar.appendChild(drag);
-
-  // attach event listeners
-  this.hammer = Hammer(bar, {
-    prevent_default: true
-  });
-  this.hammer.on('dragstart', this._onDragStart.bind(this));
-  this.hammer.on('drag',      this._onDrag.bind(this));
-  this.hammer.on('dragend',   this._onDragEnd.bind(this));
-};
-
-/**
- * Destroy the CustomTime bar
- */
-CustomTime.prototype.destroy = function () {
-  this.options.showCustomTime = false;
-  this.redraw(); // will remove the bar from the DOM
-
-  this.hammer.enable(false);
-  this.hammer = null;
-
-  this.body = null;
-};
-
-/**
- * Repaint the component
- * @return {boolean} Returns true if the component is resized
- */
-CustomTime.prototype.redraw = function () {
-  if (this.options.showCustomTime) {
-    var parent = this.body.dom.backgroundVertical;
-    if (this.bar.parentNode != parent) {
-      // attach to the dom
-      if (this.bar.parentNode) {
-        this.bar.parentNode.removeChild(this.bar);
-      }
-      parent.appendChild(this.bar);
-    }
-
-    var x = this.body.util.toScreen(this.customTime);
-
-    this.bar.style.left = x + 'px';
-    this.bar.title = 'Time: ' + this.customTime;
-  }
-  else {
-    // remove the line from the DOM
-    if (this.bar.parentNode) {
-      this.bar.parentNode.removeChild(this.bar);
-    }
-  }
-
-  return false;
-};
-
-/**
- * Set custom time.
- * @param {Date} time
- */
-CustomTime.prototype.setCustomTime = function(time) {
-  this.customTime = new Date(time.valueOf());
-  this.redraw();
-};
-
-/**
- * Retrieve the current custom time.
- * @return {Date} customTime
- */
-CustomTime.prototype.getCustomTime = function() {
-  return new Date(this.customTime.valueOf());
-};
-
-/**
- * Start moving horizontally
- * @param {Event} event
- * @private
- */
-CustomTime.prototype._onDragStart = function(event) {
-  this.eventParams.dragging = true;
-  this.eventParams.customTime = this.customTime;
-
-  event.stopPropagation();
-  event.preventDefault();
-};
-
-/**
- * Perform moving operating.
- * @param {Event} event
- * @private
- */
-CustomTime.prototype._onDrag = function (event) {
-  if (!this.eventParams.dragging) return;
-
-  var deltaX = event.gesture.deltaX,
-      x = this.body.util.toScreen(this.eventParams.customTime) + deltaX,
-      time = this.body.util.toTime(x);
-
-  this.setCustomTime(time);
-
-  // fire a timechange event
-  this.body.emitter.emit('timechange', {
-    time: new Date(this.customTime.valueOf())
-  });
-
-  event.stopPropagation();
-  event.preventDefault();
-};
-
-/**
- * Stop moving operating.
- * @param {event} event
- * @private
- */
-CustomTime.prototype._onDragEnd = function (event) {
-  if (!this.eventParams.dragging) return;
-
-  // fire a timechanged event
-  this.body.emitter.emit('timechanged', {
-    time: new Date(this.customTime.valueOf())
-  });
-
-  event.stopPropagation();
-  event.preventDefault();
-};
-
-var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
-
-/**
- * An ItemSet holds a set of items and ranges which can be displayed in a
- * range. The width is determined by the parent of the ItemSet, and the height
- * is determined by the size of the items.
- * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body
- * @param {Object} [options]      See ItemSet.setOptions for the available options.
- * @constructor ItemSet
- * @extends Component
- */
-function ItemSet(body, options) {
-  this.body = body;
-
-  this.defaultOptions = {
-    type: 'box',
-    orientation: 'bottom',  // 'top' or 'bottom'
-    align: 'center', // alignment of box items
-    stack: true,
-    groupOrder: null,
-
-    selectable: true,
-    editable: {
-      updateTime: false,
-      updateGroup: false,
-      add: false,
-      remove: false
-    },
-
-    onAdd: function (item, callback) {
-      callback(item);
-    },
-    onUpdate: function (item, callback) {
-      callback(item);
-    },
-    onMove: function (item, callback) {
-      callback(item);
-    },
-    onRemove: function (item, callback) {
-      callback(item);
-    },
-
-    margin: {
-      item: 10,
-      axis: 20
-    },
-    padding: 5
-  };
-
-  // options is shared by this ItemSet and all its items
-  this.options = util.extend({}, this.defaultOptions);
-
-  // options for getting items from the DataSet with the correct type
-  this.itemOptions = {
-    type: {start: 'Date', end: 'Date'}
-  };
-
-  this.conversion = {
-    toScreen: body.util.toScreen,
-    toTime: body.util.toTime
-  };
-  this.dom = {};
-  this.props = {};
-  this.hammer = null;
-
-  var me = this;
-  this.itemsData = null;    // DataSet
-  this.groupsData = null;   // DataSet
-
-  // listeners for the DataSet of the items
-  this.itemListeners = {
-    'add': function (event, params, senderId) {
-      me._onAdd(params.items);
-    },
-    'update': function (event, params, senderId) {
-      me._onUpdate(params.items);
-    },
-    'remove': function (event, params, senderId) {
-      me._onRemove(params.items);
-    }
-  };
-
-  // listeners for the DataSet of the groups
-  this.groupListeners = {
-    'add': function (event, params, senderId) {
-      me._onAddGroups(params.items);
-    },
-    'update': function (event, params, senderId) {
-      me._onUpdateGroups(params.items);
-    },
-    'remove': function (event, params, senderId) {
-      me._onRemoveGroups(params.items);
-    }
-  };
-
-  this.items = {};      // object with an Item for every data item
-  this.groups = {};     // Group object for every group
-  this.groupIds = [];
-
-  this.selection = [];  // list with the ids of all selected nodes
-  this.stackDirty = true; // if true, all items will be restacked on next redraw
-
-  this.touchParams = {}; // stores properties while dragging
-  // create the HTML DOM
-
-  this._create();
-
-  this.setOptions(options);
-}
-
-ItemSet.prototype = new Component();
-
-// available item types will be registered here
-ItemSet.types = {
-  box: ItemBox,
-  range: ItemRange,
-  rangeoverflow: ItemRangeOverflow,
-  point: ItemPoint
-};
-
-/**
- * Create the HTML DOM for the ItemSet
- */
-ItemSet.prototype._create = function(){
-  var frame = document.createElement('div');
-  frame.className = 'itemset';
-  frame['timeline-itemset'] = this;
-  this.dom.frame = frame;
-
-  // create background panel
-  var background = document.createElement('div');
-  background.className = 'background';
-  frame.appendChild(background);
-  this.dom.background = background;
-
-  // create foreground panel
-  var foreground = document.createElement('div');
-  foreground.className = 'foreground';
-  frame.appendChild(foreground);
-  this.dom.foreground = foreground;
-
-  // create axis panel
-  var axis = document.createElement('div');
-  axis.className = 'axis';
-  this.dom.axis = axis;
-
-  // create labelset
-  var labelSet = document.createElement('div');
-  labelSet.className = 'labelset';
-  this.dom.labelSet = labelSet;
-
-  // create ungrouped Group
-  this._updateUngrouped();
-
-  // attach event listeners
-  // Note: we bind to the centerContainer for the case where the height
-  //       of the center container is larger than of the ItemSet, so we
-  //       can click in the empty area to create a new item or deselect an item.
-  this.hammer = Hammer(this.body.dom.centerContainer, {
-    prevent_default: true
-  });
-
-  // drag items when selected
-  this.hammer.on('touch',     this._onTouch.bind(this));
-  this.hammer.on('dragstart', this._onDragStart.bind(this));
-  this.hammer.on('drag',      this._onDrag.bind(this));
-  this.hammer.on('dragend',   this._onDragEnd.bind(this));
-
-  // single select (or unselect) when tapping an item
-  this.hammer.on('tap',  this._onSelectItem.bind(this));
-
-  // multi select when holding mouse/touch, or on ctrl+click
-  this.hammer.on('hold', this._onMultiSelectItem.bind(this));
-
-  // add item on doubletap
-  this.hammer.on('doubletap', this._onAddItem.bind(this));
-
-  // attach to the DOM
-  this.show();
-};
-
-/**
- * Set options for the ItemSet. Existing options will be extended/overwritten.
- * @param {Object} [options] The following options are available:
- *                           {String} type
- *                              Default type for the items. Choose from 'box'
- *                              (default), 'point', or 'range'. The default
- *                              Style can be overwritten by individual items.
- *                           {String} align
- *                              Alignment for the items, only applicable for
- *                              ItemBox. Choose 'center' (default), 'left', or
- *                              'right'.
- *                           {String} orientation
- *                              Orientation of the item set. Choose 'top' or
- *                              'bottom' (default).
- *                           {Function} groupOrder
- *                              A sorting function for ordering groups
- *                           {Boolean} stack
- *                              If true (deafult), items will be stacked on
- *                              top of each other.
- *                           {Number} margin.axis
- *                              Margin between the axis and the items in pixels.
- *                              Default is 20.
- *                           {Number} margin.item
- *                              Margin between items in pixels. Default is 10.
- *                           {Number} margin
- *                              Set margin for both axis and items in pixels.
- *                           {Number} padding
- *                              Padding of the contents of an item in pixels.
- *                              Must correspond with the items css. Default is 5.
- *                           {Boolean} selectable
- *                              If true (default), items can be selected.
- *                           {Boolean} editable
- *                              Set all editable options to true or false
- *                           {Boolean} editable.updateTime
- *                              Allow dragging an item to an other moment in time
- *                           {Boolean} editable.updateGroup
- *                              Allow dragging an item to an other group
- *                           {Boolean} editable.add
- *                              Allow creating new items on double tap
- *                           {Boolean} editable.remove
- *                              Allow removing items by clicking the delete button
- *                              top right of a selected item.
- *                           {Function(item: Item, callback: Function)} onAdd
- *                              Callback function triggered when an item is about to be added:
- *                              when the user double taps an empty space in the Timeline.
- *                           {Function(item: Item, callback: Function)} onUpdate
- *                              Callback function fired when an item is about to be updated.
- *                              This function typically has to show a dialog where the user
- *                              change the item. If not implemented, nothing happens.
- *                           {Function(item: Item, callback: Function)} onMove
- *                              Fired when an item has been moved. If not implemented,
- *                              the move action will be accepted.
- *                           {Function(item: Item, callback: Function)} onRemove
- *                              Fired when an item is about to be deleted.
- *                              If not implemented, the item will be always removed.
- */
-ItemSet.prototype.setOptions = function(options) {
-  if (options) {
-    // copy all options that we know
-    var fields = ['type', 'align', 'orientation', 'padding', 'stack', 'selectable', 'groupOrder'];
-    util.selectiveExtend(fields, this.options, options);
-
-    if ('margin' in options) {
-      if (typeof options.margin === 'number') {
-        this.options.margin.axis = options.margin;
-        this.options.margin.item = options.margin;
-      }
-      else if (typeof options.margin === 'object'){
-        util.selectiveExtend(['axis', 'item'], this.options.margin, options.margin);
-      }
-    }
-
-    if ('editable' in options) {
-      if (typeof options.editable === 'boolean') {
-        this.options.editable.updateTime  = options.editable;
-        this.options.editable.updateGroup = options.editable;
-        this.options.editable.add         = options.editable;
-        this.options.editable.remove      = options.editable;
-      }
-      else if (typeof options.editable === 'object') {
-        util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove'], this.options.editable, options.editable);
-      }
-    }
-
-    // callback functions
-    var addCallback = (function (name) {
-      if (name in options) {
-        var fn = options[name];
-        if (!(fn instanceof Function) || fn.length != 2) {
-          throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)');
-        }
-        this.options[name] = fn;
-      }
-    }).bind(this);
-    ['onAdd', 'onUpdate', 'onRemove', 'onMove'].forEach(addCallback);
-
-    // force the itemSet to refresh: options like orientation and margins may be changed
-    this.markDirty();
-  }
-};
-
-/**
- * Mark the ItemSet dirty so it will refresh everything with next redraw
- */
-ItemSet.prototype.markDirty = function() {
-  this.groupIds = [];
-  this.stackDirty = true;
-};
-
-/**
- * Destroy the ItemSet
- */
-ItemSet.prototype.destroy = function() {
-  this.hide();
-  this.setItems(null);
-  this.setGroups(null);
-
-  this.hammer = null;
-
-  this.body = null;
-  this.conversion = null;
-};
-
-/**
- * Hide the component from the DOM
- */
-ItemSet.prototype.hide = function() {
-  // remove the frame containing the items
-  if (this.dom.frame.parentNode) {
-    this.dom.frame.parentNode.removeChild(this.dom.frame);
-  }
-
-  // remove the axis with dots
-  if (this.dom.axis.parentNode) {
-    this.dom.axis.parentNode.removeChild(this.dom.axis);
-  }
-
-  // remove the labelset containing all group labels
-  if (this.dom.labelSet.parentNode) {
-    this.dom.labelSet.parentNode.removeChild(this.dom.labelSet);
-  }
-};
-
-/**
- * Show the component in the DOM (when not already visible).
- * @return {Boolean} changed
- */
-ItemSet.prototype.show = function() {
-  // show frame containing the items
-  if (!this.dom.frame.parentNode) {
-    this.body.dom.center.appendChild(this.dom.frame);
-  }
-
-  // show axis with dots
-  if (!this.dom.axis.parentNode) {
-    this.body.dom.backgroundVertical.appendChild(this.dom.axis);
-  }
-
-  // show labelset containing labels
-  if (!this.dom.labelSet.parentNode) {
-    this.body.dom.left.appendChild(this.dom.labelSet);
-  }
-};
-
-/**
- * Set selected items by their id. Replaces the current selection
- * Unknown id's are silently ignored.
- * @param {Array} [ids] An array with zero or more id's of the items to be
- *                      selected. If ids is an empty array, all items will be
- *                      unselected.
- */
-ItemSet.prototype.setSelection = function(ids) {
-  var i, ii, id, item;
-
-  if (ids) {
-    if (!Array.isArray(ids)) {
-      throw new TypeError('Array expected');
-    }
-
-    // unselect currently selected items
-    for (i = 0, ii = this.selection.length; i < ii; i++) {
-      id = this.selection[i];
-      item = this.items[id];
-      if (item) item.unselect();
-    }
-
-    // select items
-    this.selection = [];
-    for (i = 0, ii = ids.length; i < ii; i++) {
-      id = ids[i];
-      item = this.items[id];
-      if (item) {
-        this.selection.push(id);
-        item.select();
-      }
-    }
-  }
-};
-
-/**
- * Get the selected items by their id
- * @return {Array} ids  The ids of the selected items
- */
-ItemSet.prototype.getSelection = function() {
-  return this.selection.concat([]);
-};
-
-/**
- * Deselect a selected item
- * @param {String | Number} id
- * @private
- */
-ItemSet.prototype._deselect = function(id) {
-  var selection = this.selection;
-  for (var i = 0, ii = selection.length; i < ii; i++) {
-    if (selection[i] == id) { // non-strict comparison!
-      selection.splice(i, 1);
-      break;
-    }
-  }
-};
-
-/**
- * Repaint the component
- * @return {boolean} Returns true if the component is resized
- */
-ItemSet.prototype.redraw = function() {
-  var margin = this.options.margin,
-      range = this.body.range,
-      asSize = util.option.asSize,
-      options = this.options,
-      orientation = options.orientation,
-      resized = false,
-      frame = this.dom.frame,
-      editable = options.editable.updateTime || options.editable.updateGroup;
-
-  // update class name
-  frame.className = 'itemset' + (editable ? ' editable' : '');
-
-  // reorder the groups (if needed)
-  resized = this._orderGroups() || resized;
-
-  // check whether zoomed (in that case we need to re-stack everything)
-  // TODO: would be nicer to get this as a trigger from Range
-  var visibleInterval = range.end - range.start;
-  var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.props.width != this.props.lastWidth);
-  if (zoomed) this.stackDirty = true;
-  this.lastVisibleInterval = visibleInterval;
-  this.props.lastWidth = this.props.width;
-
-  // redraw all groups
-  var restack = this.stackDirty,
-      firstGroup = this._firstGroup(),
-      firstMargin = {
-        item: margin.item,
-        axis: margin.axis
-      },
-      nonFirstMargin = {
-        item: margin.item,
-        axis: margin.item / 2
-      },
-      height = 0,
-      minHeight = margin.axis + margin.item;
-  util.forEach(this.groups, function (group) {
-    var groupMargin = (group == firstGroup) ? firstMargin : nonFirstMargin;
-    var groupResized = group.redraw(range, groupMargin, restack);
-    resized = groupResized || resized;
-    height += group.height;
-  });
-  height = Math.max(height, minHeight);
-  this.stackDirty = false;
-
-  // update frame height
-  frame.style.height  = asSize(height);
-
-  // calculate actual size and position
-  this.props.top = frame.offsetTop;
-  this.props.left = frame.offsetLeft;
-  this.props.width = frame.offsetWidth;
-  this.props.height = height;
-
-  // reposition axis
-  this.dom.axis.style.top = asSize((orientation == 'top') ?
-      (this.body.domProps.top.height + this.body.domProps.border.top) :
-      (this.body.domProps.top.height + this.body.domProps.centerContainer.height));
-  this.dom.axis.style.left = this.body.domProps.border.left + 'px';
-
-  // check if this component is resized
-  resized = this._isResized() || resized;
-
-  return resized;
-};
-
-/**
- * Get the first group, aligned with the axis
- * @return {Group | null} firstGroup
- * @private
- */
-ItemSet.prototype._firstGroup = function() {
-  var firstGroupIndex = (this.options.orientation == 'top') ? 0 : (this.groupIds.length - 1);
-  var firstGroupId = this.groupIds[firstGroupIndex];
-  var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED];
-
-  return firstGroup || null;
-};
-
-/**
- * Create or delete the group holding all ungrouped items. This group is used when
- * there are no groups specified.
- * @protected
- */
-ItemSet.prototype._updateUngrouped = function() {
-  var ungrouped = this.groups[UNGROUPED];
-
-  if (this.groupsData) {
-    // remove the group holding all ungrouped items
-    if (ungrouped) {
-      ungrouped.hide();
-      delete this.groups[UNGROUPED];
-    }
-  }
-  else {
-    // create a group holding all (unfiltered) items
-    if (!ungrouped) {
-      var id = null;
-      var data = null;
-      ungrouped = new Group(id, data, this);
-      this.groups[UNGROUPED] = ungrouped;
-
-      for (var itemId in this.items) {
-        if (this.items.hasOwnProperty(itemId)) {
-          ungrouped.add(this.items[itemId]);
-        }
-      }
-
-      ungrouped.show();
-    }
-  }
-};
-
-/**
- * Get the element for the labelset
- * @return {HTMLElement} labelSet
- */
-ItemSet.prototype.getLabelSet = function() {
-  return this.dom.labelSet;
-};
-
-/**
- * Set items
- * @param {vis.DataSet | null} items
- */
-ItemSet.prototype.setItems = function(items) {
-  var me = this,
-      ids,
-      oldItemsData = this.itemsData;
-
-  // replace the dataset
-  if (!items) {
-    this.itemsData = null;
-  }
-  else if (items instanceof DataSet || items instanceof DataView) {
-    this.itemsData = items;
-  }
-  else {
-    throw new TypeError('Data must be an instance of DataSet or DataView');
-  }
-
-  if (oldItemsData) {
-    // unsubscribe from old dataset
-    util.forEach(this.itemListeners, function (callback, event) {
-      oldItemsData.off(event, callback);
-    });
-
-    // remove all drawn items
-    ids = oldItemsData.getIds();
-    this._onRemove(ids);
-  }
-
-  if (this.itemsData) {
-    // subscribe to new dataset
-    var id = this.id;
-    util.forEach(this.itemListeners, function (callback, event) {
-      me.itemsData.on(event, callback, id);
-    });
-
-    // add all new items
-    ids = this.itemsData.getIds();
-    this._onAdd(ids);
-
-    // update the group holding all ungrouped items
-    this._updateUngrouped();
-  }
-};
-
-/**
- * Get the current items
- * @returns {vis.DataSet | null}
- */
-ItemSet.prototype.getItems = function() {
-  return this.itemsData;
-};
-
-/**
- * Set groups
- * @param {vis.DataSet} groups
- */
-ItemSet.prototype.setGroups = function(groups) {
-  var me = this,
-      ids;
-
-  // unsubscribe from current dataset
-  if (this.groupsData) {
-    util.forEach(this.groupListeners, function (callback, event) {
-      me.groupsData.unsubscribe(event, callback);
-    });
-
-    // remove all drawn groups
-    ids = this.groupsData.getIds();
-    this.groupsData = null;
-    this._onRemoveGroups(ids); // note: this will cause a redraw
-  }
-
-  // replace the dataset
-  if (!groups) {
-    this.groupsData = null;
-  }
-  else if (groups instanceof DataSet || groups instanceof DataView) {
-    this.groupsData = groups;
-  }
-  else {
-    throw new TypeError('Data must be an instance of DataSet or DataView');
-  }
-
-  if (this.groupsData) {
-    // subscribe to new dataset
-    var id = this.id;
-    util.forEach(this.groupListeners, function (callback, event) {
-      me.groupsData.on(event, callback, id);
-    });
-
-    // draw all ms
-    ids = this.groupsData.getIds();
-    this._onAddGroups(ids);
-  }
-
-  // update the group holding all ungrouped items
-  this._updateUngrouped();
-
-  // update the order of all items in each group
-  this._order();
-
-  this.body.emitter.emit('change');
-};
-
-/**
- * Get the current groups
- * @returns {vis.DataSet | null} groups
- */
-ItemSet.prototype.getGroups = function() {
-  return this.groupsData;
-};
-
-/**
- * Remove an item by its id
- * @param {String | Number} id
- */
-ItemSet.prototype.removeItem = function(id) {
-  var item = this.itemsData.get(id),
-      dataset = this._myDataSet();
-
-  if (item) {
-    // confirm deletion
-    this.options.onRemove(item, function (item) {
-      if (item) {
-        // remove by id here, it is possible that an item has no id defined
-        // itself, so better not delete by the item itself
-        dataset.remove(id);
-      }
-    });
-  }
-};
-
-/**
- * Handle updated items
- * @param {Number[]} ids
- * @protected
- */
-ItemSet.prototype._onUpdate = function(ids) {
-  var me = this;
-
-  ids.forEach(function (id) {
-    var itemData = me.itemsData.get(id, me.itemOptions),
-        item = me.items[id],
-        type = itemData.type ||
-            (itemData.start && itemData.end && 'range') ||
-            me.options.type ||
-            'box';
-
-    var constructor = ItemSet.types[type];
-
-    if (item) {
-      // update item
-      if (!constructor || !(item instanceof constructor)) {
-        // item type has changed, delete the item and recreate it
-        me._removeItem(item);
-        item = null;
-      }
-      else {
-        me._updateItem(item, itemData);
-      }
-    }
-
-    if (!item) {
-      // create item
-      if (constructor) {
-        item = new constructor(itemData, me.conversion, me.options);
-        item.id = id; // TODO: not so nice setting id afterwards
-        me._addItem(item);
-      }
-      else {
-        throw new TypeError('Unknown item type "' + type + '"');
-      }
-    }
-  });
-
-  this._order();
-  this.stackDirty = true; // force re-stacking of all items next redraw
-  this.body.emitter.emit('change');
-};
-
-/**
- * Handle added items
- * @param {Number[]} ids
- * @protected
- */
-ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate;
-
-/**
- * Handle removed items
- * @param {Number[]} ids
- * @protected
- */
-ItemSet.prototype._onRemove = function(ids) {
-  var count = 0;
-  var me = this;
-  ids.forEach(function (id) {
-    var item = me.items[id];
-    if (item) {
-      count++;
-      me._removeItem(item);
-    }
-  });
-
-  if (count) {
-    // update order
-    this._order();
-    this.stackDirty = true; // force re-stacking of all items next redraw
-    this.body.emitter.emit('change');
-  }
-};
-
-/**
- * Update the order of item in all groups
- * @private
- */
-ItemSet.prototype._order = function() {
-  // reorder the items in all groups
-  // TODO: optimization: only reorder groups affected by the changed items
-  util.forEach(this.groups, function (group) {
-    group.order();
-  });
-};
-
-/**
- * Handle updated groups
- * @param {Number[]} ids
- * @private
- */
-ItemSet.prototype._onUpdateGroups = function(ids) {
-  this._onAddGroups(ids);
-};
-
-/**
- * Handle changed groups
- * @param {Number[]} ids
- * @private
- */
-ItemSet.prototype._onAddGroups = function(ids) {
-  var me = this;
-
-  ids.forEach(function (id) {
-    var groupData = me.groupsData.get(id);
-    var group = me.groups[id];
-
-    if (!group) {
-      // check for reserved ids
-      if (id == UNGROUPED) {
-        throw new Error('Illegal group id. ' + id + ' is a reserved id.');
-      }
-
-      var groupOptions = Object.create(me.options);
-      util.extend(groupOptions, {
-        height: null
-      });
-
-      group = new Group(id, groupData, me);
-      me.groups[id] = group;
-
-      // add items with this groupId to the new group
-      for (var itemId in me.items) {
-        if (me.items.hasOwnProperty(itemId)) {
-          var item = me.items[itemId];
-          if (item.data.group == id) {
-            group.add(item);
-          }
-        }
-      }
-
-      group.order();
-      group.show();
-    }
-    else {
-      // update group
-      group.setData(groupData);
-    }
-  });
-
-  this.body.emitter.emit('change');
-};
-
-/**
- * Handle removed groups
- * @param {Number[]} ids
- * @private
- */
-ItemSet.prototype._onRemoveGroups = function(ids) {
-  var groups = this.groups;
-  ids.forEach(function (id) {
-    var group = groups[id];
-
-    if (group) {
-      group.hide();
-      delete groups[id];
-    }
-  });
-
-  this.markDirty();
-
-  this.body.emitter.emit('change');
-};
-
-/**
- * Reorder the groups if needed
- * @return {boolean} changed
- * @private
- */
-ItemSet.prototype._orderGroups = function () {
-  if (this.groupsData) {
-    // reorder the groups
-    var groupIds = this.groupsData.getIds({
-      order: this.options.groupOrder
-    });
-
-    var changed = !util.equalArray(groupIds, this.groupIds);
-    if (changed) {
-      // hide all groups, removes them from the DOM
-      var groups = this.groups;
-      groupIds.forEach(function (groupId) {
-        groups[groupId].hide();
-      });
-
-      // show the groups again, attach them to the DOM in correct order
-      groupIds.forEach(function (groupId) {
-        groups[groupId].show();
-      });
-
-      this.groupIds = groupIds;
-    }
-
-    return changed;
-  }
-  else {
-    return false;
-  }
-};
-
-/**
- * Add a new item
- * @param {Item} item
- * @private
- */
-ItemSet.prototype._addItem = function(item) {
-  this.items[item.id] = item;
-
-  // add to group
-  var groupId = this.groupsData ? item.data.group : UNGROUPED;
-  var group = this.groups[groupId];
-  if (group) group.add(item);
-};
-
-/**
- * Update an existing item
- * @param {Item} item
- * @param {Object} itemData
- * @private
- */
-ItemSet.prototype._updateItem = function(item, itemData) {
-  var oldGroupId = item.data.group;
-
-  item.data = itemData;
-  if (item.displayed) {
-    item.redraw();
-  }
-
-  // update group
-  if (oldGroupId != item.data.group) {
-    var oldGroup = this.groups[oldGroupId];
-    if (oldGroup) oldGroup.remove(item);
-
-    var groupId = this.groupsData ? item.data.group : UNGROUPED;
-    var group = this.groups[groupId];
-    if (group) group.add(item);
-  }
-};
-
-/**
- * Delete an item from the ItemSet: remove it from the DOM, from the map
- * with items, and from the map with visible items, and from the selection
- * @param {Item} item
- * @private
- */
-ItemSet.prototype._removeItem = function(item) {
-  // remove from DOM
-  item.hide();
-
-  // remove from items
-  delete this.items[item.id];
-
-  // remove from selection
-  var index = this.selection.indexOf(item.id);
-  if (index != -1) this.selection.splice(index, 1);
-
-  // remove from group
-  var groupId = this.groupsData ? item.data.group : UNGROUPED;
-  var group = this.groups[groupId];
-  if (group) group.remove(item);
-};
-
-/**
- * Create an array containing all items being a range (having an end date)
- * @param array
- * @returns {Array}
- * @private
- */
-ItemSet.prototype._constructByEndArray = function(array) {
-  var endArray = [];
-
-  for (var i = 0; i < array.length; i++) {
-    if (array[i] instanceof ItemRange) {
-      endArray.push(array[i]);
-    }
-  }
-  return endArray;
-};
-
-/**
- * Register the clicked item on touch, before dragStart is initiated.
- *
- * dragStart is initiated from a mousemove event, which can have left the item
- * already resulting in an item == null
- *
- * @param {Event} event
- * @private
- */
-ItemSet.prototype._onTouch = function (event) {
-  // store the touched item, used in _onDragStart
-  this.touchParams.item = ItemSet.itemFromTarget(event);
-};
-
-/**
- * Start dragging the selected events
- * @param {Event} event
- * @private
- */
-ItemSet.prototype._onDragStart = function (event) {
-  if (!this.options.editable.updateTime && !this.options.editable.updateGroup) {
-    return;
-  }
-
-  var item = this.touchParams.item || null,
-      me = this,
-      props;
-
-  if (item && item.selected) {
-    var dragLeftItem = event.target.dragLeftItem;
-    var dragRightItem = event.target.dragRightItem;
-
-    if (dragLeftItem) {
-      props = {
-        item: dragLeftItem
-      };
-
-      if (me.options.editable.updateTime) {
-        props.start = item.data.start.valueOf();
-      }
-      if (me.options.editable.updateGroup) {
-        if ('group' in item.data) props.group = item.data.group;
-      }
-
-      this.touchParams.itemProps = [props];
-    }
-    else if (dragRightItem) {
-      props = {
-        item: dragRightItem
-      };
-
-      if (me.options.editable.updateTime) {
-        props.end = item.data.end.valueOf();
-      }
-      if (me.options.editable.updateGroup) {
-        if ('group' in item.data) props.group = item.data.group;
-      }
-
-      this.touchParams.itemProps = [props];
-    }
-    else {
-      this.touchParams.itemProps = this.getSelection().map(function (id) {
-        var item = me.items[id];
-        var props = {
-          item: item
-        };
-
-        if (me.options.editable.updateTime) {
-          if ('start' in item.data) props.start = item.data.start.valueOf();
-          if ('end' in item.data)   props.end = item.data.end.valueOf();
-        }
-        if (me.options.editable.updateGroup) {
-          if ('group' in item.data) props.group = item.data.group;
-        }
-
-        return props;
-      });
-    }
-
-    event.stopPropagation();
-  }
-};
-
-/**
- * Drag selected items
- * @param {Event} event
- * @private
- */
-ItemSet.prototype._onDrag = function (event) {
-  if (this.touchParams.itemProps) {
-    var range = this.body.range,
-        snap = this.body.util.snap || null,
-        deltaX = event.gesture.deltaX,
-        scale = (this.props.width / (range.end - range.start)),
-        offset = deltaX / scale;
-
-    // move
-    this.touchParams.itemProps.forEach(function (props) {
-      if ('start' in props) {
-        var start = new Date(props.start + offset);
-        props.item.data.start = snap ? snap(start) : start;
-      }
-
-      if ('end' in props) {
-        var end = new Date(props.end + offset);
-        props.item.data.end = snap ? snap(end) : end;
-      }
-
-      if ('group' in props) {
-        // drag from one group to another
-        var group = ItemSet.groupFromTarget(event);
-        if (group && group.groupId != props.item.data.group) {
-          var oldGroup = props.item.parent;
-          oldGroup.remove(props.item);
-          oldGroup.order();
-          group.add(props.item);
-          group.order();
-
-          props.item.data.group = group.groupId;
-        }
-      }
-    });
-
-    // TODO: implement onMoving handler
-
-    this.stackDirty = true; // force re-stacking of all items next redraw
-    this.body.emitter.emit('change');
-
-    event.stopPropagation();
-  }
-};
-
-/**
- * End of dragging selected items
- * @param {Event} event
- * @private
- */
-ItemSet.prototype._onDragEnd = function (event) {
-  if (this.touchParams.itemProps) {
-    // prepare a change set for the changed items
-    var changes = [],
-        me = this,
-        dataset = this._myDataSet();
-
-    this.touchParams.itemProps.forEach(function (props) {
-      var id = props.item.id,
-          itemData = me.itemsData.get(id, me.itemOptions);
-
-      var changed = false;
-      if ('start' in props.item.data) {
-        changed = (props.start != props.item.data.start.valueOf());
-        itemData.start = util.convert(props.item.data.start,
-                dataset._options.type && dataset._options.type.start || 'Date');
-      }
-      if ('end' in props.item.data) {
-        changed = changed  || (props.end != props.item.data.end.valueOf());
-        itemData.end = util.convert(props.item.data.end,
-                dataset._options.type && dataset._options.type.end || 'Date');
-      }
-      if ('group' in props.item.data) {
-        changed = changed  || (props.group != props.item.data.group);
-        itemData.group = props.item.data.group;
-      }
-
-      // only apply changes when start or end is actually changed
-      if (changed) {
-        me.options.onMove(itemData, function (itemData) {
-          if (itemData) {
-            // apply changes
-            itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined)
-            changes.push(itemData);
-          }
-          else {
-            // restore original values
-            if ('start' in props) props.item.data.start = props.start;
-            if ('end' in props)   props.item.data.end   = props.end;
-
-            me.stackDirty = true; // force re-stacking of all items next redraw
-            me.body.emitter.emit('change');
-          }
-        });
-      }
-    });
-    this.touchParams.itemProps = null;
-
-    // apply the changes to the data (if there are changes)
-    if (changes.length) {
-      dataset.update(changes);
-    }
-
-    event.stopPropagation();
-  }
-};
-
-/**
- * Handle selecting/deselecting an item when tapping it
- * @param {Event} event
- * @private
- */
-ItemSet.prototype._onSelectItem = function (event) {
-  if (!this.options.selectable) return;
-
-  var ctrlKey  = event.gesture.srcEvent && event.gesture.srcEvent.ctrlKey;
-  var shiftKey = event.gesture.srcEvent && event.gesture.srcEvent.shiftKey;
-  if (ctrlKey || shiftKey) {
-    this._onMultiSelectItem(event);
-    return;
-  }
-
-  var oldSelection = this.getSelection();
-
-  var item = ItemSet.itemFromTarget(event);
-  var selection = item ? [item.id] : [];
-  this.setSelection(selection);
-
-  var newSelection = this.getSelection();
-
-  // emit a select event,
-  // except when old selection is empty and new selection is still empty
-  if (newSelection.length > 0 || oldSelection.length > 0) {
-    this.body.emitter.emit('select', {
-      items: this.getSelection()
-    });
-  }
-
-  event.stopPropagation();
-};
-
-/**
- * Handle creation and updates of an item on double tap
- * @param event
- * @private
- */
-ItemSet.prototype._onAddItem = function (event) {
-  if (!this.options.selectable) return;
-  if (!this.options.editable.add) return;
-
-  var me = this,
-      snap = this.body.util.snap || null,
-      item = ItemSet.itemFromTarget(event);
-
-  if (item) {
-    // update item
-
-    // execute async handler to update the item (or cancel it)
-    var itemData = me.itemsData.get(item.id); // get a clone of the data from the dataset
-    this.options.onUpdate(itemData, function (itemData) {
-      if (itemData) {
-        me.itemsData.update(itemData);
-      }
-    });
-  }
-  else {
-    // add item
-    var xAbs = vis.util.getAbsoluteLeft(this.dom.frame);
-    var x = event.gesture.center.pageX - xAbs;
-    var start = this.body.util.toTime(x);
-    var newItem = {
-      start: snap ? snap(start) : start,
-      content: 'new item'
-    };
-
-    // when default type is a range, add a default end date to the new item
-    if (this.options.type === 'range' || this.options.type == 'rangeoverflow') {
-      var end = this.body.util.toTime(x + this.props.width / 5);
-      newItem.end = snap ? snap(end) : end;
-    }
-
-    newItem[this.itemsData.fieldId] = util.randomUUID();
-
-    var group = ItemSet.groupFromTarget(event);
-    if (group) {
-      newItem.group = group.groupId;
-    }
-
-    // execute async handler to customize (or cancel) adding an item
-    this.options.onAdd(newItem, function (item) {
-      if (item) {
-        me.itemsData.add(newItem);
-        // TODO: need to trigger a redraw?
-      }
-    });
-  }
-};
-
-/**
- * Handle selecting/deselecting multiple items when holding an item
- * @param {Event} event
- * @private
- */
-ItemSet.prototype._onMultiSelectItem = function (event) {
-  if (!this.options.selectable) return;
-
-  var selection,
-      item = ItemSet.itemFromTarget(event);
-
-  if (item) {
-    // multi select items
-    selection = this.getSelection(); // current selection
-    var index = selection.indexOf(item.id);
-    if (index == -1) {
-      // item is not yet selected -> select it
-      selection.push(item.id);
-    }
-    else {
-      // item is already selected -> deselect it
-      selection.splice(index, 1);
-    }
-    this.setSelection(selection);
-
-    this.body.emitter.emit('select', {
-      items: this.getSelection()
-    });
-
-    event.stopPropagation();
-  }
-};
-
-/**
- * Find an item from an event target:
- * searches for the attribute 'timeline-item' in the event target's element tree
- * @param {Event} event
- * @return {Item | null} item
- */
-ItemSet.itemFromTarget = function(event) {
-  var target = event.target;
-  while (target) {
-    if (target.hasOwnProperty('timeline-item')) {
-      return target['timeline-item'];
-    }
-    target = target.parentNode;
-  }
-
-  return null;
-};
-
-/**
- * Find the Group from an event target:
- * searches for the attribute 'timeline-group' in the event target's element tree
- * @param {Event} event
- * @return {Group | null} group
- */
-ItemSet.groupFromTarget = function(event) {
-  var target = event.target;
-  while (target) {
-    if (target.hasOwnProperty('timeline-group')) {
-      return target['timeline-group'];
-    }
-    target = target.parentNode;
-  }
-
-  return null;
-};
-
-/**
- * Find the ItemSet from an event target:
- * searches for the attribute 'timeline-itemset' in the event target's element tree
- * @param {Event} event
- * @return {ItemSet | null} item
- */
-ItemSet.itemSetFromTarget = function(event) {
-  var target = event.target;
-  while (target) {
-    if (target.hasOwnProperty('timeline-itemset')) {
-      return target['timeline-itemset'];
-    }
-    target = target.parentNode;
-  }
-
-  return null;
-};
-
-/**
- * Find the DataSet to which this ItemSet is connected
- * @returns {null | DataSet} dataset
- * @private
- */
-ItemSet.prototype._myDataSet = function() {
-  // find the root DataSet
-  var dataset = this.itemsData;
-  while (dataset instanceof DataView) {
-    dataset = dataset.data;
-  }
-  return dataset;
-};
-/**
- * @constructor Item
- * @param {Object} data             Object containing (optional) parameters type,
- *                                  start, end, content, group, className.
- * @param {{toScreen: function, toTime: function}} conversion
- *                                  Conversion functions from time to screen and vice versa
- * @param {Object} options          Configuration options
- *                                  // TODO: describe available options
- */
-function Item (data, conversion, options) {
-  this.id = null;
-  this.parent = null;
-  this.data = data;
-  this.dom = null;
-  this.conversion = conversion || {};
-  this.options = options || {};
-
-  this.selected = false;
-  this.displayed = false;
-  this.dirty = true;
-
-  this.top = null;
-  this.left = null;
-  this.width = null;
-  this.height = null;
-}
-
-/**
- * Select current item
- */
-Item.prototype.select = function() {
-  this.selected = true;
-  if (this.displayed) this.redraw();
-};
-
-/**
- * Unselect current item
- */
-Item.prototype.unselect = function() {
-  this.selected = false;
-  if (this.displayed) this.redraw();
-};
-
-/**
- * Set a parent for the item
- * @param {ItemSet | Group} parent
- */
-Item.prototype.setParent = function(parent) {
-  if (this.displayed) {
-    this.hide();
-    this.parent = parent;
-    if (this.parent) {
-      this.show();
-    }
-  }
-  else {
-    this.parent = parent;
-  }
-};
-
-/**
- * Check whether this item is visible inside given range
- * @returns {{start: Number, end: Number}} range with a timestamp for start and end
- * @returns {boolean} True if visible
- */
-Item.prototype.isVisible = function(range) {
-  // Should be implemented by Item implementations
-  return false;
-};
-
-/**
- * Show the Item in the DOM (when not already visible)
- * @return {Boolean} changed
- */
-Item.prototype.show = function() {
-  return false;
-};
-
-/**
- * Hide the Item from the DOM (when visible)
- * @return {Boolean} changed
- */
-Item.prototype.hide = function() {
-  return false;
-};
-
-/**
- * Repaint the item
- */
-Item.prototype.redraw = function() {
-  // should be implemented by the item
-};
-
-/**
- * Reposition the Item horizontally
- */
-Item.prototype.repositionX = function() {
-  // should be implemented by the item
-};
-
-/**
- * Reposition the Item vertically
- */
-Item.prototype.repositionY = function() {
-  // should be implemented by the item
-};
-
-/**
- * Repaint a delete button on the top right of the item when the item is selected
- * @param {HTMLElement} anchor
- * @protected
- */
-Item.prototype._repaintDeleteButton = function (anchor) {
-  if (this.selected && this.options.editable.remove && !this.dom.deleteButton) {
-    // create and show button
-    var me = this;
-
-    var deleteButton = document.createElement('div');
-    deleteButton.className = 'delete';
-    deleteButton.title = 'Delete this item';
-
-    Hammer(deleteButton, {
-      preventDefault: true
-    }).on('tap', function (event) {
-      me.parent.removeFromDataSet(me);
-      event.stopPropagation();
-    });
-
-    anchor.appendChild(deleteButton);
-    this.dom.deleteButton = deleteButton;
-  }
-  else if (!this.selected && this.dom.deleteButton) {
-    // remove button
-    if (this.dom.deleteButton.parentNode) {
-      this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton);
-    }
-    this.dom.deleteButton = null;
-  }
-};
-
-/**
- * @constructor ItemBox
- * @extends Item
- * @param {Object} data             Object containing parameters start
- *                                  content, className.
- * @param {{toScreen: function, toTime: function}} conversion
- *                                  Conversion functions from time to screen and vice versa
- * @param {Object} [options]        Configuration options
- *                                  // TODO: describe available options
- */
-function ItemBox (data, conversion, options) {
-  this.props = {
-    dot: {
-      width: 0,
-      height: 0
-    },
-    line: {
-      width: 0,
-      height: 0
-    }
-  };
-
-  // validate data
-  if (data) {
-    if (data.start == undefined) {
-      throw new Error('Property "start" missing in item ' + data);
-    }
-  }
-
-  Item.call(this, data, conversion, options);
-}
-
-ItemBox.prototype = new Item (null, null, null);
-
-/**
- * Check whether this item is visible inside given range
- * @returns {{start: Number, end: Number}} range with a timestamp for start and end
- * @returns {boolean} True if visible
- */
-ItemBox.prototype.isVisible = function(range) {
-  // determine visibility
-  // TODO: account for the real width of the item. Right now we just add 1/4 to the window
-  var interval = (range.end - range.start) / 4;
-  return (this.data.start > range.start - interval) && (this.data.start < range.end + interval);
-};
-
-/**
- * Repaint the item
- */
-ItemBox.prototype.redraw = function() {
-  var dom = this.dom;
-  if (!dom) {
-    // create DOM
-    this.dom = {};
-    dom = this.dom;
-
-    // create main box
-    dom.box = document.createElement('DIV');
-
-    // contents box (inside the background box). used for making margins
-    dom.content = document.createElement('DIV');
-    dom.content.className = 'content';
-    dom.box.appendChild(dom.content);
-
-    // line to axis
-    dom.line = document.createElement('DIV');
-    dom.line.className = 'line';
-
-    // dot on axis
-    dom.dot = document.createElement('DIV');
-    dom.dot.className = 'dot';
-
-    // attach this item as attribute
-    dom.box['timeline-item'] = this;
-  }
-
-  // append DOM to parent DOM
-  if (!this.parent) {
-    throw new Error('Cannot redraw item: no parent attached');
-  }
-  if (!dom.box.parentNode) {
-    var foreground = this.parent.dom.foreground;
-    if (!foreground) throw new Error('Cannot redraw time axis: parent has no foreground container element');
-    foreground.appendChild(dom.box);
-  }
-  if (!dom.line.parentNode) {
-    var background = this.parent.dom.background;
-    if (!background) throw new Error('Cannot redraw time axis: parent has no background container element');
-    background.appendChild(dom.line);
-  }
-  if (!dom.dot.parentNode) {
-    var axis = this.parent.dom.axis;
-    if (!background) throw new Error('Cannot redraw time axis: parent has no axis container element');
-    axis.appendChild(dom.dot);
-  }
-  this.displayed = true;
-
-  // update contents
-  if (this.data.content != this.content) {
-    this.content = this.data.content;
-    if (this.content instanceof Element) {
-      dom.content.innerHTML = '';
-      dom.content.appendChild(this.content);
-    }
-    else if (this.data.content != undefined) {
-      dom.content.innerHTML = this.content;
-    }
-    else {
-      throw new Error('Property "content" missing in item ' + this.data.id);
-    }
-
-    this.dirty = true;
-  }
-
-  // update class
-  var className = (this.data.className? ' ' + this.data.className : '') +
-      (this.selected ? ' selected' : '');
-  if (this.className != className) {
-    this.className = className;
-    dom.box.className = 'item box' + className;
-    dom.line.className = 'item line' + className;
-    dom.dot.className  = 'item dot' + className;
-
-    this.dirty = true;
-  }
-
-  // recalculate size
-  if (this.dirty) {
-    this.props.dot.height = dom.dot.offsetHeight;
-    this.props.dot.width = dom.dot.offsetWidth;
-    this.props.line.width = dom.line.offsetWidth;
-    this.width = dom.box.offsetWidth;
-    this.height = dom.box.offsetHeight;
-
-    this.dirty = false;
-  }
-
-  this._repaintDeleteButton(dom.box);
-};
-
-/**
- * Show the item in the DOM (when not already displayed). The items DOM will
- * be created when needed.
- */
-ItemBox.prototype.show = function() {
-  if (!this.displayed) {
-    this.redraw();
-  }
-};
-
-/**
- * Hide the item from the DOM (when visible)
- */
-ItemBox.prototype.hide = function() {
-  if (this.displayed) {
-    var dom = this.dom;
-
-    if (dom.box.parentNode)   dom.box.parentNode.removeChild(dom.box);
-    if (dom.line.parentNode)  dom.line.parentNode.removeChild(dom.line);
-    if (dom.dot.parentNode)   dom.dot.parentNode.removeChild(dom.dot);
-
-    this.top = null;
-    this.left = null;
-
-    this.displayed = false;
-  }
-};
-
-/**
- * Reposition the item horizontally
- * @Override
- */
-ItemBox.prototype.repositionX = function() {
-  var start = this.conversion.toScreen(this.data.start),
-      align = this.options.align,
-      left,
-      box = this.dom.box,
-      line = this.dom.line,
-      dot = this.dom.dot;
-
-  // calculate left position of the box
-  if (align == 'right') {
-    this.left = start - this.width;
-  }
-  else if (align == 'left') {
-    this.left = start;
-  }
-  else {
-    // default or 'center'
-    this.left = start - this.width / 2;
-  }
-
-  // reposition box
-  box.style.left = this.left + 'px';
-
-  // reposition line
-  line.style.left = (start - this.props.line.width / 2) + 'px';
-
-  // reposition dot
-  dot.style.left = (start - this.props.dot.width / 2) + 'px';
-};
-
-/**
- * Reposition the item vertically
- * @Override
- */
-ItemBox.prototype.repositionY = function() {
-  var orientation = this.options.orientation,
-      box = this.dom.box,
-      line = this.dom.line,
-      dot = this.dom.dot;
-
-  if (orientation == 'top') {
-    box.style.top     = (this.top || 0) + 'px';
-
-    line.style.top    = '0';
-    line.style.height = (this.parent.top + this.top + 1) + 'px';
-    line.style.bottom = '';
-  }
-  else { // orientation 'bottom'
-    var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty
-    var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top;
-
-    box.style.top     = (this.parent.height - this.top - this.height || 0) + 'px';
-    line.style.top    = (itemSetHeight - lineHeight) + 'px';
-    line.style.bottom = '0';
-  }
-
-  dot.style.top = (-this.props.dot.height / 2) + 'px';
-};
-
-/**
- * @constructor ItemPoint
- * @extends Item
- * @param {Object} data             Object containing parameters start
- *                                  content, className.
- * @param {{toScreen: function, toTime: function}} conversion
- *                                  Conversion functions from time to screen and vice versa
- * @param {Object} [options]        Configuration options
- *                                  // TODO: describe available options
- */
-function ItemPoint (data, conversion, options) {
-  this.props = {
-    dot: {
-      top: 0,
-      width: 0,
-      height: 0
-    },
-    content: {
-      height: 0,
-      marginLeft: 0
-    }
-  };
-
-  // validate data
-  if (data) {
-    if (data.start == undefined) {
-      throw new Error('Property "start" missing in item ' + data);
-    }
-  }
-
-  Item.call(this, data, conversion, options);
-}
-
-ItemPoint.prototype = new Item (null, null, null);
-
-/**
- * Check whether this item is visible inside given range
- * @returns {{start: Number, end: Number}} range with a timestamp for start and end
- * @returns {boolean} True if visible
- */
-ItemPoint.prototype.isVisible = function(range) {
-  // determine visibility
-  // TODO: account for the real width of the item. Right now we just add 1/4 to the window
-  var interval = (range.end - range.start) / 4;
-  return (this.data.start > range.start - interval) && (this.data.start < range.end + interval);
-};
-
-/**
- * Repaint the item
- */
-ItemPoint.prototype.redraw = function() {
-  var dom = this.dom;
-  if (!dom) {
-    // create DOM
-    this.dom = {};
-    dom = this.dom;
-
-    // background box
-    dom.point = document.createElement('div');
-    // className is updated in redraw()
-
-    // contents box, right from the dot
-    dom.content = document.createElement('div');
-    dom.content.className = 'content';
-    dom.point.appendChild(dom.content);
-
-    // dot at start
-    dom.dot = document.createElement('div');
-    dom.point.appendChild(dom.dot);
-
-    // attach this item as attribute
-    dom.point['timeline-item'] = this;
-  }
-
-  // append DOM to parent DOM
-  if (!this.parent) {
-    throw new Error('Cannot redraw item: no parent attached');
-  }
-  if (!dom.point.parentNode) {
-    var foreground = this.parent.dom.foreground;
-    if (!foreground) {
-      throw new Error('Cannot redraw time axis: parent has no foreground container element');
-    }
-    foreground.appendChild(dom.point);
-  }
-  this.displayed = true;
-
-  // update contents
-  if (this.data.content != this.content) {
-    this.content = this.data.content;
-    if (this.content instanceof Element) {
-      dom.content.innerHTML = '';
-      dom.content.appendChild(this.content);
-    }
-    else if (this.data.content != undefined) {
-      dom.content.innerHTML = this.content;
-    }
-    else {
-      throw new Error('Property "content" missing in item ' + this.data.id);
-    }
-
-    this.dirty = true;
-  }
-
-  // update class
-  var className = (this.data.className? ' ' + this.data.className : '') +
-      (this.selected ? ' selected' : '');
-  if (this.className != className) {
-    this.className = className;
-    dom.point.className  = 'item point' + className;
-    dom.dot.className  = 'item dot' + className;
-
-    this.dirty = true;
-  }
-
-  // recalculate size
-  if (this.dirty) {
-    this.width = dom.point.offsetWidth;
-    this.height = dom.point.offsetHeight;
-    this.props.dot.width = dom.dot.offsetWidth;
-    this.props.dot.height = dom.dot.offsetHeight;
-    this.props.content.height = dom.content.offsetHeight;
-
-    // resize contents
-    dom.content.style.marginLeft = 2 * this.props.dot.width + 'px';
-    //dom.content.style.marginRight = ... + 'px'; // TODO: margin right
-
-    dom.dot.style.top = ((this.height - this.props.dot.height) / 2) + 'px';
-    dom.dot.style.left = (this.props.dot.width / 2) + 'px';
-
-    this.dirty = false;
-  }
-
-  this._repaintDeleteButton(dom.point);
-};
-
-/**
- * Show the item in the DOM (when not already visible). The items DOM will
- * be created when needed.
- */
-ItemPoint.prototype.show = function() {
-  if (!this.displayed) {
-    this.redraw();
-  }
-};
-
-/**
- * Hide the item from the DOM (when visible)
- */
-ItemPoint.prototype.hide = function() {
-  if (this.displayed) {
-    if (this.dom.point.parentNode) {
-      this.dom.point.parentNode.removeChild(this.dom.point);
-    }
-
-    this.top = null;
-    this.left = null;
-
-    this.displayed = false;
-  }
-};
-
-/**
- * Reposition the item horizontally
- * @Override
- */
-ItemPoint.prototype.repositionX = function() {
-  var start = this.conversion.toScreen(this.data.start);
-
-  this.left = start - this.props.dot.width;
-
-  // reposition point
-  this.dom.point.style.left = this.left + 'px';
-};
-
-/**
- * Reposition the item vertically
- * @Override
- */
-ItemPoint.prototype.repositionY = function() {
-  var orientation = this.options.orientation,
-      point = this.dom.point;
-
-  if (orientation == 'top') {
-    point.style.top = this.top + 'px';
-  }
-  else {
-    point.style.top = (this.parent.height - this.top - this.height) + 'px';
-  }
-};
-
-/**
- * @constructor ItemRange
- * @extends Item
- * @param {Object} data             Object containing parameters start, end
- *                                  content, className.
- * @param {{toScreen: function, toTime: function}} conversion
- *                                  Conversion functions from time to screen and vice versa
- * @param {Object} [options]        Configuration options
- *                                  // TODO: describe options
- */
-function ItemRange (data, conversion, options) {
-  this.props = {
-    content: {
-      width: 0
-    }
-  };
-
-  // validate data
-  if (data) {
-    if (data.start == undefined) {
-      throw new Error('Property "start" missing in item ' + data.id);
-    }
-    if (data.end == undefined) {
-      throw new Error('Property "end" missing in item ' + data.id);
-    }
-  }
-
-  Item.call(this, data, conversion, options);
-}
-
-ItemRange.prototype = new Item (null, null, null);
-
-ItemRange.prototype.baseClassName = 'item range';
-
-/**
- * Check whether this item is visible inside given range
- * @returns {{start: Number, end: Number}} range with a timestamp for start and end
- * @returns {boolean} True if visible
- */
-ItemRange.prototype.isVisible = function(range) {
-  // determine visibility
-  return (this.data.start < range.end) && (this.data.end > range.start);
-};
-
-/**
- * Repaint the item
- */
-ItemRange.prototype.redraw = function() {
-  var dom = this.dom;
-  if (!dom) {
-    // create DOM
-    this.dom = {};
-    dom = this.dom;
-
-      // background box
-    dom.box = document.createElement('div');
-    // className is updated in redraw()
-
-    // contents box
-    dom.content = document.createElement('div');
-    dom.content.className = 'content';
-    dom.box.appendChild(dom.content);
-
-    // attach this item as attribute
-    dom.box['timeline-item'] = this;
-  }
-
-  // append DOM to parent DOM
-  if (!this.parent) {
-    throw new Error('Cannot redraw item: no parent attached');
-  }
-  if (!dom.box.parentNode) {
-    var foreground = this.parent.dom.foreground;
-    if (!foreground) {
-      throw new Error('Cannot redraw time axis: parent has no foreground container element');
-    }
-    foreground.appendChild(dom.box);
-  }
-  this.displayed = true;
-
-  // update contents
-  if (this.data.content != this.content) {
-    this.content = this.data.content;
-    if (this.content instanceof Element) {
-      dom.content.innerHTML = '';
-      dom.content.appendChild(this.content);
-    }
-    else if (this.data.content != undefined) {
-      dom.content.innerHTML = this.content;
-    }
-    else {
-      throw new Error('Property "content" missing in item ' + this.data.id);
-    }
-
-    this.dirty = true;
-  }
-
-  // update class
-  var className = (this.data.className ? (' ' + this.data.className) : '') +
-      (this.selected ? ' selected' : '');
-  if (this.className != className) {
-    this.className = className;
-    dom.box.className = this.baseClassName + className;
-
-    this.dirty = true;
-  }
-
-  // recalculate size
-  if (this.dirty) {
-    this.props.content.width = this.dom.content.offsetWidth;
-    this.height = this.dom.box.offsetHeight;
-
-    this.dirty = false;
-  }
-
-  this._repaintDeleteButton(dom.box);
-  this._repaintDragLeft();
-  this._repaintDragRight();
-};
-
-/**
- * Show the item in the DOM (when not already visible). The items DOM will
- * be created when needed.
- */
-ItemRange.prototype.show = function() {
-  if (!this.displayed) {
-    this.redraw();
-  }
-};
-
-/**
- * Hide the item from the DOM (when visible)
- * @return {Boolean} changed
- */
-ItemRange.prototype.hide = function() {
-  if (this.displayed) {
-    var box = this.dom.box;
-
-    if (box.parentNode) {
-      box.parentNode.removeChild(box);
-    }
-
-    this.top = null;
-    this.left = null;
-
-    this.displayed = false;
-  }
-};
-
-/**
- * Reposition the item horizontally
- * @Override
- */
-ItemRange.prototype.repositionX = function() {
-  var props = this.props,
-      parentWidth = this.parent.width,
-      start = this.conversion.toScreen(this.data.start),
-      end = this.conversion.toScreen(this.data.end),
-      padding = this.options.padding,
-      contentLeft;
-
-  // limit the width of the this, as browsers cannot draw very wide divs
-  if (start < -parentWidth) {
-    start = -parentWidth;
-  }
-  if (end > 2 * parentWidth) {
-    end = 2 * parentWidth;
-  }
-
-  // when range exceeds left of the window, position the contents at the left of the visible area
-  if (start < 0) {
-    contentLeft = Math.min(-start,
-        (end - start - props.content.width - 2 * padding));
-    // TODO: remove the need for options.padding. it's terrible.
-  }
-  else {
-    contentLeft = 0;
-  }
-
-  this.left = start;
-  this.width = Math.max(end - start, 1);
-
-  this.dom.box.style.left = this.left + 'px';
-  this.dom.box.style.width = this.width + 'px';
-  this.dom.content.style.left = contentLeft + 'px';
-};
-
-/**
- * Reposition the item vertically
- * @Override
- */
-ItemRange.prototype.repositionY = function() {
-  var orientation = this.options.orientation,
-      box = this.dom.box;
-
-  if (orientation == 'top') {
-    box.style.top = this.top + 'px';
-  }
-  else {
-    box.style.top = (this.parent.height - this.top - this.height) + 'px';
-  }
-};
-
-/**
- * Repaint a drag area on the left side of the range when the range is selected
- * @protected
- */
-ItemRange.prototype._repaintDragLeft = function () {
-  if (this.selected && this.options.editable.updateTime && !this.dom.dragLeft) {
-    // create and show drag area
-    var dragLeft = document.createElement('div');
-    dragLeft.className = 'drag-left';
-    dragLeft.dragLeftItem = this;
-
-    // TODO: this should be redundant?
-    Hammer(dragLeft, {
-      preventDefault: true
-    }).on('drag', function () {
-          //console.log('drag left')
-        });
-
-    this.dom.box.appendChild(dragLeft);
-    this.dom.dragLeft = dragLeft;
-  }
-  else if (!this.selected && this.dom.dragLeft) {
-    // delete drag area
-    if (this.dom.dragLeft.parentNode) {
-      this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft);
-    }
-    this.dom.dragLeft = null;
-  }
-};
-
-/**
- * Repaint a drag area on the right side of the range when the range is selected
- * @protected
- */
-ItemRange.prototype._repaintDragRight = function () {
-  if (this.selected && this.options.editable.updateTime && !this.dom.dragRight) {
-    // create and show drag area
-    var dragRight = document.createElement('div');
-    dragRight.className = 'drag-right';
-    dragRight.dragRightItem = this;
-
-    // TODO: this should be redundant?
-    Hammer(dragRight, {
-      preventDefault: true
-    }).on('drag', function () {
-      //console.log('drag right')
-    });
-
-    this.dom.box.appendChild(dragRight);
-    this.dom.dragRight = dragRight;
-  }
-  else if (!this.selected && this.dom.dragRight) {
-    // delete drag area
-    if (this.dom.dragRight.parentNode) {
-      this.dom.dragRight.parentNode.removeChild(this.dom.dragRight);
-    }
-    this.dom.dragRight = null;
-  }
-};
-
-/**
- * @constructor ItemRangeOverflow
- * @extends ItemRange
- * @param {Object} data             Object containing parameters start, end
- *                                  content, className.
- * @param {{toScreen: function, toTime: function}} conversion
- *                                  Conversion functions from time to screen and vice versa
- * @param {Object} [options]        Configuration options
- *                                  // TODO: describe options
- */
-function ItemRangeOverflow (data, conversion, options) {
-  this.props = {
-    content: {
-      left: 0,
-      width: 0
-    }
-  };
-
-  ItemRange.call(this, data, conversion, options);
-}
-
-ItemRangeOverflow.prototype = new ItemRange (null, null, null);
-
-ItemRangeOverflow.prototype.baseClassName = 'item rangeoverflow';
-
-/**
- * Reposition the item horizontally
- * @Override
- */
-ItemRangeOverflow.prototype.repositionX = function() {
-  var parentWidth = this.parent.width,
-      start = this.conversion.toScreen(this.data.start),
-      end = this.conversion.toScreen(this.data.end),
-      contentLeft;
-
-  // limit the width of the this, as browsers cannot draw very wide divs
-  if (start < -parentWidth) {
-    start = -parentWidth;
-  }
-  if (end > 2 * parentWidth) {
-    end = 2 * parentWidth;
-  }
-
-  // when range exceeds left of the window, position the contents at the left of the visible area
-  contentLeft = Math.max(-start, 0);
-
-  this.left = start;
-  var boxWidth = Math.max(end - start, 1);
-  this.width = boxWidth + this.props.content.width;
-  // Note: The calculation of width is an optimistic calculation, giving
-  //       a width which will not change when moving the Timeline
-  //       So no restacking needed, which is nicer for the eye
-
-  this.dom.box.style.left = this.left + 'px';
-  this.dom.box.style.width = boxWidth + 'px';
-  this.dom.content.style.left = contentLeft + 'px';
-};
-
-/**
- * @constructor Group
- * @param {Number | String} groupId
- * @param {Object} data
- * @param {ItemSet} itemSet
- */
-function Group (groupId, data, itemSet) {
-  this.groupId = groupId;
-
-  this.itemSet = itemSet;
-
-  this.dom = {};
-  this.props = {
-    label: {
-      width: 0,
-      height: 0
-    }
-  };
-  this.className = null;
-
-  this.items = {};        // items filtered by groupId of this group
-  this.visibleItems = []; // items currently visible in window
-  this.orderedItems = {   // items sorted by start and by end
-    byStart: [],
-    byEnd: []
-  };
-
-  this._create();
-
-  this.setData(data);
-}
-
-/**
- * Create DOM elements for the group
- * @private
- */
-Group.prototype._create = function() {
-  var label = document.createElement('div');
-  label.className = 'vlabel';
-  this.dom.label = label;
-
-  var inner = document.createElement('div');
-  inner.className = 'inner';
-  label.appendChild(inner);
-  this.dom.inner = inner;
-
-  var foreground = document.createElement('div');
-  foreground.className = 'group';
-  foreground['timeline-group'] = this;
-  this.dom.foreground = foreground;
-
-  this.dom.background = document.createElement('div');
-  this.dom.background.className = 'group';
-
-  this.dom.axis = document.createElement('div');
-  this.dom.axis.className = 'group';
-
-  // create a hidden marker to detect when the Timelines container is attached
-  // to the DOM, or the style of a parent of the Timeline is changed from
-  // display:none is changed to visible.
-  this.dom.marker = document.createElement('div');
-  this.dom.marker.style.visibility = 'hidden';
-  this.dom.marker.innerHTML = '?';
-  this.dom.background.appendChild(this.dom.marker);
-};
-
-/**
- * Set the group data for this group
- * @param {Object} data   Group data, can contain properties content and className
- */
-Group.prototype.setData = function(data) {
-  // update contents
-  var content = data && data.content;
-  if (content instanceof Element) {
-    this.dom.inner.appendChild(content);
-  }
-  else if (content != undefined) {
-    this.dom.inner.innerHTML = content;
-  }
-  else {
-    this.dom.inner.innerHTML = this.groupId;
-  }
-
-  if (!this.dom.inner.firstChild) {
-    util.addClassName(this.dom.inner, 'hidden');
-  }
-  else {
-    util.removeClassName(this.dom.inner, 'hidden');
-  }
-
-  // update className
-  var className = data && data.className || null;
-  if (className != this.className) {
-    if (this.className) {
-      util.removeClassName(this.dom.label, className);
-      util.removeClassName(this.dom.foreground, className);
-      util.removeClassName(this.dom.background, className);
-      util.removeClassName(this.dom.axis, className);
-    }
-    util.addClassName(this.dom.label, className);
-    util.addClassName(this.dom.foreground, className);
-    util.addClassName(this.dom.background, className);
-    util.addClassName(this.dom.axis, className);
-  }
-};
-
-/**
- * Get the width of the group label
- * @return {number} width
- */
-Group.prototype.getLabelWidth = function() {
-  return this.props.label.width;
-};
-
-
-/**
- * Repaint this group
- * @param {{start: number, end: number}} range
- * @param {{item: number, axis: number}} margin
- * @param {boolean} [restack=false]  Force restacking of all items
- * @return {boolean} Returns true if the group is resized
- */
-Group.prototype.redraw = function(range, margin, restack) {
-  var resized = false;
-
-  this.visibleItems = this._updateVisibleItems(this.orderedItems, this.visibleItems, range);
-
-  // force recalculation of the height of the items when the marker height changed
-  // (due to the Timeline being attached to the DOM or changed from display:none to visible)
-  var markerHeight = this.dom.marker.clientHeight;
-  if (markerHeight != this.lastMarkerHeight) {
-    this.lastMarkerHeight = markerHeight;
-
-    util.forEach(this.items, function (item) {
-      item.dirty = true;
-      if (item.displayed) item.redraw();
-    });
-
-    restack = true;
-  }
-
-  // reposition visible items vertically
-  if (this.itemSet.options.stack) { // TODO: ugly way to access options...
-    stack.stack(this.visibleItems, margin, restack);
-  }
-  else { // no stacking
-    stack.nostack(this.visibleItems, margin);
-  }
-
-  // recalculate the height of the group
-  var height;
-  var visibleItems = this.visibleItems;
-  if (visibleItems.length) {
-    var min = visibleItems[0].top;
-    var max = visibleItems[0].top + visibleItems[0].height;
-    util.forEach(visibleItems, function (item) {
-      min = Math.min(min, item.top);
-      max = Math.max(max, (item.top + item.height));
-    });
-    height = (max - min) + margin.axis + margin.item;
-  }
-  else {
-    height = margin.axis + margin.item;
-  }
-  height = Math.max(height, this.props.label.height);
-
-  // calculate actual size and position
-  var foreground = this.dom.foreground;
-  this.top = foreground.offsetTop;
-  this.left = foreground.offsetLeft;
-  this.width = foreground.offsetWidth;
-  resized = util.updateProperty(this, 'height', height) || resized;
-
-  // recalculate size of label
-  resized = util.updateProperty(this.props.label, 'width', this.dom.inner.clientWidth) || resized;
-  resized = util.updateProperty(this.props.label, 'height', this.dom.inner.clientHeight) || resized;
-
-  // apply new height
-  foreground.style.height  = height + 'px';
-  this.dom.label.style.height = height + 'px';
-
-  // update vertical position of items after they are re-stacked and the height of the group is calculated
-  for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
-    var item = this.visibleItems[i];
-    item.repositionY();
-  }
-
-  return resized;
-};
-
-/**
- * Show this group: attach to the DOM
- */
-Group.prototype.show = function() {
-  if (!this.dom.label.parentNode) {
-    this.itemSet.dom.labelSet.appendChild(this.dom.label);
-  }
-
-  if (!this.dom.foreground.parentNode) {
-    this.itemSet.dom.foreground.appendChild(this.dom.foreground);
-  }
-
-  if (!this.dom.background.parentNode) {
-    this.itemSet.dom.background.appendChild(this.dom.background);
-  }
-
-  if (!this.dom.axis.parentNode) {
-    this.itemSet.dom.axis.appendChild(this.dom.axis);
-  }
-};
-
-/**
- * Hide this group: remove from the DOM
- */
-Group.prototype.hide = function() {
-  var label = this.dom.label;
-  if (label.parentNode) {
-    label.parentNode.removeChild(label);
-  }
-
-  var foreground = this.dom.foreground;
-  if (foreground.parentNode) {
-    foreground.parentNode.removeChild(foreground);
-  }
-
-  var background = this.dom.background;
-  if (background.parentNode) {
-    background.parentNode.removeChild(background);
-  }
-
-  var axis = this.dom.axis;
-  if (axis.parentNode) {
-    axis.parentNode.removeChild(axis);
-  }
-};
-
-/**
- * Add an item to the group
- * @param {Item} item
- */
-Group.prototype.add = function(item) {
-  this.items[item.id] = item;
-  item.setParent(this);
-
-  if (item instanceof ItemRange && this.visibleItems.indexOf(item) == -1) {
-    var range = this.itemSet.body.range; // TODO: not nice accessing the range like this
-    this._checkIfVisible(item, this.visibleItems, range);
-  }
-};
-
-/**
- * Remove an item from the group
- * @param {Item} item
- */
-Group.prototype.remove = function(item) {
-  delete this.items[item.id];
-  item.setParent(this.itemSet);
-
-  // remove from visible items
-  var index = this.visibleItems.indexOf(item);
-  if (index != -1) this.visibleItems.splice(index, 1);
-
-  // TODO: also remove from ordered items?
-};
-
-/**
- * Remove an item from the corresponding DataSet
- * @param {Item} item
- */
-Group.prototype.removeFromDataSet = function(item) {
-  this.itemSet.removeItem(item.id);
-};
-
-/**
- * Reorder the items
- */
-Group.prototype.order = function() {
-  var array = util.toArray(this.items);
-  this.orderedItems.byStart = array;
-  this.orderedItems.byEnd = this._constructByEndArray(array);
-
-  stack.orderByStart(this.orderedItems.byStart);
-  stack.orderByEnd(this.orderedItems.byEnd);
-};
-
-/**
- * Create an array containing all items being a range (having an end date)
- * @param {Item[]} array
- * @returns {ItemRange[]}
- * @private
- */
-Group.prototype._constructByEndArray = function(array) {
-  var endArray = [];
-
-  for (var i = 0; i < array.length; i++) {
-    if (array[i] instanceof ItemRange) {
-      endArray.push(array[i]);
-    }
-  }
-  return endArray;
-};
-
-/**
- * Update the visible items
- * @param {{byStart: Item[], byEnd: Item[]}} orderedItems   All items ordered by start date and by end date
- * @param {Item[]} visibleItems                             The previously visible items.
- * @param {{start: number, end: number}} range              Visible range
- * @return {Item[]} visibleItems                            The new visible items.
- * @private
- */
-Group.prototype._updateVisibleItems = function(orderedItems, visibleItems, range) {
-  var initialPosByStart,
-      newVisibleItems = [],
-      i;
-
-  // first check if the items that were in view previously are still in view.
-  // this handles the case for the ItemRange that is both before and after the current one.
-  if (visibleItems.length > 0) {
-    for (i = 0; i < visibleItems.length; i++) {
-      this._checkIfVisible(visibleItems[i], newVisibleItems, range);
-    }
-  }
-
-  // If there were no visible items previously, use binarySearch to find a visible ItemPoint or ItemRange (based on startTime)
-  if (newVisibleItems.length == 0) {
-    initialPosByStart = this._binarySearch(orderedItems, range, false);
-  }
-  else {
-    initialPosByStart = orderedItems.byStart.indexOf(newVisibleItems[0]);
-  }
-
-  // use visible search to find a visible ItemRange (only based on endTime)
-  var initialPosByEnd = this._binarySearch(orderedItems, range, true);
-
-  // if we found a initial ID to use, trace it up and down until we meet an invisible item.
-  if (initialPosByStart != -1) {
-    for (i = initialPosByStart; i >= 0; i--) {
-      if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;}
-    }
-    for (i = initialPosByStart + 1; i < orderedItems.byStart.length; i++) {
-      if (this._checkIfInvisible(orderedItems.byStart[i], newVisibleItems, range)) {break;}
-    }
-  }
-
-  // if we found a initial ID to use, trace it up and down until we meet an invisible item.
-  if (initialPosByEnd != -1) {
-    for (i = initialPosByEnd; i >= 0; i--) {
-      if (this._checkIfInvisible(orderedItems.byEnd[i], newVisibleItems, range)) {break;}
-    }
-    for (i = initialPosByEnd + 1; i < orderedItems.byEnd.length; i++) {
-      if (this._checkIfInvisible(orderedItems.byEnd[i], newVisibleItems, range)) {break;}
-    }
-  }
-
-  return newVisibleItems;
-};
-
-/**
- * This function does a binary search for a visible item. The user can select either the this.orderedItems.byStart or .byEnd
- * arrays. This is done by giving a boolean value true if you want to use the byEnd.
- * This is done to be able to select the correct if statement (we do not want to check if an item is visible, we want to check
- * if the time we selected (start or end) is within the current range).
- *
- * The trick is that every interval has to either enter the screen at the initial load or by dragging. The case of the ItemRange that is
- * before and after the current range is handled by simply checking if it was in view before and if it is again. For all the rest,
- * either the start OR end time has to be in the range.
- *
- * @param {{byStart: Item[], byEnd: Item[]}} orderedItems
- * @param {{start: number, end: number}} range
- * @param {Boolean} byEnd
- * @returns {number}
- * @private
- */
-Group.prototype._binarySearch = function(orderedItems, range, byEnd) {
-  var array = [];
-  var byTime = byEnd ? 'end' : 'start';
-  if (byEnd == true) {array = orderedItems.byEnd;  }
-  else               {array = orderedItems.byStart;}
-
-  var interval = range.end - range.start;
-
-  var found = false;
-  var low = 0;
-  var high = array.length;
-  var guess = Math.floor(0.5*(high+low));
-  var newGuess;
-
-  if (high == 0) {guess = -1;}
-  else if (high == 1) {
-    if ((array[guess].data[byTime] > range.start - interval) && (array[guess].data[byTime] < range.end)) {
-      guess =  0;
-    }
-    else {
-      guess = -1;
-    }
-  }
-  else {
-    high -= 1;
-    while (found == false) {
-      if ((array[guess].data[byTime] > range.start - interval) && (array[guess].data[byTime] < range.end)) {
-        found = true;
-      }
-      else {
-        if (array[guess].data[byTime] < range.start - interval) { // it is too small --> increase low
-          low = Math.floor(0.5*(high+low));
-        }
-        else {  // it is too big --> decrease high
-          high = Math.floor(0.5*(high+low));
-        }
-        newGuess = Math.floor(0.5*(high+low));
-        // not in list;
-        if (guess == newGuess) {
-          guess = -1;
-          found = true;
-        }
-        else {
-          guess = newGuess;
-        }
-      }
-    }
-  }
-  return guess;
-};
-
-/**
- * this function checks if an item is invisible. If it is NOT we make it visible
- * and add it to the global visible items. If it is, return true.
- *
- * @param {Item} item
- * @param {Item[]} visibleItems
- * @param {{start:number, end:number}} range
- * @returns {boolean}
- * @private
- */
-Group.prototype._checkIfInvisible = function(item, visibleItems, range) {
-  if (item.isVisible(range)) {
-    if (!item.displayed) item.show();
-    item.repositionX();
-    if (visibleItems.indexOf(item) == -1) {
-      visibleItems.push(item);
-    }
-    return false;
-  }
-  else {
-    return true;
-  }
-};
-
-/**
- * this function is very similar to the _checkIfInvisible() but it does not
- * return booleans, hides the item if it should not be seen and always adds to
- * the visibleItems.
- * this one is for brute forcing and hiding.
- *
- * @param {Item} item
- * @param {Array} visibleItems
- * @param {{start:number, end:number}} range
- * @private
- */
-Group.prototype._checkIfVisible = function(item, visibleItems, range) {
-  if (item.isVisible(range)) {
-    if (!item.displayed) item.show();
-    // reposition item horizontally
-    item.repositionX();
-    visibleItems.push(item);
-  }
-  else {
-    if (item.displayed) item.hide();
-  }
-};
-
-/**
- * Create a timeline visualization
- * @param {HTMLElement} container
- * @param {vis.DataSet | Array | google.visualization.DataTable} [items]
- * @param {Object} [options]  See Timeline.setOptions for the available options.
- * @constructor
- */
-function Timeline (container, items, options) {
-  var me = this;
-  this.defaultOptions = {
-    start: null,
-    end:   null,
-
-    autoResize: true,
-
-    orientation: 'bottom',
-    width: null,
-    height: null,
-    maxHeight: null,
-    minHeight: null
-  };
-  this.options = util.deepExtend({}, this.defaultOptions);
-
-  // Create the DOM, props, and emitter
-  this._create(container);
-
-  // all components listed here will be repainted automatically
-  this.components = [];
-
-  this.body = {
-    dom: this.dom,
-    domProps: this.props,
-    emitter: {
-      on: this.on.bind(this),
-      off: this.off.bind(this),
-      emit: this.emit.bind(this)
-    },
-    util: {
-      snap: null, // will be specified after TimeAxis is created
-      toScreen: me._toScreen.bind(me),
-      toTime: me._toTime.bind(me)
-    }
-  };
-
-  // range
-  this.range = new Range(this.body);
-  this.components.push(this.range);
-  this.body.range = this.range;
-
-  // time axis
-  this.timeAxis = new TimeAxis(this.body);
-  this.components.push(this.timeAxis);
-  this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis);
-
-  // current time bar
-  this.currentTime = new CurrentTime(this.body);
-  this.components.push(this.currentTime);
-
-  // custom time bar
-  // Note: time bar will be attached in this.setOptions when selected
-  this.customTime = new CustomTime(this.body);
-  this.components.push(this.customTime);
-
-  // item set
-  this.itemSet = new ItemSet(this.body);
-  this.components.push(this.itemSet);
-
-  this.itemsData = null;      // DataSet
-  this.groupsData = null;     // DataSet
-
-  // apply options
-  if (options) {
-    this.setOptions(options);
-  }
-
-  // create itemset
-  if (items) {
-    this.setItems(items);
-  }
-  else {
-    this.redraw();
-  }
-}
-
-// turn Timeline into an event emitter
-Emitter(Timeline.prototype);
-
-/**
- * Create the main DOM for the Timeline: a root panel containing left, right,
- * top, bottom, content, and background panel.
- * @param {Element} container  The container element where the Timeline will
- *                             be attached.
- * @private
- */
-Timeline.prototype._create = function (container) {
-  this.dom = {};
-
-  this.dom.root                 = document.createElement('div');
-  this.dom.background           = document.createElement('div');
-  this.dom.backgroundVertical   = document.createElement('div');
-  this.dom.backgroundHorizontal = document.createElement('div');
-  this.dom.centerContainer      = document.createElement('div');
-  this.dom.leftContainer        = document.createElement('div');
-  this.dom.rightContainer       = document.createElement('div');
-  this.dom.center               = document.createElement('div');
-  this.dom.left                 = document.createElement('div');
-  this.dom.right                = document.createElement('div');
-  this.dom.top                  = document.createElement('div');
-  this.dom.bottom               = document.createElement('div');
-  this.dom.shadowTop            = document.createElement('div');
-  this.dom.shadowBottom         = document.createElement('div');
-  this.dom.shadowTopLeft        = document.createElement('div');
-  this.dom.shadowBottomLeft     = document.createElement('div');
-  this.dom.shadowTopRight       = document.createElement('div');
-  this.dom.shadowBottomRight    = document.createElement('div');
-
-  this.dom.background.className           = 'vispanel background';
-  this.dom.backgroundVertical.className   = 'vispanel background vertical';
-  this.dom.backgroundHorizontal.className = 'vispanel background horizontal';
-  this.dom.centerContainer.className      = 'vispanel center';
-  this.dom.leftContainer.className        = 'vispanel left';
-  this.dom.rightContainer.className       = 'vispanel right';
-  this.dom.top.className                  = 'vispanel top';
-  this.dom.bottom.className               = 'vispanel bottom';
-  this.dom.left.className                 = 'content';
-  this.dom.center.className               = 'content';
-  this.dom.right.className                = 'content';
-  this.dom.shadowTop.className            = 'shadow top';
-  this.dom.shadowBottom.className         = 'shadow bottom';
-  this.dom.shadowTopLeft.className        = 'shadow top';
-  this.dom.shadowBottomLeft.className     = 'shadow bottom';
-  this.dom.shadowTopRight.className       = 'shadow top';
-  this.dom.shadowBottomRight.className    = 'shadow bottom';
-
-  this.dom.root.appendChild(this.dom.background);
-  this.dom.root.appendChild(this.dom.backgroundVertical);
-  this.dom.root.appendChild(this.dom.backgroundHorizontal);
-  this.dom.root.appendChild(this.dom.centerContainer);
-  this.dom.root.appendChild(this.dom.leftContainer);
-  this.dom.root.appendChild(this.dom.rightContainer);
-  this.dom.root.appendChild(this.dom.top);
-  this.dom.root.appendChild(this.dom.bottom);
-
-  this.dom.centerContainer.appendChild(this.dom.center);
-  this.dom.leftContainer.appendChild(this.dom.left);
-  this.dom.rightContainer.appendChild(this.dom.right);
-
-  this.dom.centerContainer.appendChild(this.dom.shadowTop);
-  this.dom.centerContainer.appendChild(this.dom.shadowBottom);
-  this.dom.leftContainer.appendChild(this.dom.shadowTopLeft);
-  this.dom.leftContainer.appendChild(this.dom.shadowBottomLeft);
-  this.dom.rightContainer.appendChild(this.dom.shadowTopRight);
-  this.dom.rightContainer.appendChild(this.dom.shadowBottomRight);
-
-  this.on('rangechange', this.redraw.bind(this));
-  this.on('change', this.redraw.bind(this));
-  this.on('touch', this._onTouch.bind(this));
-  this.on('pinch', this._onPinch.bind(this));
-  this.on('dragstart', this._onDragStart.bind(this));
-  this.on('drag', this._onDrag.bind(this));
-
-  // create event listeners for all interesting events, these events will be
-  // emitted via emitter
-  this.hammer = Hammer(this.dom.root, {
-    prevent_default: true
-  });
-  this.listeners = {};
-
-  var me = this;
-  var events = [
-    'touch', 'pinch',
-    'tap', 'doubletap', 'hold',
-    'dragstart', 'drag', 'dragend',
-    'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox
-  ];
-  events.forEach(function (event) {
-    var listener = function () {
-      var args = [event].concat(Array.prototype.slice.call(arguments, 0));
-      me.emit.apply(me, args);
-    };
-    me.hammer.on(event, listener);
-    me.listeners[event] = listener;
-  });
-
-  // size properties of each of the panels
-  this.props = {
-    root: {},
-    background: {},
-    centerContainer: {},
-    leftContainer: {},
-    rightContainer: {},
-    center: {},
-    left: {},
-    right: {},
-    top: {},
-    bottom: {},
-    border: {},
-    scrollTop: 0,
-    scrollTopMin: 0
-  };
-  this.touch = {}; // store state information needed for touch events
-
-  // attach the root panel to the provided container
-  if (!container) throw new Error('No container provided');
-  container.appendChild(this.dom.root);
-};
-
-/**
- * Destroy the Timeline, clean up all DOM elements and event listeners.
- */
-Timeline.prototype.destroy = function () {
-  // unbind datasets
-  this.clear();
-
-  // remove all event listeners
-  this.off();
-
-  // stop checking for changed size
-  this._stopAutoResize();
-
-  // remove from DOM
-  if (this.dom.root.parentNode) {
-    this.dom.root.parentNode.removeChild(this.dom.root);
-  }
-  this.dom = null;
-
-  // cleanup hammer touch events
-  for (var event in this.listeners) {
-    if (this.listeners.hasOwnProperty(event)) {
-      delete this.listeners[event];
-    }
-  }
-  this.listeners = null;
-  this.hammer = null;
-
-  // give all components the opportunity to cleanup
-  this.components.forEach(function (component) {
-    component.destroy();
-  });
-
-  this.body = null;
-};
-
-/**
- * Set options. Options will be passed to all components loaded in the Timeline.
- * @param {Object} [options]
- *                           {String} orientation
- *                              Vertical orientation for the Timeline,
- *                              can be 'bottom' (default) or 'top'.
- *                           {String | Number} width
- *                              Width for the timeline, a number in pixels or
- *                              a css string like '1000px' or '75%'. '100%' by default.
- *                           {String | Number} height
- *                              Fixed height for the Timeline, a number in pixels or
- *                              a css string like '400px' or '75%'. If undefined,
- *                              The Timeline will automatically size such that
- *                              its contents fit.
- *                           {String | Number} minHeight
- *                              Minimum height for the Timeline, a number in pixels or
- *                              a css string like '400px' or '75%'.
- *                           {String | Number} maxHeight
- *                              Maximum height for the Timeline, a number in pixels or
- *                              a css string like '400px' or '75%'.
- *                           {Number | Date | String} start
- *                              Start date for the visible window
- *                           {Number | Date | String} end
- *                              End date for the visible window
- */
-Timeline.prototype.setOptions = function (options) {
-  if (options) {
-    // copy the known options
-    var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'orientation'];
-    util.selectiveExtend(fields, this.options, options);
-
-    // enable/disable autoResize
-    this._initAutoResize();
-  }
-
-  // propagate options to all components
-  this.components.forEach(function (component) {
-    component.setOptions(options);
-  });
-
-  // TODO: remove deprecation error one day (deprecated since version 0.8.0)
-  if (options && options.order) {
-    throw new Error('Option order is deprecated. There is no replacement for this feature.');
-  }
-
-  // redraw everything
-  this.redraw();
-};
-
-/**
- * Set a custom time bar
- * @param {Date} time
- */
-Timeline.prototype.setCustomTime = function (time) {
-  if (!this.customTime) {
-    throw new Error('Cannot get custom time: Custom time bar is not enabled');
-  }
-
-  this.customTime.setCustomTime(time);
-};
-
-/**
- * Retrieve the current custom time.
- * @return {Date} customTime
- */
-Timeline.prototype.getCustomTime = function() {
-  if (!this.customTime) {
-    throw new Error('Cannot get custom time: Custom time bar is not enabled');
-  }
-
-  return this.customTime.getCustomTime();
-};
-
-/**
- * Set items
- * @param {vis.DataSet | Array | google.visualization.DataTable | null} items
- */
-Timeline.prototype.setItems = function(items) {
-  var initialLoad = (this.itemsData == null);
-
-  // convert to type DataSet when needed
-  var newDataSet;
-  if (!items) {
-    newDataSet = null;
-  }
-  else if (items instanceof DataSet || items instanceof DataView) {
-    newDataSet = items;
-  }
-  else {
-    // turn an array into a dataset
-    newDataSet = new DataSet(items, {
-      type: {
-        start: 'Date',
-        end: 'Date'
-      }
-    });
-  }
-
-  // set items
-  this.itemsData = newDataSet;
-  this.itemSet && this.itemSet.setItems(newDataSet);
-
-  if (initialLoad && ('start' in this.options || 'end' in this.options)) {
-    this.fit();
-
-    var start = ('start' in this.options) ? util.convert(this.options.start, 'Date') : null;
-    var end   = ('end' in this.options)   ? util.convert(this.options.end, 'Date') : null;
-
-    this.setWindow(start, end);
-  }
-};
-
-/**
- * Set groups
- * @param {vis.DataSet | Array | google.visualization.DataTable} groups
- */
-Timeline.prototype.setGroups = function(groups) {
-  // convert to type DataSet when needed
-  var newDataSet;
-  if (!groups) {
-    newDataSet = null;
-  }
-  else if (groups instanceof DataSet || groups instanceof DataView) {
-    newDataSet = groups;
-  }
-  else {
-    // turn an array into a dataset
-    newDataSet = new DataSet(groups);
-  }
-
-  this.groupsData = newDataSet;
-  this.itemSet.setGroups(newDataSet);
-};
-
-/**
- * Clear the Timeline. By Default, items, groups and options are cleared.
- * Example usage:
- *
- *     timeline.clear();                // clear items, groups, and options
- *     timeline.clear({options: true}); // clear options only
- *
- * @param {Object} [what]      Optionally specify what to clear. By default:
- *                             {items: true, groups: true, options: true}
- */
-Timeline.prototype.clear = function(what) {
-  // clear items
-  if (!what || what.items) {
-    this.setItems(null);
-  }
-
-  // clear groups
-  if (!what || what.groups) {
-    this.setGroups(null);
-  }
-
-  // clear options of timeline and of each of the components
-  if (!what || what.options) {
-    this.components.forEach(function (component) {
-      component.setOptions(component.defaultOptions);
-    });
-
-    this.setOptions(this.defaultOptions); // this will also do a redraw
-  }
-};
-
-/**
- * Set Timeline window such that it fits all items
- */
-Timeline.prototype.fit = function() {
-  // apply the data range as range
-  var dataRange = this.getItemRange();
-
-  // add 5% space on both sides
-  var start = dataRange.min;
-  var end = dataRange.max;
-  if (start != null && end != null) {
-    var interval = (end.valueOf() - start.valueOf());
-    if (interval <= 0) {
-      // prevent an empty interval
-      interval = 24 * 60 * 60 * 1000; // 1 day
-    }
-    start = new Date(start.valueOf() - interval * 0.05);
-    end = new Date(end.valueOf() + interval * 0.05);
-  }
-
-  // skip range set if there is no start and end date
-  if (start === null && end === null) {
-    return;
-  }
-
-  this.range.setRange(start, end);
-};
-
-/**
- * Get the data range of the item set.
- * @returns {{min: Date, max: Date}} range  A range with a start and end Date.
- *                                          When no minimum is found, min==null
- *                                          When no maximum is found, max==null
- */
-Timeline.prototype.getItemRange = function() {
-  // calculate min from start filed
-  var itemsData = this.itemsData,
-      min = null,
-      max = null;
-
-  if (itemsData) {
-    // calculate the minimum value of the field 'start'
-    var minItem = itemsData.min('start');
-    min = minItem ? util.convert(minItem.start, 'Date').valueOf() : null;
-    // Note: we convert first to Date and then to number because else
-    // a conversion from ISODate to Number will fail
-
-    // calculate maximum value of fields 'start' and 'end'
-    var maxStartItem = itemsData.max('start');
-    if (maxStartItem) {
-      max = util.convert(maxStartItem.start, 'Date').valueOf();
-    }
-    var maxEndItem = itemsData.max('end');
-    if (maxEndItem) {
-      if (max == null) {
-        max = util.convert(maxEndItem.end, 'Date').valueOf();
-      }
-      else {
-        max = Math.max(max, util.convert(maxEndItem.end, 'Date').valueOf());
-      }
-    }
-  }
-
-  return {
-    min: (min != null) ? new Date(min) : null,
-    max: (max != null) ? new Date(max) : null
-  };
-};
-
-/**
- * Set selected items by their id. Replaces the current selection
- * Unknown id's are silently ignored.
- * @param {Array} [ids] An array with zero or more id's of the items to be
- *                      selected. If ids is an empty array, all items will be
- *                      unselected.
- */
-Timeline.prototype.setSelection = function(ids) {
-  this.itemSet && this.itemSet.setSelection(ids);
-};
-
-/**
- * Get the selected items by their id
- * @return {Array} ids  The ids of the selected items
- */
-Timeline.prototype.getSelection = function() {
-  return this.itemSet && this.itemSet.getSelection() || [];
-};
-
-/**
- * Set the visible window. Both parameters are optional, you can change only
- * start or only end. Syntax:
- *
- *     TimeLine.setWindow(start, end)
- *     TimeLine.setWindow(range)
- *
- * Where start and end can be a Date, number, or string, and range is an
- * object with properties start and end.
- *
- * @param {Date | Number | String | Object} [start] Start date of visible window
- * @param {Date | Number | String} [end]   End date of visible window
- */
-Timeline.prototype.setWindow = function(start, end) {
-  if (arguments.length == 1) {
-    var range = arguments[0];
-    this.range.setRange(range.start, range.end);
-  }
-  else {
-    this.range.setRange(start, end);
-  }
-};
-
-/**
- * Get the visible window
- * @return {{start: Date, end: Date}}   Visible range
- */
-Timeline.prototype.getWindow = function() {
-  var range = this.range.getRange();
-  return {
-    start: new Date(range.start),
-    end: new Date(range.end)
-  };
-};
-
-/**
- * Force a redraw of the Timeline. Can be useful to manually redraw when
- * option autoResize=false
- */
-Timeline.prototype.redraw = function() {
-  var resized = false,
-      options = this.options,
-      props = this.props,
-      dom = this.dom;
-
-  if (!dom) return; // when destroyed
-
-  // update class names
-  dom.root.className = 'vis timeline root ' + options.orientation;
-
-  // update root width and height options
-  dom.root.style.maxHeight = util.option.asSize(options.maxHeight, '');
-  dom.root.style.minHeight = util.option.asSize(options.minHeight, '');
-  dom.root.style.width = util.option.asSize(options.width, '');
-
-  // calculate border widths
-  props.border.left   = (dom.centerContainer.offsetWidth - dom.centerContainer.clientWidth) / 2;
-  props.border.right  = props.border.left;
-  props.border.top    = (dom.centerContainer.offsetHeight - dom.centerContainer.clientHeight) / 2;
-  props.border.bottom = props.border.top;
-  var borderRootHeight= dom.root.offsetHeight - dom.root.clientHeight;
-  var borderRootWidth = dom.root.offsetWidth - dom.root.clientWidth;
-
-  // calculate the heights. If any of the side panels is empty, we set the height to
-  // minus the border width, such that the border will be invisible
-  props.center.height = dom.center.offsetHeight;
-  props.left.height   = dom.left.offsetHeight;
-  props.right.height  = dom.right.offsetHeight;
-  props.top.height    = dom.top.clientHeight    || -props.border.top;
-  props.bottom.height = dom.bottom.clientHeight || -props.border.bottom;
-
-  // TODO: compensate borders when any of the panels is empty.
-
-  // apply auto height
-  // TODO: only calculate autoHeight when needed (else we cause an extra reflow/repaint of the DOM)
-  var contentHeight = Math.max(props.left.height, props.center.height, props.right.height);
-  var autoHeight = props.top.height + contentHeight + props.bottom.height +
-      borderRootHeight + props.border.top + props.border.bottom;
-  dom.root.style.height = util.option.asSize(options.height, autoHeight + 'px');
-
-  // calculate heights of the content panels
-  props.root.height = dom.root.offsetHeight;
-  props.background.height = props.root.height - borderRootHeight;
-  var containerHeight = props.root.height - props.top.height - props.bottom.height -
-      borderRootHeight;
-  props.centerContainer.height  = containerHeight;
-  props.leftContainer.height    = containerHeight;
-  props.rightContainer.height   = props.leftContainer.height;
-
-  // calculate the widths of the panels
-  props.root.width = dom.root.offsetWidth;
-  props.background.width = props.root.width - borderRootWidth;
-  props.left.width = dom.leftContainer.clientWidth   || -props.border.left;
-  props.leftContainer.width = props.left.width;
-  props.right.width = dom.rightContainer.clientWidth || -props.border.right;
-  props.rightContainer.width = props.right.width;
-  var centerWidth = props.root.width - props.left.width - props.right.width - borderRootWidth;
-  props.center.width          = centerWidth;
-  props.centerContainer.width = centerWidth;
-  props.top.width             = centerWidth;
-  props.bottom.width          = centerWidth;
-
-  // resize the panels
-  dom.background.style.height           = props.background.height + 'px';
-  dom.backgroundVertical.style.height   = props.background.height + 'px';
-  dom.backgroundHorizontal.style.height = props.centerContainer.height + 'px';
-  dom.centerContainer.style.height      = props.centerContainer.height + 'px';
-  dom.leftContainer.style.height        = props.leftContainer.height + 'px';
-  dom.rightContainer.style.height       = props.rightContainer.height + 'px';
-
-  dom.background.style.width            = props.background.width + 'px';
-  dom.backgroundVertical.style.width    = props.centerContainer.width + 'px';
-  dom.backgroundHorizontal.style.width  = props.background.width + 'px';
-  dom.centerContainer.style.width       = props.center.width + 'px';
-  dom.top.style.width                   = props.top.width + 'px';
-  dom.bottom.style.width                = props.bottom.width + 'px';
-
-  // reposition the panels
-  dom.background.style.left           = '0';
-  dom.background.style.top            = '0';
-  dom.backgroundVertical.style.left   = props.left.width + 'px';
-  dom.backgroundVertical.style.top    = '0';
-  dom.backgroundHorizontal.style.left = '0';
-  dom.backgroundHorizontal.style.top  = props.top.height + 'px';
-  dom.centerContainer.style.left      = props.left.width + 'px';
-  dom.centerContainer.style.top       = props.top.height + 'px';
-  dom.leftContainer.style.left        = '0';
-  dom.leftContainer.style.top         = props.top.height + 'px';
-  dom.rightContainer.style.left       = (props.left.width + props.center.width) + 'px';
-  dom.rightContainer.style.top        = props.top.height + 'px';
-  dom.top.style.left                  = props.left.width + 'px';
-  dom.top.style.top                   = '0';
-  dom.bottom.style.left               = props.left.width + 'px';
-  dom.bottom.style.top                = (props.top.height + props.centerContainer.height) + 'px';
-
-  // update the scrollTop, feasible range for the offset can be changed
-  // when the height of the Timeline or of the contents of the center changed
-  this._updateScrollTop();
-
-  // reposition the scrollable contents
-  var offset = this.props.scrollTop;
-  if (options.orientation == 'bottom') {
-    offset += Math.max(this.props.centerContainer.height - this.props.center.height, 0);
-  }
-  dom.center.style.left = '0';
-  dom.center.style.top  = offset + 'px';
-  dom.left.style.left   = '0';
-  dom.left.style.top    = offset + 'px';
-  dom.right.style.left  = '0';
-  dom.right.style.top   = offset + 'px';
-
-  // show shadows when vertical scrolling is available
-  var visibilityTop = this.props.scrollTop == 0 ? 'hidden' : '';
-  var visibilityBottom = this.props.scrollTop == this.props.scrollTopMin ? 'hidden' : '';
-  dom.shadowTop.style.visibility          = visibilityTop;
-  dom.shadowBottom.style.visibility       = visibilityBottom;
-  dom.shadowTopLeft.style.visibility      = visibilityTop;
-  dom.shadowBottomLeft.style.visibility   = visibilityBottom;
-  dom.shadowTopRight.style.visibility     = visibilityTop;
-  dom.shadowBottomRight.style.visibility  = visibilityBottom;
-
-  // redraw all components
-  this.components.forEach(function (component) {
-    resized = component.redraw() || resized;
-  });
-  if (resized) {
-    // keep repainting until all sizes are settled
-    this.redraw();
-  }
-};
-
-// TODO: deprecated since version 1.1.0, remove some day
-Timeline.prototype.repaint = function () {
-    throw new Error('Function repaint is deprecated. Use redraw instead.');
-};
-
-/**
- * Convert a position on screen (pixels) to a datetime
- * @param {int}     x    Position on the screen in pixels
- * @return {Date}   time The datetime the corresponds with given position x
- * @private
- */
-// TODO: move this function to Range
-Timeline.prototype._toTime = function(x) {
-  var conversion = this.range.conversion(this.props.center.width);
-  return new Date(x / conversion.scale + conversion.offset);
-};
-
-/**
- * Convert a datetime (Date object) into a position on the screen
- * @param {Date}   time A date
- * @return {int}   x    The position on the screen in pixels which corresponds
- *                      with the given date.
- * @private
- */
-// TODO: move this function to Range
-Timeline.prototype._toScreen = function(time) {
-  var conversion = this.range.conversion(this.props.center.width);
-  return (time.valueOf() - conversion.offset) * conversion.scale;
-};
-
-/**
- * Initialize watching when option autoResize is true
- * @private
- */
-Timeline.prototype._initAutoResize = function () {
-  if (this.options.autoResize == true) {
-    this._startAutoResize();
-  }
-  else {
-    this._stopAutoResize();
-  }
-};
-
-/**
- * Watch for changes in the size of the container. On resize, the Panel will
- * automatically redraw itself.
- * @private
- */
-Timeline.prototype._startAutoResize = function () {
-  var me = this;
-
-  this._stopAutoResize();
-
-  this._onResize = function() {
-    if (me.options.autoResize != true) {
-      // stop watching when the option autoResize is changed to false
-      me._stopAutoResize();
-      return;
-    }
-
-    if (me.dom.root) {
-      // check whether the frame is resized
-      if ((me.dom.root.clientWidth != me.props.lastWidth) ||
-          (me.dom.root.clientHeight != me.props.lastHeight)) {
-        me.props.lastWidth = me.dom.root.clientWidth;
-        me.props.lastHeight = me.dom.root.clientHeight;
-
-        me.emit('change');
-      }
-    }
-  };
-
-  // add event listener to window resize
-  util.addEventListener(window, 'resize', this._onResize);
-
-  this.watchTimer = setInterval(this._onResize, 1000);
-};
-
-/**
- * Stop watching for a resize of the frame.
- * @private
- */
-Timeline.prototype._stopAutoResize = function () {
-  if (this.watchTimer) {
-    clearInterval(this.watchTimer);
-    this.watchTimer = undefined;
-  }
-
-  // remove event listener on window.resize
-  util.removeEventListener(window, 'resize', this._onResize);
-  this._onResize = null;
-};
-
-/**
- * Start moving the timeline vertically
- * @param {Event} event
- * @private
- */
-Timeline.prototype._onTouch = function (event) {
-  this.touch.allowDragging = true;
-};
-
-/**
- * Start moving the timeline vertically
- * @param {Event} event
- * @private
- */
-Timeline.prototype._onPinch = function (event) {
-  this.touch.allowDragging = false;
-};
-
-/**
- * Start moving the timeline vertically
- * @param {Event} event
- * @private
- */
-Timeline.prototype._onDragStart = function (event) {
-  this.touch.initialScrollTop = this.props.scrollTop;
-};
-
-/**
- * Move the timeline vertically
- * @param {Event} event
- * @private
- */
-Timeline.prototype._onDrag = function (event) {
-  // refuse to drag when we where pinching to prevent the timeline make a jump
-  // when releasing the fingers in opposite order from the touch screen
-  if (!this.touch.allowDragging) return;
-
-  var delta = event.gesture.deltaY;
-
-  var oldScrollTop = this._getScrollTop();
-  var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta);
-
-  if (newScrollTop != oldScrollTop) {
-    this.redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already
-  }
-};
-
-/**
- * Apply a scrollTop
- * @param {Number} scrollTop
- * @returns {Number} scrollTop  Returns the applied scrollTop
- * @private
- */
-Timeline.prototype._setScrollTop = function (scrollTop) {
-  this.props.scrollTop = scrollTop;
-  this._updateScrollTop();
-  return this.props.scrollTop;
-};
-
-/**
- * Update the current scrollTop when the height of  the containers has been changed
- * @returns {Number} scrollTop  Returns the applied scrollTop
- * @private
- */
-Timeline.prototype._updateScrollTop = function () {
-  // recalculate the scrollTopMin
-  var scrollTopMin = Math.min(this.props.centerContainer.height - this.props.center.height, 0); // is negative or zero
-  if (scrollTopMin != this.props.scrollTopMin) {
-    // in case of bottom orientation, change the scrollTop such that the contents
-    // do not move relative to the time axis at the bottom
-    if (this.options.orientation == 'bottom') {
-      this.props.scrollTop += (scrollTopMin - this.props.scrollTopMin);
-    }
-    this.props.scrollTopMin = scrollTopMin;
-  }
-
-  // limit the scrollTop to the feasible scroll range
-  if (this.props.scrollTop > 0) this.props.scrollTop = 0;
-  if (this.props.scrollTop < scrollTopMin) this.props.scrollTop = scrollTopMin;
-
-  return this.props.scrollTop;
-};
-
-/**
- * Get the current scrollTop
- * @returns {number} scrollTop
- * @private
- */
-Timeline.prototype._getScrollTop = function () {
-  return this.props.scrollTop;
-};
-
-(function(exports) {
-  /**
-   * Parse a text source containing data in DOT language into a JSON object.
-   * The object contains two lists: one with nodes and one with edges.
-   *
-   * DOT language reference: http://www.graphviz.org/doc/info/lang.html
-   *
-   * @param {String} data     Text containing a graph in DOT-notation
-   * @return {Object} graph   An object containing two parameters:
-   *                          {Object[]} nodes
-   *                          {Object[]} edges
-   */
-  function parseDOT (data) {
-    dot = data;
-    return parseGraph();
-  }
-
-  // token types enumeration
-  var TOKENTYPE = {
-    NULL : 0,
-    DELIMITER : 1,
-    IDENTIFIER: 2,
-    UNKNOWN : 3
-  };
-
-  // map with all delimiters
-  var DELIMITERS = {
-    '{': true,
-    '}': true,
-    '[': true,
-    ']': true,
-    ';': true,
-    '=': true,
-    ',': true,
-
-    '->': true,
-    '--': true
-  };
-
-  var dot = '';                   // current dot file
-  var index = 0;                  // current index in dot file
-  var c = '';                     // current token character in expr
-  var token = '';                 // current token
-  var tokenType = TOKENTYPE.NULL; // type of the token
-
-  /**
-   * Get the first character from the dot file.
-   * The character is stored into the char c. If the end of the dot file is
-   * reached, the function puts an empty string in c.
-   */
-  function first() {
-    index = 0;
-    c = dot.charAt(0);
-  }
-
-  /**
-   * Get the next character from the dot file.
-   * The character is stored into the char c. If the end of the dot file is
-   * reached, the function puts an empty string in c.
-   */
-  function next() {
-    index++;
-    c = dot.charAt(index);
-  }
-
-  /**
-   * Preview the next character from the dot file.
-   * @return {String} cNext
-   */
-  function nextPreview() {
-    return dot.charAt(index + 1);
-  }
-
-  /**
-   * Test whether given character is alphabetic or numeric
-   * @param {String} c
-   * @return {Boolean} isAlphaNumeric
-   */
-  var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/;
-  function isAlphaNumeric(c) {
-    return regexAlphaNumeric.test(c);
-  }
-
-  /**
-   * Merge all properties of object b into object b
-   * @param {Object} a
-   * @param {Object} b
-   * @return {Object} a
-   */
-  function merge (a, b) {
-    if (!a) {
-      a = {};
-    }
-
-    if (b) {
-      for (var name in b) {
-        if (b.hasOwnProperty(name)) {
-          a[name] = b[name];
-        }
-      }
-    }
-    return a;
-  }
-
-  /**
-   * Set a value in an object, where the provided parameter name can be a
-   * path with nested parameters. For example:
-   *
-   *     var obj = {a: 2};
-   *     setValue(obj, 'b.c', 3);     // obj = {a: 2, b: {c: 3}}
-   *
-   * @param {Object} obj
-   * @param {String} path  A parameter name or dot-separated parameter path,
-   *                      like "color.highlight.border".
-   * @param {*} value
-   */
-  function setValue(obj, path, value) {
-    var keys = path.split('.');
-    var o = obj;
-    while (keys.length) {
-      var key = keys.shift();
-      if (keys.length) {
-        // this isn't the end point
-        if (!o[key]) {
-          o[key] = {};
-        }
-        o = o[key];
-      }
-      else {
-        // this is the end point
-        o[key] = value;
-      }
-    }
-  }
-
-  /**
-   * Add a node to a graph object. If there is already a node with
-   * the same id, their attributes will be merged.
-   * @param {Object} graph
-   * @param {Object} node
-   */
-  function addNode(graph, node) {
-    var i, len;
-    var current = null;
-
-    // find root graph (in case of subgraph)
-    var graphs = [graph]; // list with all graphs from current graph to root graph
-    var root = graph;
-    while (root.parent) {
-      graphs.push(root.parent);
-      root = root.parent;
-    }
-
-    // find existing node (at root level) by its id
-    if (root.nodes) {
-      for (i = 0, len = root.nodes.length; i < len; i++) {
-        if (node.id === root.nodes[i].id) {
-          current = root.nodes[i];
-          break;
-        }
-      }
-    }
-
-    if (!current) {
-      // this is a new node
-      current = {
-        id: node.id
-      };
-      if (graph.node) {
-        // clone default attributes
-        current.attr = merge(current.attr, graph.node);
-      }
-    }
-
-    // add node to this (sub)graph and all its parent graphs
-    for (i = graphs.length - 1; i >= 0; i--) {
-      var g = graphs[i];
-
-      if (!g.nodes) {
-        g.nodes = [];
-      }
-      if (g.nodes.indexOf(current) == -1) {
-        g.nodes.push(current);
-      }
-    }
-
-    // merge attributes
-    if (node.attr) {
-      current.attr = merge(current.attr, node.attr);
-    }
-  }
-
-  /**
-   * Add an edge to a graph object
-   * @param {Object} graph
-   * @param {Object} edge
-   */
-  function addEdge(graph, edge) {
-    if (!graph.edges) {
-      graph.edges = [];
-    }
-    graph.edges.push(edge);
-    if (graph.edge) {
-      var attr = merge({}, graph.edge);     // clone default attributes
-      edge.attr = merge(attr, edge.attr); // merge attributes
-    }
-  }
-
-  /**
-   * Create an edge to a graph object
-   * @param {Object} graph
-   * @param {String | Number | Object} from
-   * @param {String | Number | Object} to
-   * @param {String} type
-   * @param {Object | null} attr
-   * @return {Object} edge
-   */
-  function createEdge(graph, from, to, type, attr) {
-    var edge = {
-      from: from,
-      to: to,
-      type: type
-    };
-
-    if (graph.edge) {
-      edge.attr = merge({}, graph.edge);  // clone default attributes
-    }
-    edge.attr = merge(edge.attr || {}, attr); // merge attributes
-
-    return edge;
-  }
-
-  /**
-   * Get next token in the current dot file.
-   * The token and token type are available as token and tokenType
-   */
-  function getToken() {
-    tokenType = TOKENTYPE.NULL;
-    token = '';
-
-    // skip over whitespaces
-    while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {  // space, tab, enter
-      next();
-    }
-
-    do {
-      var isComment = false;
-
-      // skip comment
-      if (c == '#') {
-        // find the previous non-space character
-        var i = index - 1;
-        while (dot.charAt(i) == ' ' || dot.charAt(i) == '\t') {
-          i--;
-        }
-        if (dot.charAt(i) == '\n' || dot.charAt(i) == '') {
-          // the # is at the start of a line, this is indeed a line comment
-          while (c != '' && c != '\n') {
-            next();
-          }
-          isComment = true;
-        }
-      }
-      if (c == '/' && nextPreview() == '/') {
-        // skip line comment
-        while (c != '' && c != '\n') {
-          next();
-        }
-        isComment = true;
-      }
-      if (c == '/' && nextPreview() == '*') {
-        // skip block comment
-        while (c != '') {
-          if (c == '*' && nextPreview() == '/') {
-            // end of block comment found. skip these last two characters
-            next();
-            next();
-            break;
-          }
-          else {
-            next();
-          }
-        }
-        isComment = true;
-      }
-
-      // skip over whitespaces
-      while (c == ' ' || c == '\t' || c == '\n' || c == '\r') {  // space, tab, enter
-        next();
-      }
-    }
-    while (isComment);
-
-    // check for end of dot file
-    if (c == '') {
-      // token is still empty
-      tokenType = TOKENTYPE.DELIMITER;
-      return;
-    }
-
-    // check for delimiters consisting of 2 characters
-    var c2 = c + nextPreview();
-    if (DELIMITERS[c2]) {
-      tokenType = TOKENTYPE.DELIMITER;
-      token = c2;
-      next();
-      next();
-      return;
-    }
-
-    // check for delimiters consisting of 1 character
-    if (DELIMITERS[c]) {
-      tokenType = TOKENTYPE.DELIMITER;
-      token = c;
-      next();
-      return;
-    }
-
-    // check for an identifier (number or string)
-    // TODO: more precise parsing of numbers/strings (and the port separator ':')
-    if (isAlphaNumeric(c) || c == '-') {
-      token += c;
-      next();
-
-      while (isAlphaNumeric(c)) {
-        token += c;
-        next();
-      }
-      if (token == 'false') {
-        token = false;   // convert to boolean
-      }
-      else if (token == 'true') {
-        token = true;   // convert to boolean
-      }
-      else if (!isNaN(Number(token))) {
-        token = Number(token); // convert to number
-      }
-      tokenType = TOKENTYPE.IDENTIFIER;
-      return;
-    }
-
-    // check for a string enclosed by double quotes
-    if (c == '"') {
-      next();
-      while (c != '' && (c != '"' || (c == '"' && nextPreview() == '"'))) {
-        token += c;
-        if (c == '"') { // skip the escape character
-          next();
-        }
-        next();
-      }
-      if (c != '"') {
-        throw newSyntaxError('End of string " expected');
-      }
-      next();
-      tokenType = TOKENTYPE.IDENTIFIER;
-      return;
-    }
-
-    // something unknown is found, wrong characters, a syntax error
-    tokenType = TOKENTYPE.UNKNOWN;
-    while (c != '') {
-      token += c;
-      next();
-    }
-    throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"');
-  }
-
-  /**
-   * Parse a graph.
-   * @returns {Object} graph
-   */
-  function parseGraph() {
-    var graph = {};
-
-    first();
-    getToken();
-
-    // optional strict keyword
-    if (token == 'strict') {
-      graph.strict = true;
-      getToken();
-    }
-
-    // graph or digraph keyword
-    if (token == 'graph' || token == 'digraph') {
-      graph.type = token;
-      getToken();
-    }
-
-    // optional graph id
-    if (tokenType == TOKENTYPE.IDENTIFIER) {
-      graph.id = token;
-      getToken();
-    }
-
-    // open angle bracket
-    if (token != '{') {
-      throw newSyntaxError('Angle bracket { expected');
-    }
-    getToken();
-
-    // statements
-    parseStatements(graph);
-
-    // close angle bracket
-    if (token != '}') {
-      throw newSyntaxError('Angle bracket } expected');
-    }
-    getToken();
-
-    // end of file
-    if (token !== '') {
-      throw newSyntaxError('End of file expected');
-    }
-    getToken();
-
-    // remove temporary default properties
-    delete graph.node;
-    delete graph.edge;
-    delete graph.graph;
-
-    return graph;
-  }
-
-  /**
-   * Parse a list with statements.
-   * @param {Object} graph
-   */
-  function parseStatements (graph) {
-    while (token !== '' && token != '}') {
-      parseStatement(graph);
-      if (token == ';') {
-        getToken();
-      }
-    }
-  }
-
-  /**
-   * Parse a single statement. Can be a an attribute statement, node
-   * statement, a series of node statements and edge statements, or a
-   * parameter.
-   * @param {Object} graph
-   */
-  function parseStatement(graph) {
-    // parse subgraph
-    var subgraph = parseSubgraph(graph);
-    if (subgraph) {
-      // edge statements
-      parseEdge(graph, subgraph);
-
-      return;
-    }
-
-    // parse an attribute statement
-    var attr = parseAttributeStatement(graph);
-    if (attr) {
-      return;
-    }
-
-    // parse node
-    if (tokenType != TOKENTYPE.IDENTIFIER) {
-      throw newSyntaxError('Identifier expected');
-    }
-    var id = token; // id can be a string or a number
-    getToken();
-
-    if (token == '=') {
-      // id statement
-      getToken();
-      if (tokenType != TOKENTYPE.IDENTIFIER) {
-        throw newSyntaxError('Identifier expected');
-      }
-      graph[id] = token;
-      getToken();
-      // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] "
-    }
-    else {
-      parseNodeStatement(graph, id);
-    }
-  }
-
-  /**
-   * Parse a subgraph
-   * @param {Object} graph    parent graph object
-   * @return {Object | null} subgraph
-   */
-  function parseSubgraph (graph) {
-    var subgraph = null;
-
-    // optional subgraph keyword
-    if (token == 'subgraph') {
-      subgraph = {};
-      subgraph.type = 'subgraph';
-      getToken();
-
-      // optional graph id
-      if (tokenType == TOKENTYPE.IDENTIFIER) {
-        subgraph.id = token;
-        getToken();
-      }
-    }
-
-    // open angle bracket
-    if (token == '{') {
-      getToken();
-
-      if (!subgraph) {
-        subgraph = {};
-      }
-      subgraph.parent = graph;
-      subgraph.node = graph.node;
-      subgraph.edge = graph.edge;
-      subgraph.graph = graph.graph;
-
-      // statements
-      parseStatements(subgraph);
-
-      // close angle bracket
-      if (token != '}') {
-        throw newSyntaxError('Angle bracket } expected');
-      }
-      getToken();
-
-      // remove temporary default properties
-      delete subgraph.node;
-      delete subgraph.edge;
-      delete subgraph.graph;
-      delete subgraph.parent;
-
-      // register at the parent graph
-      if (!graph.subgraphs) {
-        graph.subgraphs = [];
-      }
-      graph.subgraphs.push(subgraph);
-    }
-
-    return subgraph;
-  }
-
-  /**
-   * parse an attribute statement like "node [shape=circle fontSize=16]".
-   * Available keywords are 'node', 'edge', 'graph'.
-   * The previous list with default attributes will be replaced
-   * @param {Object} graph
-   * @returns {String | null} keyword Returns the name of the parsed attribute
-   *                                  (node, edge, graph), or null if nothing
-   *                                  is parsed.
-   */
-  function parseAttributeStatement (graph) {
-    // attribute statements
-    if (token == 'node') {
-      getToken();
-
-      // node attributes
-      graph.node = parseAttributeList();
-      return 'node';
-    }
-    else if (token == 'edge') {
-      getToken();
-
-      // edge attributes
-      graph.edge = parseAttributeList();
-      return 'edge';
-    }
-    else if (token == 'graph') {
-      getToken();
-
-      // graph attributes
-      graph.graph = parseAttributeList();
-      return 'graph';
-    }
-
-    return null;
-  }
-
-  /**
-   * parse a node statement
-   * @param {Object} graph
-   * @param {String | Number} id
-   */
-  function parseNodeStatement(graph, id) {
-    // node statement
-    var node = {
-      id: id
-    };
-    var attr = parseAttributeList();
-    if (attr) {
-      node.attr = attr;
-    }
-    addNode(graph, node);
-
-    // edge statements
-    parseEdge(graph, id);
-  }
-
-  /**
-   * Parse an edge or a series of edges
-   * @param {Object} graph
-   * @param {String | Number} from        Id of the from node
-   */
-  function parseEdge(graph, from) {
-    while (token == '->' || token == '--') {
-      var to;
-      var type = token;
-      getToken();
-
-      var subgraph = parseSubgraph(graph);
-      if (subgraph) {
-        to = subgraph;
-      }
-      else {
-        if (tokenType != TOKENTYPE.IDENTIFIER) {
-          throw newSyntaxError('Identifier or subgraph expected');
-        }
-        to = token;
-        addNode(graph, {
-          id: to
-        });
-        getToken();
-      }
-
-      // parse edge attributes
-      var attr = parseAttributeList();
-
-      // create edge
-      var edge = createEdge(graph, from, to, type, attr);
-      addEdge(graph, edge);
-
-      from = to;
-    }
-  }
-
-  /**
-   * Parse a set with attributes,
-   * for example [label="1.000", shape=solid]
-   * @return {Object | null} attr
-   */
-  function parseAttributeList() {
-    var attr = null;
-
-    while (token == '[') {
-      getToken();
-      attr = {};
-      while (token !== '' && token != ']') {
-        if (tokenType != TOKENTYPE.IDENTIFIER) {
-          throw newSyntaxError('Attribute name expected');
-        }
-        var name = token;
-
-        getToken();
-        if (token != '=') {
-          throw newSyntaxError('Equal sign = expected');
-        }
-        getToken();
-
-        if (tokenType != TOKENTYPE.IDENTIFIER) {
-          throw newSyntaxError('Attribute value expected');
-        }
-        var value = token;
-        setValue(attr, name, value); // name can be a path
-
-        getToken();
-        if (token ==',') {
-          getToken();
-        }
-      }
-
-      if (token != ']') {
-        throw newSyntaxError('Bracket ] expected');
-      }
-      getToken();
-    }
-
-    return attr;
-  }
-
-  /**
-   * Create a syntax error with extra information on current token and index.
-   * @param {String} message
-   * @returns {SyntaxError} err
-   */
-  function newSyntaxError(message) {
-    return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')');
-  }
-
-  /**
-   * Chop off text after a maximum length
-   * @param {String} text
-   * @param {Number} maxLength
-   * @returns {String}
-   */
-  function chop (text, maxLength) {
-    return (text.length <= maxLength) ? text : (text.substr(0, 27) + '...');
-  }
-
-  /**
-   * Execute a function fn for each pair of elements in two arrays
-   * @param {Array | *} array1
-   * @param {Array | *} array2
-   * @param {function} fn
-   */
-  function forEach2(array1, array2, fn) {
-    if (array1 instanceof Array) {
-      array1.forEach(function (elem1) {
-        if (array2 instanceof Array) {
-          array2.forEach(function (elem2)  {
-            fn(elem1, elem2);
-          });
-        }
-        else {
-          fn(elem1, array2);
-        }
-      });
-    }
-    else {
-      if (array2 instanceof Array) {
-        array2.forEach(function (elem2)  {
-          fn(array1, elem2);
-        });
-      }
-      else {
-        fn(array1, array2);
-      }
-    }
-  }
-
-  /**
-   * Convert a string containing a graph in DOT language into a map containing
-   * with nodes and edges in the format of graph.
-   * @param {String} data         Text containing a graph in DOT-notation
-   * @return {Object} graphData
-   */
-  function DOTToGraph (data) {
-    // parse the DOT file
-    var dotData = parseDOT(data);
-    var graphData = {
-      nodes: [],
-      edges: [],
-      options: {}
-    };
-
-    // copy the nodes
-    if (dotData.nodes) {
-      dotData.nodes.forEach(function (dotNode) {
-        var graphNode = {
-          id: dotNode.id,
-          label: String(dotNode.label || dotNode.id)
-        };
-        merge(graphNode, dotNode.attr);
-        if (graphNode.image) {
-          graphNode.shape = 'image';
-        }
-        graphData.nodes.push(graphNode);
-      });
-    }
-
-    // copy the edges
-    if (dotData.edges) {
-      /**
-       * Convert an edge in DOT format to an edge with VisGraph format
-       * @param {Object} dotEdge
-       * @returns {Object} graphEdge
-       */
-      function convertEdge(dotEdge) {
-        var graphEdge = {
-          from: dotEdge.from,
-          to: dotEdge.to
-        };
-        merge(graphEdge, dotEdge.attr);
-        graphEdge.style = (dotEdge.type == '->') ? 'arrow' : 'line';
-        return graphEdge;
-      }
-
-      dotData.edges.forEach(function (dotEdge) {
-        var from, to;
-        if (dotEdge.from instanceof Object) {
-          from = dotEdge.from.nodes;
-        }
-        else {
-          from = {
-            id: dotEdge.from
-          }
-        }
-
-        if (dotEdge.to instanceof Object) {
-          to = dotEdge.to.nodes;
-        }
-        else {
-          to = {
-            id: dotEdge.to
-          }
-        }
-
-        if (dotEdge.from instanceof Object && dotEdge.from.edges) {
-          dotEdge.from.edges.forEach(function (subEdge) {
-            var graphEdge = convertEdge(subEdge);
-            graphData.edges.push(graphEdge);
-          });
-        }
-
-        forEach2(from, to, function (from, to) {
-          var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr);
-          var graphEdge = convertEdge(subEdge);
-          graphData.edges.push(graphEdge);
-        });
-
-        if (dotEdge.to instanceof Object && dotEdge.to.edges) {
-          dotEdge.to.edges.forEach(function (subEdge) {
-            var graphEdge = convertEdge(subEdge);
-            graphData.edges.push(graphEdge);
-          });
-        }
-      });
-    }
-
-    // copy the options
-    if (dotData.attr) {
-      graphData.options = dotData.attr;
-    }
-
-    return graphData;
-  }
-
-  // exports
-  exports.parseDOT = parseDOT;
-  exports.DOTToGraph = DOTToGraph;
-
-})(typeof util !== 'undefined' ? util : exports);
-
-/**
- * Canvas shapes used by the Graph
- */
-if (typeof CanvasRenderingContext2D !== 'undefined') {
-
-  /**
-   * Draw a circle shape
-   */
-  CanvasRenderingContext2D.prototype.circle = function(x, y, r) {
-    this.beginPath();
-    this.arc(x, y, r, 0, 2*Math.PI, false);
-  };
-
-  /**
-   * Draw a square shape
-   * @param {Number} x horizontal center
-   * @param {Number} y vertical center
-   * @param {Number} r   size, width and height of the square
-   */
-  CanvasRenderingContext2D.prototype.square = function(x, y, r) {
-    this.beginPath();
-    this.rect(x - r, y - r, r * 2, r * 2);
-  };
-
-  /**
-   * Draw a triangle shape
-   * @param {Number} x horizontal center
-   * @param {Number} y vertical center
-   * @param {Number} r   radius, half the length of the sides of the triangle
-   */
-  CanvasRenderingContext2D.prototype.triangle = function(x, y, r) {
-    // http://en.wikipedia.org/wiki/Equilateral_triangle
-    this.beginPath();
-
-    var s = r * 2;
-    var s2 = s / 2;
-    var ir = Math.sqrt(3) / 6 * s;      // radius of inner circle
-    var h = Math.sqrt(s * s - s2 * s2); // height
-
-    this.moveTo(x, y - (h - ir));
-    this.lineTo(x + s2, y + ir);
-    this.lineTo(x - s2, y + ir);
-    this.lineTo(x, y - (h - ir));
-    this.closePath();
-  };
-
-  /**
-   * Draw a triangle shape in downward orientation
-   * @param {Number} x horizontal center
-   * @param {Number} y vertical center
-   * @param {Number} r radius
-   */
-  CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) {
-    // http://en.wikipedia.org/wiki/Equilateral_triangle
-    this.beginPath();
-
-    var s = r * 2;
-    var s2 = s / 2;
-    var ir = Math.sqrt(3) / 6 * s;      // radius of inner circle
-    var h = Math.sqrt(s * s - s2 * s2); // height
-
-    this.moveTo(x, y + (h - ir));
-    this.lineTo(x + s2, y - ir);
-    this.lineTo(x - s2, y - ir);
-    this.lineTo(x, y + (h - ir));
-    this.closePath();
-  };
-
-  /**
-   * Draw a star shape, a star with 5 points
-   * @param {Number} x horizontal center
-   * @param {Number} y vertical center
-   * @param {Number} r   radius, half the length of the sides of the triangle
-   */
-  CanvasRenderingContext2D.prototype.star = function(x, y, r) {
-    // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
-    this.beginPath();
-
-    for (var n = 0; n < 10; n++) {
-      var radius = (n % 2 === 0) ? r * 1.3 : r * 0.5;
-      this.lineTo(
-          x + radius * Math.sin(n * 2 * Math.PI / 10),
-          y - radius * Math.cos(n * 2 * Math.PI / 10)
-      );
-    }
-
-    this.closePath();
-  };
-
-  /**
-   * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas
-   */
-  CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
-    var r2d = Math.PI/180;
-    if( w - ( 2 * r ) < 0 ) { r = ( w / 2 ); } //ensure that the radius isn't too large for x
-    if( h - ( 2 * r ) < 0 ) { r = ( h / 2 ); } //ensure that the radius isn't too large for y
-    this.beginPath();
-    this.moveTo(x+r,y);
-    this.lineTo(x+w-r,y);
-    this.arc(x+w-r,y+r,r,r2d*270,r2d*360,false);
-    this.lineTo(x+w,y+h-r);
-    this.arc(x+w-r,y+h-r,r,0,r2d*90,false);
-    this.lineTo(x+r,y+h);
-    this.arc(x+r,y+h-r,r,r2d*90,r2d*180,false);
-    this.lineTo(x,y+r);
-    this.arc(x+r,y+r,r,r2d*180,r2d*270,false);
-  };
-
-  /**
-   * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
-   */
-  CanvasRenderingContext2D.prototype.ellipse = function(x, y, w, h) {
-    var kappa = .5522848,
-        ox = (w / 2) * kappa, // control point offset horizontal
-        oy = (h / 2) * kappa, // control point offset vertical
-        xe = x + w,           // x-end
-        ye = y + h,           // y-end
-        xm = x + w / 2,       // x-middle
-        ym = y + h / 2;       // y-middle
-
-    this.beginPath();
-    this.moveTo(x, ym);
-    this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
-    this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
-    this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
-    this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
-  };
-
-
-
-  /**
-   * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
-   */
-  CanvasRenderingContext2D.prototype.database = function(x, y, w, h) {
-    var f = 1/3;
-    var wEllipse = w;
-    var hEllipse = h * f;
-
-    var kappa = .5522848,
-        ox = (wEllipse / 2) * kappa, // control point offset horizontal
-        oy = (hEllipse / 2) * kappa, // control point offset vertical
-        xe = x + wEllipse,           // x-end
-        ye = y + hEllipse,           // y-end
-        xm = x + wEllipse / 2,       // x-middle
-        ym = y + hEllipse / 2,       // y-middle
-        ymb = y + (h - hEllipse/2),  // y-midlle, bottom ellipse
-        yeb = y + h;                 // y-end, bottom ellipse
-
-    this.beginPath();
-    this.moveTo(xe, ym);
-
-    this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
-    this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
-
-    this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
-    this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
-
-    this.lineTo(xe, ymb);
-
-    this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb);
-    this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb);
-
-    this.lineTo(x, ym);
-  };
-
-
-  /**
-   * Draw an arrow point (no line)
-   */
-  CanvasRenderingContext2D.prototype.arrow = function(x, y, angle, length) {
-    // tail
-    var xt = x - length * Math.cos(angle);
-    var yt = y - length * Math.sin(angle);
-
-    // inner tail
-    // TODO: allow to customize different shapes
-    var xi = x - length * 0.9 * Math.cos(angle);
-    var yi = y - length * 0.9 * Math.sin(angle);
-
-    // left
-    var xl = xt + length / 3 * Math.cos(angle + 0.5 * Math.PI);
-    var yl = yt + length / 3 * Math.sin(angle + 0.5 * Math.PI);
-
-    // right
-    var xr = xt + length / 3 * Math.cos(angle - 0.5 * Math.PI);
-    var yr = yt + length / 3 * Math.sin(angle - 0.5 * Math.PI);
-
-    this.beginPath();
-    this.moveTo(x, y);
-    this.lineTo(xl, yl);
-    this.lineTo(xi, yi);
-    this.lineTo(xr, yr);
-    this.closePath();
-  };
-
-  /**
-   * Sets up the dashedLine functionality for drawing
-   * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas
-   * @author David Jordan
-   * @date 2012-08-08
-   */
-  CanvasRenderingContext2D.prototype.dashedLine = function(x,y,x2,y2,dashArray){
-    if (!dashArray) dashArray=[10,5];
-    if (dashLength==0) dashLength = 0.001; // Hack for Safari
-    var dashCount = dashArray.length;
-    this.moveTo(x, y);
-    var dx = (x2-x), dy = (y2-y);
-    var slope = dy/dx;
-    var distRemaining = Math.sqrt( dx*dx + dy*dy );
-    var dashIndex=0, draw=true;
-    while (distRemaining>=0.1){
-      var dashLength = dashArray[dashIndex++%dashCount];
-      if (dashLength > distRemaining) dashLength = distRemaining;
-      var xStep = Math.sqrt( dashLength*dashLength / (1 + slope*slope) );
-      if (dx<0) xStep = -xStep;
-      x += xStep;
-      y += slope*xStep;
-      this[draw ? 'lineTo' : 'moveTo'](x,y);
-      distRemaining -= dashLength;
-      draw = !draw;
-    }
-  };
-
-  // TODO: add diamond shape
-}
-
-/**
- * @class Node
- * A node. A node can be connected to other nodes via one or multiple edges.
- * @param {object} properties An object containing properties for the node. All
- *                            properties are optional, except for the id.
- *                              {number} id     Id of the node. Required
- *                              {string} label  Text label for the node
- *                              {number} x      Horizontal position of the node
- *                              {number} y      Vertical position of the node
- *                              {string} shape  Node shape, available:
- *                                              "database", "circle", "ellipse",
- *                                              "box", "image", "text", "dot",
- *                                              "star", "triangle", "triangleDown",
- *                                              "square"
- *                              {string} image  An image url
- *                              {string} title  An title text, can be HTML
- *                              {anytype} group A group name or number
- * @param {Graph.Images} imagelist    A list with images. Only needed
- *                                            when the node has an image
- * @param {Graph.Groups} grouplist    A list with groups. Needed for
- *                                            retrieving group properties
- * @param {Object}               constants    An object with default values for
- *                                            example for the color
- *
- */
-function Node(properties, imagelist, grouplist, constants) {
-  this.selected = false;
-  this.hover = false;
-
-  this.edges = []; // all edges connected to this node
-  this.dynamicEdges = [];
-  this.reroutedEdges = {};
-
-  this.group = constants.nodes.group;
-  this.fontSize = Number(constants.nodes.fontSize);
-  this.fontFace = constants.nodes.fontFace;
-  this.fontColor = constants.nodes.fontColor;
-  this.fontDrawThreshold = 3;
-
-  this.color = constants.nodes.color;
-
-  // set defaults for the properties
-  this.id = undefined;
-  this.shape = constants.nodes.shape;
-  this.image = constants.nodes.image;
-  this.x = null;
-  this.y = null;
-  this.xFixed = false;
-  this.yFixed = false;
-  this.horizontalAlignLeft = true; // these are for the navigation controls
-  this.verticalAlignTop    = true; // these are for the navigation controls
-  this.radius = constants.nodes.radius;
-  this.baseRadiusValue = constants.nodes.radius;
-  this.radiusFixed = false;
-  this.radiusMin = constants.nodes.radiusMin;
-  this.radiusMax = constants.nodes.radiusMax;
-  this.level = -1;
-  this.preassignedLevel = false;
-
-
-  this.imagelist = imagelist;
-  this.grouplist = grouplist;
-
-  // physics properties
-  this.fx = 0.0;  // external force x
-  this.fy = 0.0;  // external force y
-  this.vx = 0.0;  // velocity x
-  this.vy = 0.0;  // velocity y
-  this.minForce = constants.minForce;
-  this.damping = constants.physics.damping;
-  this.mass = 1;  // kg
-  this.fixedData = {x:null,y:null};
-
-  this.setProperties(properties, constants);
-
-  // creating the variables for clustering
-  this.resetCluster();
-  this.dynamicEdgesLength = 0;
-  this.clusterSession = 0;
-  this.clusterSizeWidthFactor  = constants.clustering.nodeScaling.width;
-  this.clusterSizeHeightFactor = constants.clustering.nodeScaling.height;
-  this.clusterSizeRadiusFactor = constants.clustering.nodeScaling.radius;
-  this.maxNodeSizeIncrements = constants.clustering.maxNodeSizeIncrements;
-  this.growthIndicator = 0;
-
-  // variables to tell the node about the graph.
-  this.graphScaleInv = 1;
-  this.graphScale = 1;
-  this.canvasTopLeft = {"x": -300, "y": -300};
-  this.canvasBottomRight = {"x":  300, "y":  300};
-  this.parentEdgeId = null;
-}
-
-/**
- * (re)setting the clustering variables and objects
- */
-Node.prototype.resetCluster = function() {
-  // clustering variables
-  this.formationScale = undefined; // this is used to determine when to open the cluster
-  this.clusterSize = 1;            // this signifies the total amount of nodes in this cluster
-  this.containedNodes = {};
-  this.containedEdges = {};
-  this.clusterSessions = [];
-};
-
-/**
- * Attach a edge to the node
- * @param {Edge} edge
- */
-Node.prototype.attachEdge = function(edge) {
-  if (this.edges.indexOf(edge) == -1) {
-    this.edges.push(edge);
-  }
-  if (this.dynamicEdges.indexOf(edge) == -1) {
-    this.dynamicEdges.push(edge);
-  }
-  this.dynamicEdgesLength = this.dynamicEdges.length;
-};
-
-/**
- * Detach a edge from the node
- * @param {Edge} edge
- */
-Node.prototype.detachEdge = function(edge) {
-  var index = this.edges.indexOf(edge);
-  if (index != -1) {
-    this.edges.splice(index, 1);
-    this.dynamicEdges.splice(index, 1);
-  }
-  this.dynamicEdgesLength = this.dynamicEdges.length;
-};
-
-
-/**
- * Set or overwrite properties for the node
- * @param {Object} properties an object with properties
- * @param {Object} constants  and object with default, global properties
- */
-Node.prototype.setProperties = function(properties, constants) {
-  if (!properties) {
-    return;
-  }
-  this.originalLabel = undefined;
-  // basic properties
-  if (properties.id !== undefined)        {this.id = properties.id;}
-  if (properties.label !== undefined)     {this.label = properties.label; this.originalLabel = properties.label;}
-  if (properties.title !== undefined)     {this.title = properties.title;}
-  if (properties.group !== undefined)     {this.group = properties.group;}
-  if (properties.x !== undefined)         {this.x = properties.x;}
-  if (properties.y !== undefined)         {this.y = properties.y;}
-  if (properties.value !== undefined)     {this.value = properties.value;}
-  if (properties.level !== undefined)     {this.level = properties.level; this.preassignedLevel = true;}
-
-
-  // physics
-  if (properties.mass !== undefined)                {this.mass = properties.mass;}
-
-  // navigation controls properties
-  if (properties.horizontalAlignLeft !== undefined) {this.horizontalAlignLeft = properties.horizontalAlignLeft;}
-  if (properties.verticalAlignTop    !== undefined) {this.verticalAlignTop    = properties.verticalAlignTop;}
-  if (properties.triggerFunction     !== undefined) {this.triggerFunction     = properties.triggerFunction;}
-
-  if (this.id === undefined) {
-    throw "Node must have an id";
-  }
-
-  // copy group properties
-  if (this.group) {
-    var groupObj = this.grouplist.get(this.group);
-    for (var prop in groupObj) {
-      if (groupObj.hasOwnProperty(prop)) {
-        this[prop] = groupObj[prop];
-      }
-    }
-  }
-
-  // individual shape properties
-  if (properties.shape !== undefined)          {this.shape = properties.shape;}
-  if (properties.image !== undefined)          {this.image = properties.image;}
-  if (properties.radius !== undefined)         {this.radius = properties.radius;}
-  if (properties.color !== undefined)          {this.color = util.parseColor(properties.color);}
-
-  if (properties.fontColor !== undefined)      {this.fontColor = properties.fontColor;}
-  if (properties.fontSize !== undefined)       {this.fontSize = properties.fontSize;}
-  if (properties.fontFace !== undefined)       {this.fontFace = properties.fontFace;}
-
-  if (this.image !== undefined && this.image != "") {
-    if (this.imagelist) {
-      this.imageObj = this.imagelist.load(this.image);
-    }
-    else {
-      throw "No imagelist provided";
-    }
-  }
-
-  this.xFixed = this.xFixed || (properties.x !== undefined && !properties.allowedToMoveX);
-  this.yFixed = this.yFixed || (properties.y !== undefined && !properties.allowedToMoveY);
-  this.radiusFixed = this.radiusFixed || (properties.radius !== undefined);
-
-  if (this.shape == 'image') {
-    this.radiusMin = constants.nodes.widthMin;
-    this.radiusMax = constants.nodes.widthMax;
-  }
-
-  // choose draw method depending on the shape
-  switch (this.shape) {
-    case 'database':      this.draw = this._drawDatabase; this.resize = this._resizeDatabase; break;
-    case 'box':           this.draw = this._drawBox; this.resize = this._resizeBox; break;
-    case 'circle':        this.draw = this._drawCircle; this.resize = this._resizeCircle; break;
-    case 'ellipse':       this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break;
-    // TODO: add diamond shape
-    case 'image':         this.draw = this._drawImage; this.resize = this._resizeImage; break;
-    case 'text':          this.draw = this._drawText; this.resize = this._resizeText; break;
-    case 'dot':           this.draw = this._drawDot; this.resize = this._resizeShape; break;
-    case 'square':        this.draw = this._drawSquare; this.resize = this._resizeShape; break;
-    case 'triangle':      this.draw = this._drawTriangle; this.resize = this._resizeShape; break;
-    case 'triangleDown':  this.draw = this._drawTriangleDown; this.resize = this._resizeShape; break;
-    case 'star':          this.draw = this._drawStar; this.resize = this._resizeShape; break;
-    default:              this.draw = this._drawEllipse; this.resize = this._resizeEllipse; break;
-  }
-  // reset the size of the node, this can be changed
-  this._reset();
-};
-
-/**
- * select this node
- */
-Node.prototype.select = function() {
-  this.selected = true;
-  this._reset();
-};
-
-/**
- * unselect this node
- */
-Node.prototype.unselect = function() {
-  this.selected = false;
-  this._reset();
-};
-
-
-/**
- * Reset the calculated size of the node, forces it to recalculate its size
- */
-Node.prototype.clearSizeCache = function() {
-  this._reset();
-};
-
-/**
- * Reset the calculated size of the node, forces it to recalculate its size
- * @private
- */
-Node.prototype._reset = function() {
-  this.width = undefined;
-  this.height = undefined;
-};
-
-/**
- * get the title of this node.
- * @return {string} title    The title of the node, or undefined when no title
- *                           has been set.
- */
-Node.prototype.getTitle = function() {
-  return typeof this.title === "function" ? this.title() : this.title;
-};
-
-/**
- * Calculate the distance to the border of the Node
- * @param {CanvasRenderingContext2D}   ctx
- * @param {Number} angle        Angle in radians
- * @returns {number} distance   Distance to the border in pixels
- */
-Node.prototype.distanceToBorder = function (ctx, angle) {
-  var borderWidth = 1;
-
-  if (!this.width) {
-    this.resize(ctx);
-  }
-
-  switch (this.shape) {
-    case 'circle':
-    case 'dot':
-      return this.radius + borderWidth;
-
-    case 'ellipse':
-      var a = this.width / 2;
-      var b = this.height / 2;
-      var w = (Math.sin(angle) * a);
-      var h = (Math.cos(angle) * b);
-      return a * b / Math.sqrt(w * w + h * h);
-
-    // TODO: implement distanceToBorder for database
-    // TODO: implement distanceToBorder for triangle
-    // TODO: implement distanceToBorder for triangleDown
-
-    case 'box':
-    case 'image':
-    case 'text':
-    default:
-      if (this.width) {
-        return Math.min(
-            Math.abs(this.width / 2 / Math.cos(angle)),
-            Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
-        // TODO: reckon with border radius too in case of box
-      }
-      else {
-        return 0;
-      }
-
-  }
-  // TODO: implement calculation of distance to border for all shapes
-};
-
-/**
- * Set forces acting on the node
- * @param {number} fx   Force in horizontal direction
- * @param {number} fy   Force in vertical direction
- */
-Node.prototype._setForce = function(fx, fy) {
-  this.fx = fx;
-  this.fy = fy;
-};
-
-/**
- * Add forces acting on the node
- * @param {number} fx   Force in horizontal direction
- * @param {number} fy   Force in vertical direction
- * @private
- */
-Node.prototype._addForce = function(fx, fy) {
-  this.fx += fx;
-  this.fy += fy;
-};
-
-/**
- * Perform one discrete step for the node
- * @param {number} interval    Time interval in seconds
- */
-Node.prototype.discreteStep = function(interval) {
-  if (!this.xFixed) {
-    var dx   = this.damping * this.vx;     // damping force
-    var ax   = (this.fx - dx) / this.mass;  // acceleration
-    this.vx += ax * interval;               // velocity
-    this.x  += this.vx * interval;          // position
-  }
-
-  if (!this.yFixed) {
-    var dy   = this.damping * this.vy;     // damping force
-    var ay   = (this.fy - dy) / this.mass;  // acceleration
-    this.vy += ay * interval;               // velocity
-    this.y  += this.vy * interval;          // position
-  }
-};
-
-
-
-/**
- * Perform one discrete step for the node
- * @param {number} interval    Time interval in seconds
- * @param {number} maxVelocity The speed limit imposed on the velocity
- */
-Node.prototype.discreteStepLimited = function(interval, maxVelocity) {
-  if (!this.xFixed) {
-    var dx   = this.damping * this.vx;     // damping force
-    var ax   = (this.fx - dx) / this.mass;  // acceleration
-    this.vx += ax * interval;               // velocity
-    this.vx = (Math.abs(this.vx) > maxVelocity) ? ((this.vx > 0) ? maxVelocity : -maxVelocity) : this.vx;
-    this.x  += this.vx * interval;          // position
-  }
-  else {
-    this.fx = 0;
-  }
-
-  if (!this.yFixed) {
-    var dy   = this.damping * this.vy;     // damping force
-    var ay   = (this.fy - dy) / this.mass;  // acceleration
-    this.vy += ay * interval;               // velocity
-    this.vy = (Math.abs(this.vy) > maxVelocity) ? ((this.vy > 0) ? maxVelocity : -maxVelocity) : this.vy;
-    this.y  += this.vy * interval;          // position
-  }
-  else {
-    this.fy = 0;
-  }
-};
-
-/**
- * Check if this node has a fixed x and y position
- * @return {boolean}      true if fixed, false if not
- */
-Node.prototype.isFixed = function() {
-  return (this.xFixed && this.yFixed);
-};
-
-/**
- * Check if this node is moving
- * @param {number} vmin   the minimum velocity considered as "moving"
- * @return {boolean}      true if moving, false if it has no velocity
- */
-// TODO: replace this method with calculating the kinetic energy
-Node.prototype.isMoving = function(vmin) {
-  return (Math.abs(this.vx) > vmin || Math.abs(this.vy) > vmin);
-};
-
-/**
- * check if this node is selecte
- * @return {boolean} selected   True if node is selected, else false
- */
-Node.prototype.isSelected = function() {
-  return this.selected;
-};
-
-/**
- * Retrieve the value of the node. Can be undefined
- * @return {Number} value
- */
-Node.prototype.getValue = function() {
-  return this.value;
-};
-
-/**
- * Calculate the distance from the nodes location to the given location (x,y)
- * @param {Number} x
- * @param {Number} y
- * @return {Number} value
- */
-Node.prototype.getDistance = function(x, y) {
-  var dx = this.x - x,
-      dy = this.y - y;
-  return Math.sqrt(dx * dx + dy * dy);
-};
-
-
-/**
- * Adjust the value range of the node. The node will adjust it's radius
- * based on its value.
- * @param {Number} min
- * @param {Number} max
- */
-Node.prototype.setValueRange = function(min, max) {
-  if (!this.radiusFixed && this.value !== undefined) {
-    if (max == min) {
-      this.radius = (this.radiusMin + this.radiusMax) / 2;
-    }
-    else {
-      var scale = (this.radiusMax - this.radiusMin) / (max - min);
-      this.radius = (this.value - min) * scale + this.radiusMin;
-    }
-  }
-  this.baseRadiusValue = this.radius;
-};
-
-/**
- * Draw this node in the given canvas
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
- * @param {CanvasRenderingContext2D}   ctx
- */
-Node.prototype.draw = function(ctx) {
-  throw "Draw method not initialized for node";
-};
-
-/**
- * Recalculate the size of this node in the given canvas
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
- * @param {CanvasRenderingContext2D}   ctx
- */
-Node.prototype.resize = function(ctx) {
-  throw "Resize method not initialized for node";
-};
-
-/**
- * Check if this object is overlapping with the provided object
- * @param {Object} obj   an object with parameters left, top, right, bottom
- * @return {boolean}     True if location is located on node
- */
-Node.prototype.isOverlappingWith = function(obj) {
-  return (this.left              < obj.right  &&
-          this.left + this.width > obj.left   &&
-          this.top               < obj.bottom &&
-          this.top + this.height > obj.top);
-};
-
-Node.prototype._resizeImage = function (ctx) {
-  // TODO: pre calculate the image size
-
-  if (!this.width || !this.height) {  // undefined or 0
-    var width, height;
-    if (this.value) {
-      this.radius = this.baseRadiusValue;
-      var scale = this.imageObj.height / this.imageObj.width;
-      if (scale !== undefined) {
-        width = this.radius || this.imageObj.width;
-        height = this.radius * scale || this.imageObj.height;
-      }
-      else {
-        width = 0;
-        height = 0;
-      }
-    }
-    else {
-      width = this.imageObj.width;
-      height = this.imageObj.height;
-    }
-    this.width  = width;
-    this.height = height;
-
-    this.growthIndicator = 0;
-    if (this.width > 0 && this.height > 0) {
-      this.width  += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements)  * this.clusterSizeWidthFactor;
-      this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
-      this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
-      this.growthIndicator = this.width - width;
-    }
-  }
-
-};
-
-Node.prototype._drawImage = function (ctx) {
-  this._resizeImage(ctx);
-
-  this.left   = this.x - this.width / 2;
-  this.top    = this.y - this.height / 2;
-
-  var yLabel;
-  if (this.imageObj.width != 0 ) {
-    // draw the shade
-    if (this.clusterSize > 1) {
-      var lineWidth = ((this.clusterSize > 1) ? 10 : 0.0);
-      lineWidth *= this.graphScaleInv;
-      lineWidth = Math.min(0.2 * this.width,lineWidth);
-
-      ctx.globalAlpha = 0.5;
-      ctx.drawImage(this.imageObj, this.left - lineWidth, this.top - lineWidth, this.width + 2*lineWidth, this.height + 2*lineWidth);
-    }
-
-    // draw the image
-    ctx.globalAlpha = 1.0;
-    ctx.drawImage(this.imageObj, this.left, this.top, this.width, this.height);
-    yLabel = this.y + this.height / 2;
-  }
-  else {
-    // image still loading... just draw the label for now
-    yLabel = this.y;
-  }
-
-  this._label(ctx, this.label, this.x, yLabel, undefined, "top");
-};
-
-
-Node.prototype._resizeBox = function (ctx) {
-  if (!this.width) {
-    var margin = 5;
-    var textSize = this.getTextSize(ctx);
-    this.width = textSize.width + 2 * margin;
-    this.height = textSize.height + 2 * margin;
-
-    this.width  += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
-    this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
-    this.growthIndicator = this.width - (textSize.width + 2 * margin);
-//    this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
-
-  }
-};
-
-Node.prototype._drawBox = function (ctx) {
-  this._resizeBox(ctx);
-
-  this.left = this.x - this.width / 2;
-  this.top = this.y - this.height / 2;
-
-  var clusterLineWidth = 2.5;
-  var selectionLineWidth = 2;
-
-  ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
-
-  // draw the outer border
-  if (this.clusterSize > 1) {
-    ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-    ctx.lineWidth *= this.graphScaleInv;
-    ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-    ctx.roundRect(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth, this.radius);
-    ctx.stroke();
-  }
-  ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-  ctx.lineWidth *= this.graphScaleInv;
-  ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-  ctx.fillStyle = this.selected ? this.color.highlight.background : this.color.background;
-
-  ctx.roundRect(this.left, this.top, this.width, this.height, this.radius);
-  ctx.fill();
-  ctx.stroke();
-
-  this._label(ctx, this.label, this.x, this.y);
-};
-
-
-Node.prototype._resizeDatabase = function (ctx) {
-  if (!this.width) {
-    var margin = 5;
-    var textSize = this.getTextSize(ctx);
-    var size = textSize.width + 2 * margin;
-    this.width = size;
-    this.height = size;
-
-    // scaling used for clustering
-    this.width  += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
-    this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
-    this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
-    this.growthIndicator = this.width - size;
-  }
-};
-
-Node.prototype._drawDatabase = function (ctx) {
-  this._resizeDatabase(ctx);
-  this.left = this.x - this.width / 2;
-  this.top = this.y - this.height / 2;
-
-  var clusterLineWidth = 2.5;
-  var selectionLineWidth = 2;
-
-  ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
-
-  // draw the outer border
-  if (this.clusterSize > 1) {
-    ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-    ctx.lineWidth *= this.graphScaleInv;
-    ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-    ctx.database(this.x - this.width/2 - 2*ctx.lineWidth, this.y - this.height*0.5 - 2*ctx.lineWidth, this.width + 4*ctx.lineWidth, this.height + 4*ctx.lineWidth);
-    ctx.stroke();
-  }
-  ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-  ctx.lineWidth *= this.graphScaleInv;
-  ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-  ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
-  ctx.database(this.x - this.width/2, this.y - this.height*0.5, this.width, this.height);
-  ctx.fill();
-  ctx.stroke();
-
-  this._label(ctx, this.label, this.x, this.y);
-};
-
-
-Node.prototype._resizeCircle = function (ctx) {
-  if (!this.width) {
-    var margin = 5;
-    var textSize = this.getTextSize(ctx);
-    var diameter = Math.max(textSize.width, textSize.height) + 2 * margin;
-    this.radius = diameter / 2;
-
-    this.width = diameter;
-    this.height = diameter;
-
-    // scaling used for clustering
-//    this.width  += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeWidthFactor;
-//    this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeHeightFactor;
-    this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
-    this.growthIndicator = this.radius - 0.5*diameter;
-  }
-};
-
-Node.prototype._drawCircle = function (ctx) {
-  this._resizeCircle(ctx);
-  this.left = this.x - this.width / 2;
-  this.top = this.y - this.height / 2;
-
-  var clusterLineWidth = 2.5;
-  var selectionLineWidth = 2;
-
-  ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
-
-  // draw the outer border
-  if (this.clusterSize > 1) {
-    ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-    ctx.lineWidth *= this.graphScaleInv;
-    ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-    ctx.circle(this.x, this.y, this.radius+2*ctx.lineWidth);
-    ctx.stroke();
-  }
-  ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-  ctx.lineWidth *= this.graphScaleInv;
-  ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-  ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
-  ctx.circle(this.x, this.y, this.radius);
-  ctx.fill();
-  ctx.stroke();
-
-  this._label(ctx, this.label, this.x, this.y);
-};
-
-Node.prototype._resizeEllipse = function (ctx) {
-  if (!this.width) {
-    var textSize = this.getTextSize(ctx);
-
-    this.width = textSize.width * 1.5;
-    this.height = textSize.height * 2;
-    if (this.width < this.height) {
-      this.width = this.height;
-    }
-    var defaultSize = this.width;
-
-      // scaling used for clustering
-    this.width  += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
-    this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
-    this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
-    this.growthIndicator = this.width - defaultSize;
-  }
-};
-
-Node.prototype._drawEllipse = function (ctx) {
-  this._resizeEllipse(ctx);
-  this.left = this.x - this.width / 2;
-  this.top = this.y - this.height / 2;
-
-  var clusterLineWidth = 2.5;
-  var selectionLineWidth = 2;
-
-  ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
-
-  // draw the outer border
-  if (this.clusterSize > 1) {
-    ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-    ctx.lineWidth *= this.graphScaleInv;
-    ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-    ctx.ellipse(this.left-2*ctx.lineWidth, this.top-2*ctx.lineWidth, this.width+4*ctx.lineWidth, this.height+4*ctx.lineWidth);
-    ctx.stroke();
-  }
-  ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-  ctx.lineWidth *= this.graphScaleInv;
-  ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-  ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
-
-  ctx.ellipse(this.left, this.top, this.width, this.height);
-  ctx.fill();
-  ctx.stroke();
-  this._label(ctx, this.label, this.x, this.y);
-};
-
-Node.prototype._drawDot = function (ctx) {
-  this._drawShape(ctx, 'circle');
-};
-
-Node.prototype._drawTriangle = function (ctx) {
-  this._drawShape(ctx, 'triangle');
-};
-
-Node.prototype._drawTriangleDown = function (ctx) {
-  this._drawShape(ctx, 'triangleDown');
-};
-
-Node.prototype._drawSquare = function (ctx) {
-  this._drawShape(ctx, 'square');
-};
-
-Node.prototype._drawStar = function (ctx) {
-  this._drawShape(ctx, 'star');
-};
-
-Node.prototype._resizeShape = function (ctx) {
-  if (!this.width) {
-    this.radius = this.baseRadiusValue;
-    var size = 2 * this.radius;
-    this.width = size;
-    this.height = size;
-
-    // scaling used for clustering
-    this.width  += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
-    this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
-    this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * 0.5 * this.clusterSizeRadiusFactor;
-    this.growthIndicator = this.width - size;
-  }
-};
-
-Node.prototype._drawShape = function (ctx, shape) {
-  this._resizeShape(ctx);
-
-  this.left = this.x - this.width / 2;
-  this.top = this.y - this.height / 2;
-
-  var clusterLineWidth = 2.5;
-  var selectionLineWidth = 2;
-  var radiusMultiplier = 2;
-
-  // choose draw method depending on the shape
-  switch (shape) {
-    case 'dot':           radiusMultiplier = 2; break;
-    case 'square':        radiusMultiplier = 2; break;
-    case 'triangle':      radiusMultiplier = 3; break;
-    case 'triangleDown':  radiusMultiplier = 3; break;
-    case 'star':          radiusMultiplier = 4; break;
-  }
-
-  ctx.strokeStyle = this.selected ? this.color.highlight.border : this.hover ? this.color.hover.border : this.color.border;
-
-  // draw the outer border
-  if (this.clusterSize > 1) {
-    ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-    ctx.lineWidth *= this.graphScaleInv;
-    ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-    ctx[shape](this.x, this.y, this.radius + radiusMultiplier * ctx.lineWidth);
-    ctx.stroke();
-  }
-  ctx.lineWidth = (this.selected ? selectionLineWidth : 1.0) + ((this.clusterSize > 1) ? clusterLineWidth : 0.0);
-  ctx.lineWidth *= this.graphScaleInv;
-  ctx.lineWidth = Math.min(0.1 * this.width,ctx.lineWidth);
-
-  ctx.fillStyle = this.selected ? this.color.highlight.background : this.hover ? this.color.hover.background : this.color.background;
-  ctx[shape](this.x, this.y, this.radius);
-  ctx.fill();
-  ctx.stroke();
-
-  if (this.label) {
-    this._label(ctx, this.label, this.x, this.y + this.height / 2, undefined, 'top');
-  }
-};
-
-Node.prototype._resizeText = function (ctx) {
-  if (!this.width) {
-    var margin = 5;
-    var textSize = this.getTextSize(ctx);
-    this.width = textSize.width + 2 * margin;
-    this.height = textSize.height + 2 * margin;
-
-    // scaling used for clustering
-    this.width  += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeWidthFactor;
-    this.height += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeHeightFactor;
-    this.radius += Math.min(this.clusterSize - 1, this.maxNodeSizeIncrements) * this.clusterSizeRadiusFactor;
-    this.growthIndicator = this.width - (textSize.width + 2 * margin);
-  }
-};
-
-Node.prototype._drawText = function (ctx) {
-  this._resizeText(ctx);
-  this.left = this.x - this.width / 2;
-  this.top = this.y - this.height / 2;
-
-  this._label(ctx, this.label, this.x, this.y);
-};
-
-
-Node.prototype._label = function (ctx, text, x, y, align, baseline) {
-  if (text && this.fontSize * this.graphScale > this.fontDrawThreshold) {
-    ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace;
-    ctx.fillStyle = this.fontColor || "black";
-    ctx.textAlign = align || "center";
-    ctx.textBaseline = baseline || "middle";
-
-    var lines = text.split('\n'),
-        lineCount = lines.length,
-        fontSize = (this.fontSize + 4),
-        yLine = y + (1 - lineCount) / 2 * fontSize;
-
-    for (var i = 0; i < lineCount; i++) {
-      ctx.fillText(lines[i], x, yLine);
-      yLine += fontSize;
-    }
-  }
-};
-
-
-Node.prototype.getTextSize = function(ctx) {
-  if (this.label !== undefined) {
-    ctx.font = (this.selected ? "bold " : "") + this.fontSize + "px " + this.fontFace;
-
-    var lines = this.label.split('\n'),
-        height = (this.fontSize + 4) * lines.length,
-        width = 0;
-
-    for (var i = 0, iMax = lines.length; i < iMax; i++) {
-      width = Math.max(width, ctx.measureText(lines[i]).width);
-    }
-
-    return {"width": width, "height": height};
-  }
-  else {
-    return {"width": 0, "height": 0};
-  }
-};
-
-/**
- * this is used to determine if a node is visible at all. this is used to determine when it needs to be drawn.
- * there is a safety margin of 0.3 * width;
- *
- * @returns {boolean}
- */
-Node.prototype.inArea = function() {
-  if (this.width !== undefined) {
-  return (this.x + this.width *this.graphScaleInv  >= this.canvasTopLeft.x     &&
-          this.x - this.width *this.graphScaleInv  <  this.canvasBottomRight.x &&
-          this.y + this.height*this.graphScaleInv  >= this.canvasTopLeft.y     &&
-          this.y - this.height*this.graphScaleInv  <  this.canvasBottomRight.y);
-  }
-  else {
-    return true;
-  }
-};
-
-/**
- * checks if the core of the node is in the display area, this is used for opening clusters around zoom
- * @returns {boolean}
- */
-Node.prototype.inView = function() {
-  return (this.x >= this.canvasTopLeft.x    &&
-          this.x < this.canvasBottomRight.x &&
-          this.y >= this.canvasTopLeft.y    &&
-          this.y < this.canvasBottomRight.y);
-};
-
-/**
- * This allows the zoom level of the graph to influence the rendering
- * We store the inverted scale and the coordinates of the top left, and bottom right points of the canvas
- *
- * @param scale
- * @param canvasTopLeft
- * @param canvasBottomRight
- */
-Node.prototype.setScaleAndPos = function(scale,canvasTopLeft,canvasBottomRight) {
-  this.graphScaleInv = 1.0/scale;
-  this.graphScale = scale;
-  this.canvasTopLeft = canvasTopLeft;
-  this.canvasBottomRight = canvasBottomRight;
-};
-
-
-/**
- * This allows the zoom level of the graph to influence the rendering
- *
- * @param scale
- */
-Node.prototype.setScale = function(scale) {
-  this.graphScaleInv = 1.0/scale;
-  this.graphScale = scale;
-};
-
-
-
-/**
- * set the velocity at 0. Is called when this node is contained in another during clustering
- */
-Node.prototype.clearVelocity = function() {
-  this.vx = 0;
-  this.vy = 0;
-};
-
-
-/**
- * Basic preservation of (kinectic) energy
- *
- * @param massBeforeClustering
- */
-Node.prototype.updateVelocity = function(massBeforeClustering) {
-  var energyBefore = this.vx * this.vx * massBeforeClustering;
-  //this.vx = (this.vx < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass);
-  this.vx = Math.sqrt(energyBefore/this.mass);
-  energyBefore = this.vy * this.vy * massBeforeClustering;
-  //this.vy = (this.vy < 0) ? -Math.sqrt(energyBefore/this.mass) : Math.sqrt(energyBefore/this.mass);
-  this.vy = Math.sqrt(energyBefore/this.mass);
-};
-
-
-/**
- * @class Edge
- *
- * A edge connects two nodes
- * @param {Object} properties     Object with properties. Must contain
- *                                At least properties from and to.
- *                                Available properties: from (number),
- *                                to (number), label (string, color (string),
- *                                width (number), style (string),
- *                                length (number), title (string)
- * @param {Graph} graph A graph object, used to find and edge to
- *                                nodes.
- * @param {Object} constants      An object with default values for
- *                                example for the color
- */
-function Edge (properties, graph, constants) {
-  if (!graph) {
-    throw "No graph provided";
-  }
-  this.graph = graph;
-
-  // initialize constants
-  this.widthMin = constants.edges.widthMin;
-  this.widthMax = constants.edges.widthMax;
-
-  // initialize variables
-  this.id     = undefined;
-  this.fromId = undefined;
-  this.toId   = undefined;
-  this.style  = constants.edges.style;
-  this.title  = undefined;
-  this.width  = constants.edges.width;
-  this.hoverWidth = constants.edges.hoverWidth;
-  this.value  = undefined;
-  this.length = constants.physics.springLength;
-  this.customLength = false;
-  this.selected = false;
-  this.hover = false;
-  this.smooth = constants.smoothCurves;
-  this.arrowScaleFactor = constants.edges.arrowScaleFactor;
-
-  this.from = null;   // a node
-  this.to = null;     // a node
-  this.via = null;    // a temp node
-
-  // we use this to be able to reconnect the edge to a cluster if its node is put into a cluster
-  // by storing the original information we can revert to the original connection when the cluser is opened.
-  this.originalFromId = [];
-  this.originalToId = [];
-
-  this.connected = false;
-
-  // Added to support dashed lines
-  // David Jordan
-  // 2012-08-08
-  this.dash = util.extend({}, constants.edges.dash); // contains properties length, gap, altLength
-
-  this.color       = {color:constants.edges.color.color,
-                      highlight:constants.edges.color.highlight,
-                      hover:constants.edges.color.hover};
-  this.widthFixed  = false;
-  this.lengthFixed = false;
-
-  this.setProperties(properties, constants);
-
-  this.controlNodesEnabled = false;
-  this.controlNodes = {from:null, to:null, positions:{}};
-  this.connectedNode = null;
-}
-
-/**
- * Set or overwrite properties for the edge
- * @param {Object} properties  an object with properties
- * @param {Object} constants   and object with default, global properties
- */
-Edge.prototype.setProperties = function(properties, constants) {
-  if (!properties) {
-    return;
-  }
-
-  if (properties.from !== undefined)           {this.fromId = properties.from;}
-  if (properties.to !== undefined)             {this.toId = properties.to;}
-
-  if (properties.id !== undefined)             {this.id = properties.id;}
-  if (properties.style !== undefined)          {this.style = properties.style;}
-  if (properties.label !== undefined)          {this.label = properties.label;}
-
-  if (this.label) {
-    this.fontSize = constants.edges.fontSize;
-    this.fontFace = constants.edges.fontFace;
-    this.fontColor = constants.edges.fontColor;
-    this.fontFill = constants.edges.fontFill;
-
-    if (properties.fontColor !== undefined)  {this.fontColor = properties.fontColor;}
-    if (properties.fontSize !== undefined)   {this.fontSize = properties.fontSize;}
-    if (properties.fontFace !== undefined)   {this.fontFace = properties.fontFace;}
-    if (properties.fontFill !== undefined)   {this.fontFill = properties.fontFill;}
-  }
-
-  if (properties.title !== undefined)        {this.title = properties.title;}
-  if (properties.width !== undefined)        {this.width = properties.width;}
-  if (properties.hoverWidth !== undefined)   {this.hoverWidth = properties.hoverWidth;}
-  if (properties.value !== undefined)        {this.value = properties.value;}
-  if (properties.length !== undefined)       {this.length = properties.length;
-                                              this.customLength = true;}
-
-  // scale the arrow
-  if (properties.arrowScaleFactor !== undefined)       {this.arrowScaleFactor = properties.arrowScaleFactor;}
-
-  // Added to support dashed lines
-  // David Jordan
-  // 2012-08-08
-  if (properties.dash) {
-    if (properties.dash.length !== undefined)    {this.dash.length = properties.dash.length;}
-    if (properties.dash.gap !== undefined)       {this.dash.gap = properties.dash.gap;}
-    if (properties.dash.altLength !== undefined) {this.dash.altLength = properties.dash.altLength;}
-  }
-
-  if (properties.color !== undefined) {
-    if (util.isString(properties.color)) {
-      this.color.color = properties.color;
-      this.color.highlight = properties.color;
-    }
-    else {
-      if (properties.color.color !== undefined)     {this.color.color = properties.color.color;}
-      if (properties.color.highlight !== undefined) {this.color.highlight = properties.color.highlight;}
-    }
-  }
-
-  // A node is connected when it has a from and to node.
-  this.connect();
-
-  this.widthFixed = this.widthFixed || (properties.width !== undefined);
-  this.lengthFixed = this.lengthFixed || (properties.length !== undefined);
-
-  // set draw method based on style
-  switch (this.style) {
-    case 'line':          this.draw = this._drawLine; break;
-    case 'arrow':         this.draw = this._drawArrow; break;
-    case 'arrow-center':  this.draw = this._drawArrowCenter; break;
-    case 'dash-line':     this.draw = this._drawDashLine; break;
-    default:              this.draw = this._drawLine; break;
-  }
-};
-
-/**
- * Connect an edge to its nodes
- */
-Edge.prototype.connect = function () {
-  this.disconnect();
-
-  this.from = this.graph.nodes[this.fromId] || null;
-  this.to = this.graph.nodes[this.toId] || null;
-  this.connected = (this.from && this.to);
-
-  if (this.connected) {
-    this.from.attachEdge(this);
-    this.to.attachEdge(this);
-  }
-  else {
-    if (this.from) {
-      this.from.detachEdge(this);
-    }
-    if (this.to) {
-      this.to.detachEdge(this);
-    }
-  }
-};
-
-/**
- * Disconnect an edge from its nodes
- */
-Edge.prototype.disconnect = function () {
-  if (this.from) {
-    this.from.detachEdge(this);
-    this.from = null;
-  }
-  if (this.to) {
-    this.to.detachEdge(this);
-    this.to = null;
-  }
-
-  this.connected = false;
-};
-
-/**
- * get the title of this edge.
- * @return {string} title    The title of the edge, or undefined when no title
- *                           has been set.
- */
-Edge.prototype.getTitle = function() {
-  return typeof this.title === "function" ? this.title() : this.title;
-};
-
-
-/**
- * Retrieve the value of the edge. Can be undefined
- * @return {Number} value
- */
-Edge.prototype.getValue = function() {
-  return this.value;
-};
-
-/**
- * Adjust the value range of the edge. The edge will adjust it's width
- * based on its value.
- * @param {Number} min
- * @param {Number} max
- */
-Edge.prototype.setValueRange = function(min, max) {
-  if (!this.widthFixed && this.value !== undefined) {
-    var scale = (this.widthMax - this.widthMin) / (max - min);
-    this.width = (this.value - min) * scale + this.widthMin;
-  }
-};
-
-/**
- * Redraw a edge
- * Draw this edge in the given canvas
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
- * @param {CanvasRenderingContext2D}   ctx
- */
-Edge.prototype.draw = function(ctx) {
-  throw "Method draw not initialized in edge";
-};
-
-/**
- * Check if this object is overlapping with the provided object
- * @param {Object} obj   an object with parameters left, top
- * @return {boolean}     True if location is located on the edge
- */
-Edge.prototype.isOverlappingWith = function(obj) {
-  if (this.connected) {
-    var distMax = 10;
-    var xFrom = this.from.x;
-    var yFrom = this.from.y;
-    var xTo = this.to.x;
-    var yTo = this.to.y;
-    var xObj = obj.left;
-    var yObj = obj.top;
-
-    var dist = this._getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
-
-    return (dist < distMax);
-  }
-  else {
-    return false
-  }
-};
-
-
-/**
- * Redraw a edge as a line
- * Draw this edge in the given canvas
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
- * @param {CanvasRenderingContext2D}   ctx
- * @private
- */
-Edge.prototype._drawLine = function(ctx) {
-  // set style
-  if (this.selected == true)   {ctx.strokeStyle = this.color.highlight;}
-  else if (this.hover == true) {ctx.strokeStyle = this.color.hover;}
-  else                         {ctx.strokeStyle = this.color.color;}
-  ctx.lineWidth = this._getLineWidth();
-
-  if (this.from != this.to) {
-    // draw line
-    this._line(ctx);
-
-    // draw label
-    var point;
-    if (this.label) {
-      if (this.smooth == true) {
-        var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
-        var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
-        point = {x:midpointX, y:midpointY};
-      }
-      else {
-        point = this._pointOnLine(0.5);
-      }
-      this._label(ctx, this.label, point.x, point.y);
-    }
-  }
-  else {
-    var x, y;
-    var radius = this.length / 4;
-    var node = this.from;
-    if (!node.width) {
-      node.resize(ctx);
-    }
-    if (node.width > node.height) {
-      x = node.x + node.width / 2;
-      y = node.y - radius;
-    }
-    else {
-      x = node.x + radius;
-      y = node.y - node.height / 2;
-    }
-    this._circle(ctx, x, y, radius);
-    point = this._pointOnCircle(x, y, radius, 0.5);
-    this._label(ctx, this.label, point.x, point.y);
-  }
-};
-
-/**
- * Get the line width of the edge. Depends on width and whether one of the
- * connected nodes is selected.
- * @return {Number} width
- * @private
- */
-Edge.prototype._getLineWidth = function() {
-  if (this.selected == true) {
-    return Math.min(this.width * 2, this.widthMax)*this.graphScaleInv;
-  }
-  else {
-    if (this.hover == true) {
-      return Math.min(this.hoverWidth, this.widthMax)*this.graphScaleInv;
-    }
-    else {
-      return this.width*this.graphScaleInv;
-    }
-  }
-};
-
-/**
- * Draw a line between two nodes
- * @param {CanvasRenderingContext2D} ctx
- * @private
- */
-Edge.prototype._line = function (ctx) {
-  // draw a straight line
-  ctx.beginPath();
-  ctx.moveTo(this.from.x, this.from.y);
- if (this.smooth == true) {
-      ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y);
-  }
-  else {
-    ctx.lineTo(this.to.x, this.to.y);
-  }
-  ctx.stroke();
-};
-
-/**
- * Draw a line from a node to itself, a circle
- * @param {CanvasRenderingContext2D} ctx
- * @param {Number} x
- * @param {Number} y
- * @param {Number} radius
- * @private
- */
-Edge.prototype._circle = function (ctx, x, y, radius) {
-  // draw a circle
-  ctx.beginPath();
-  ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
-  ctx.stroke();
-};
-
-/**
- * Draw label with white background and with the middle at (x, y)
- * @param {CanvasRenderingContext2D} ctx
- * @param {String} text
- * @param {Number} x
- * @param {Number} y
- * @private
- */
-Edge.prototype._label = function (ctx, text, x, y) {
-  if (text) {
-    // TODO: cache the calculated size
-    ctx.font = ((this.from.selected || this.to.selected) ? "bold " : "") +
-        this.fontSize + "px " + this.fontFace;
-    ctx.fillStyle = this.fontFill;
-    var width = ctx.measureText(text).width;
-    var height = this.fontSize;
-    var left = x - width / 2;
-    var top = y - height / 2;
-
-    ctx.fillRect(left, top, width, height);
-
-    // draw text
-    ctx.fillStyle = this.fontColor || "black";
-    ctx.textAlign = "left";
-    ctx.textBaseline = "top";
-    ctx.fillText(text, left, top);
-  }
-};
-
-/**
- * Redraw a edge as a dashed line
- * Draw this edge in the given canvas
- * @author David Jordan
- * @date 2012-08-08
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
- * @param {CanvasRenderingContext2D}   ctx
- * @private
- */
-Edge.prototype._drawDashLine = function(ctx) {
-  // set style
-  if (this.selected == true)   {ctx.strokeStyle = this.color.highlight;}
-  else if (this.hover == true) {ctx.strokeStyle = this.color.hover;}
-  else                         {ctx.strokeStyle = this.color.color;}
-
-  ctx.lineWidth = this._getLineWidth();
-
-  // only firefox and chrome support this method, else we use the legacy one.
-  if (ctx.mozDash !== undefined || ctx.setLineDash !== undefined) {
-    ctx.beginPath();
-    ctx.moveTo(this.from.x, this.from.y);
-
-    // configure the dash pattern
-    var pattern = [0];
-    if (this.dash.length !== undefined && this.dash.gap !== undefined) {
-      pattern = [this.dash.length,this.dash.gap];
-    }
-    else {
-      pattern = [5,5];
-    }
-
-    // set dash settings for chrome or firefox
-    if (typeof ctx.setLineDash !== 'undefined') { //Chrome
-      ctx.setLineDash(pattern);
-      ctx.lineDashOffset = 0;
-
-    } else { //Firefox
-      ctx.mozDash = pattern;
-      ctx.mozDashOffset = 0;
-    }
-
-    // draw the line
-    if (this.smooth == true) {
-      ctx.quadraticCurveTo(this.via.x,this.via.y,this.to.x, this.to.y);
-    }
-    else {
-      ctx.lineTo(this.to.x, this.to.y);
-    }
-    ctx.stroke();
-
-    // restore the dash settings.
-    if (typeof ctx.setLineDash !== 'undefined') { //Chrome
-      ctx.setLineDash([0]);
-      ctx.lineDashOffset = 0;
-
-    } else { //Firefox
-      ctx.mozDash = [0];
-      ctx.mozDashOffset = 0;
-    }
-  }
-  else { // unsupporting smooth lines
-    // draw dashed line
-    ctx.beginPath();
-    ctx.lineCap = 'round';
-    if (this.dash.altLength !== undefined) //If an alt dash value has been set add to the array this value
-    {
-      ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
-          [this.dash.length,this.dash.gap,this.dash.altLength,this.dash.gap]);
-    }
-    else if (this.dash.length !== undefined && this.dash.gap !== undefined) //If a dash and gap value has been set add to the array this value
-    {
-      ctx.dashedLine(this.from.x,this.from.y,this.to.x,this.to.y,
-          [this.dash.length,this.dash.gap]);
-    }
-    else //If all else fails draw a line
-    {
-      ctx.moveTo(this.from.x, this.from.y);
-      ctx.lineTo(this.to.x, this.to.y);
-    }
-    ctx.stroke();
-  }
-
-  // draw label
-  if (this.label) {
-    var point;
-    if (this.smooth == true) {
-      var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
-      var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
-      point = {x:midpointX, y:midpointY};
-    }
-    else {
-      point = this._pointOnLine(0.5);
-    }
-    this._label(ctx, this.label, point.x, point.y);
-  }
-};
-
-/**
- * Get a point on a line
- * @param {Number} percentage. Value between 0 (line start) and 1 (line end)
- * @return {Object} point
- * @private
- */
-Edge.prototype._pointOnLine = function (percentage) {
-  return {
-    x: (1 - percentage) * this.from.x + percentage * this.to.x,
-    y: (1 - percentage) * this.from.y + percentage * this.to.y
-  }
-};
-
-/**
- * Get a point on a circle
- * @param {Number} x
- * @param {Number} y
- * @param {Number} radius
- * @param {Number} percentage. Value between 0 (line start) and 1 (line end)
- * @return {Object} point
- * @private
- */
-Edge.prototype._pointOnCircle = function (x, y, radius, percentage) {
-  var angle = (percentage - 3/8) * 2 * Math.PI;
-  return {
-    x: x + radius * Math.cos(angle),
-    y: y - radius * Math.sin(angle)
-  }
-};
-
-/**
- * Redraw a edge as a line with an arrow halfway the line
- * Draw this edge in the given canvas
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
- * @param {CanvasRenderingContext2D}   ctx
- * @private
- */
-Edge.prototype._drawArrowCenter = function(ctx) {
-  var point;
-  // set style
-  if (this.selected == true)   {ctx.strokeStyle = this.color.highlight; ctx.fillStyle = this.color.highlight;}
-  else if (this.hover == true) {ctx.strokeStyle = this.color.hover;     ctx.fillStyle = this.color.hover;}
-  else                         {ctx.strokeStyle = this.color.color;     ctx.fillStyle = this.color.color;}
-  ctx.lineWidth = this._getLineWidth();
-
-  if (this.from != this.to) {
-    // draw line
-    this._line(ctx);
-
-    var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
-    var length = (10 + 5 * this.width) * this.arrowScaleFactor;
-    // draw an arrow halfway the line
-    if (this.smooth == true) {
-      var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
-      var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
-      point = {x:midpointX, y:midpointY};
-    }
-    else {
-      point = this._pointOnLine(0.5);
-    }
-
-    ctx.arrow(point.x, point.y, angle, length);
-    ctx.fill();
-    ctx.stroke();
-
-    // draw label
-    if (this.label) {
-      this._label(ctx, this.label, point.x, point.y);
-    }
-  }
-  else {
-    // draw circle
-    var x, y;
-    var radius = 0.25 * Math.max(100,this.length);
-    var node = this.from;
-    if (!node.width) {
-      node.resize(ctx);
-    }
-    if (node.width > node.height) {
-      x = node.x + node.width * 0.5;
-      y = node.y - radius;
-    }
-    else {
-      x = node.x + radius;
-      y = node.y - node.height * 0.5;
-    }
-    this._circle(ctx, x, y, radius);
-
-    // draw all arrows
-    var angle = 0.2 * Math.PI;
-    var length = (10 + 5 * this.width) * this.arrowScaleFactor;
-    point = this._pointOnCircle(x, y, radius, 0.5);
-    ctx.arrow(point.x, point.y, angle, length);
-    ctx.fill();
-    ctx.stroke();
-
-    // draw label
-    if (this.label) {
-      point = this._pointOnCircle(x, y, radius, 0.5);
-      this._label(ctx, this.label, point.x, point.y);
-    }
-  }
-};
-
-
-
-/**
- * Redraw a edge as a line with an arrow
- * Draw this edge in the given canvas
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
- * @param {CanvasRenderingContext2D}   ctx
- * @private
- */
-Edge.prototype._drawArrow = function(ctx) {
-  // set style
-  if (this.selected == true)   {ctx.strokeStyle = this.color.highlight; ctx.fillStyle = this.color.highlight;}
-  else if (this.hover == true) {ctx.strokeStyle = this.color.hover;     ctx.fillStyle = this.color.hover;}
-  else                         {ctx.strokeStyle = this.color.color;     ctx.fillStyle = this.color.color;}
-
-  ctx.lineWidth = this._getLineWidth();
-
-  var angle, length;
-  //draw a line
-  if (this.from != this.to) {
-    angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
-    var dx = (this.to.x - this.from.x);
-    var dy = (this.to.y - this.from.y);
-    var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
-
-    var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
-    var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
-    var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
-    var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
-
-
-    if (this.smooth == true) {
-      angle = Math.atan2((this.to.y - this.via.y), (this.to.x - this.via.x));
-      dx = (this.to.x - this.via.x);
-      dy = (this.to.y - this.via.y);
-      edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
-    }
-    var toBorderDist = this.to.distanceToBorder(ctx, angle);
-    var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
-
-    var xTo,yTo;
-    if (this.smooth == true) {
-     xTo = (1 - toBorderPoint) * this.via.x + toBorderPoint * this.to.x;
-     yTo = (1 - toBorderPoint) * this.via.y + toBorderPoint * this.to.y;
-    }
-    else {
-      xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
-      yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
-    }
-
-    ctx.beginPath();
-    ctx.moveTo(xFrom,yFrom);
-    if (this.smooth == true) {
-      ctx.quadraticCurveTo(this.via.x,this.via.y,xTo, yTo);
-    }
-    else {
-      ctx.lineTo(xTo, yTo);
-    }
-    ctx.stroke();
-
-    // draw arrow at the end of the line
-    length = (10 + 5 * this.width) * this.arrowScaleFactor;
-    ctx.arrow(xTo, yTo, angle, length);
-    ctx.fill();
-    ctx.stroke();
-
-    // draw label
-    if (this.label) {
-      var point;
-      if (this.smooth == true) {
-        var midpointX = 0.5*(0.5*(this.from.x + this.via.x) + 0.5*(this.to.x + this.via.x));
-        var midpointY = 0.5*(0.5*(this.from.y + this.via.y) + 0.5*(this.to.y + this.via.y));
-        point = {x:midpointX, y:midpointY};
-      }
-      else {
-        point = this._pointOnLine(0.5);
-      }
-      this._label(ctx, this.label, point.x, point.y);
-    }
-  }
-  else {
-    // draw circle
-    var node = this.from;
-    var x, y, arrow;
-    var radius = 0.25 * Math.max(100,this.length);
-    if (!node.width) {
-      node.resize(ctx);
-    }
-    if (node.width > node.height) {
-      x = node.x + node.width * 0.5;
-      y = node.y - radius;
-      arrow = {
-        x: x,
-        y: node.y,
-        angle: 0.9 * Math.PI
-      };
-    }
-    else {
-      x = node.x + radius;
-      y = node.y - node.height * 0.5;
-      arrow = {
-        x: node.x,
-        y: y,
-        angle: 0.6 * Math.PI
-      };
-    }
-    ctx.beginPath();
-    // TODO: similarly, for a line without arrows, draw to the border of the nodes instead of the center
-    ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
-    ctx.stroke();
-
-    // draw all arrows
-    var length = (10 + 5 * this.width) * this.arrowScaleFactor;
-    ctx.arrow(arrow.x, arrow.y, arrow.angle, length);
-    ctx.fill();
-    ctx.stroke();
-
-    // draw label
-    if (this.label) {
-      point = this._pointOnCircle(x, y, radius, 0.5);
-      this._label(ctx, this.label, point.x, point.y);
-    }
-  }
-};
-
-
-
-/**
- * Calculate the distance between a point (x3,y3) and a line segment from
- * (x1,y1) to (x2,y2).
- * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
- * @param {number} x1
- * @param {number} y1
- * @param {number} x2
- * @param {number} y2
- * @param {number} x3
- * @param {number} y3
- * @private
- */
-Edge.prototype._getDistanceToEdge = function (x1,y1, x2,y2, x3,y3) { // x3,y3 is the point
-  if (this.from != this.to) {
-    if (this.smooth == true) {
-      var minDistance = 1e9;
-      var i,t,x,y,dx,dy;
-      for (i = 0; i < 10; i++) {
-        t = 0.1*i;
-        x = Math.pow(1-t,2)*x1 + (2*t*(1 - t))*this.via.x + Math.pow(t,2)*x2;
-        y = Math.pow(1-t,2)*y1 + (2*t*(1 - t))*this.via.y + Math.pow(t,2)*y2;
-        dx = Math.abs(x3-x);
-        dy = Math.abs(y3-y);
-        minDistance = Math.min(minDistance,Math.sqrt(dx*dx + dy*dy));
-      }
-      return minDistance
-    }
-    else {
-      var px = x2-x1,
-          py = y2-y1,
-          something = px*px + py*py,
-          u =  ((x3 - x1) * px + (y3 - y1) * py) / something;
-
-      if (u > 1) {
-        u = 1;
-      }
-      else if (u < 0) {
-        u = 0;
-      }
-
-      var x = x1 + u * px,
-          y = y1 + u * py,
-          dx = x - x3,
-          dy = y - y3;
-
-      //# Note: If the actual distance does not matter,
-      //# if you only want to compare what this function
-      //# returns to other results of this function, you
-      //# can just return the squared distance instead
-      //# (i.e. remove the sqrt) to gain a little performance
-
-      return Math.sqrt(dx*dx + dy*dy);
-    }
-  }
-  else {
-    var x, y, dx, dy;
-    var radius = this.length / 4;
-    var node = this.from;
-    if (!node.width) {
-      node.resize(ctx);
-    }
-    if (node.width > node.height) {
-      x = node.x + node.width / 2;
-      y = node.y - radius;
-    }
-    else {
-      x = node.x + radius;
-      y = node.y - node.height / 2;
-    }
-    dx = x - x3;
-    dy = y - y3;
-    return Math.abs(Math.sqrt(dx*dx + dy*dy) - radius);
-  }
-};
-
-
-
-/**
- * This allows the zoom level of the graph to influence the rendering
- *
- * @param scale
- */
-Edge.prototype.setScale = function(scale) {
-  this.graphScaleInv = 1.0/scale;
-};
-
-
-Edge.prototype.select = function() {
-  this.selected = true;
-};
-
-Edge.prototype.unselect = function() {
-  this.selected = false;
-};
-
-Edge.prototype.positionBezierNode = function() {
-  if (this.via !== null) {
-    this.via.x = 0.5 * (this.from.x + this.to.x);
-    this.via.y = 0.5 * (this.from.y + this.to.y);
-  }
-};
-
-/**
- * This function draws the control nodes for the manipulator. In order to enable this, only set the this.controlNodesEnabled to true.
- * @param ctx
- */
-Edge.prototype._drawControlNodes = function(ctx) {
-  if (this.controlNodesEnabled == true) {
-    if (this.controlNodes.from === null && this.controlNodes.to === null) {
-      var nodeIdFrom = "edgeIdFrom:".concat(this.id);
-      var nodeIdTo = "edgeIdTo:".concat(this.id);
-      var constants = {
-                      nodes:{group:'', radius:8},
-                      physics:{damping:0},
-                      clustering: {maxNodeSizeIncrements: 0 ,nodeScaling: {width:0, height: 0, radius:0}}
-                      };
-      this.controlNodes.from = new Node(
-        {id:nodeIdFrom,
-          shape:'dot',
-            color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}}
-        },{},{},constants);
-      this.controlNodes.to = new Node(
-        {id:nodeIdTo,
-          shape:'dot',
-          color:{background:'#ff4e00', border:'#3c3c3c', highlight: {background:'#07f968'}}
-        },{},{},constants);
-    }
-
-    if (this.controlNodes.from.selected == false && this.controlNodes.to.selected == false) {
-      this.controlNodes.positions = this.getControlNodePositions(ctx);
-      this.controlNodes.from.x = this.controlNodes.positions.from.x;
-      this.controlNodes.from.y = this.controlNodes.positions.from.y;
-      this.controlNodes.to.x = this.controlNodes.positions.to.x;
-      this.controlNodes.to.y = this.controlNodes.positions.to.y;
-    }
-
-    this.controlNodes.from.draw(ctx);
-    this.controlNodes.to.draw(ctx);
-  }
-  else {
-    this.controlNodes = {from:null, to:null, positions:{}};
-  }
-}
-
-/**
- * Enable control nodes.
- * @private
- */
-Edge.prototype._enableControlNodes = function() {
-  this.controlNodesEnabled = true;
-}
-
-/**
- * disable control nodes
- * @private
- */
-Edge.prototype._disableControlNodes = function() {
-  this.controlNodesEnabled = false;
-}
-
-/**
- * This checks if one of the control nodes is selected and if so, returns the control node object. Else it returns null.
- * @param x
- * @param y
- * @returns {null}
- * @private
- */
-Edge.prototype._getSelectedControlNode = function(x,y) {
-  var positions = this.controlNodes.positions;
-  var fromDistance = Math.sqrt(Math.pow(x - positions.from.x,2) + Math.pow(y - positions.from.y,2));
-  var toDistance =   Math.sqrt(Math.pow(x - positions.to.x  ,2) + Math.pow(y - positions.to.y  ,2));
-
-  if (fromDistance < 15) {
-    this.connectedNode = this.from;
-    this.from = this.controlNodes.from;
-    return this.controlNodes.from;
-  }
-  else if (toDistance < 15) {
-    this.connectedNode = this.to;
-    this.to = this.controlNodes.to;
-    return this.controlNodes.to;
-  }
-  else {
-    return null;
-  }
-}
-
-
-/**
- * this resets the control nodes to their original position.
- * @private
- */
-Edge.prototype._restoreControlNodes = function() {
-  if (this.controlNodes.from.selected == true) {
-    this.from = this.connectedNode;
-    this.connectedNode = null;
-    this.controlNodes.from.unselect();
-  }
-  if (this.controlNodes.to.selected == true) {
-    this.to = this.connectedNode;
-    this.connectedNode = null;
-    this.controlNodes.to.unselect();
-  }
-}
-
-/**
- * this calculates the position of the control nodes on the edges of the parent nodes.
- *
- * @param ctx
- * @returns {{from: {x: number, y: number}, to: {x: *, y: *}}}
- */
-Edge.prototype.getControlNodePositions = function(ctx) {
-  var angle = Math.atan2((this.to.y - this.from.y), (this.to.x - this.from.x));
-  var dx = (this.to.x - this.from.x);
-  var dy = (this.to.y - this.from.y);
-  var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
-  var fromBorderDist = this.from.distanceToBorder(ctx, angle + Math.PI);
-  var fromBorderPoint = (edgeSegmentLength - fromBorderDist) / edgeSegmentLength;
-  var xFrom = (fromBorderPoint) * this.from.x + (1 - fromBorderPoint) * this.to.x;
-  var yFrom = (fromBorderPoint) * this.from.y + (1 - fromBorderPoint) * this.to.y;
-
-
-  if (this.smooth == true) {
-    angle = Math.atan2((this.to.y - this.via.y), (this.to.x - this.via.x));
-    dx = (this.to.x - this.via.x);
-    dy = (this.to.y - this.via.y);
-    edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
-  }
-  var toBorderDist = this.to.distanceToBorder(ctx, angle);
-  var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
-
-  var xTo,yTo;
-  if (this.smooth == true) {
-    xTo = (1 - toBorderPoint) * this.via.x + toBorderPoint * this.to.x;
-    yTo = (1 - toBorderPoint) * this.via.y + toBorderPoint * this.to.y;
-  }
-  else {
-    xTo = (1 - toBorderPoint) * this.from.x + toBorderPoint * this.to.x;
-    yTo = (1 - toBorderPoint) * this.from.y + toBorderPoint * this.to.y;
-  }
-
-  return {from:{x:xFrom,y:yFrom},to:{x:xTo,y:yTo}};
-}
-/**
- * Popup is a class to create a popup window with some text
- * @param {Element}  container     The container object.
- * @param {Number} [x]
- * @param {Number} [y]
- * @param {String} [text]
- * @param {Object} [style]     An object containing borderColor,
- *                             backgroundColor, etc.
- */
-function Popup(container, x, y, text, style) {
-  if (container) {
-    this.container = container;
-  }
-  else {
-    this.container = document.body;
-  }
-
-  // x, y and text are optional, see if a style object was passed in their place
-  if (style === undefined) {
-    if (typeof x === "object") {
-      style = x;
-      x = undefined;
-    } else if (typeof text === "object") {
-      style = text;
-      text = undefined;
-    } else {
-      // for backwards compatibility, in case clients other than Graph are creating Popup directly
-      style = {
-        fontColor: 'black',
-        fontSize: 14, // px
-        fontFace: 'verdana',
-        color: {
-          border: '#666',
-          background: '#FFFFC6'
-        }
-      }
-    }
-  }
-
-  this.x = 0;
-  this.y = 0;
-  this.padding = 5;
-
-  if (x !== undefined && y !== undefined ) {
-    this.setPosition(x, y);
-  }
-  if (text !== undefined) {
-    this.setText(text);
-  }
-
-  // create the frame
-  this.frame = document.createElement("div");
-  var styleAttr = this.frame.style;
-  styleAttr.position = "absolute";
-  styleAttr.visibility = "hidden";
-  styleAttr.border = "1px solid " + style.color.border;
-  styleAttr.color = style.fontColor;
-  styleAttr.fontSize = style.fontSize + "px";
-  styleAttr.fontFamily = style.fontFace;
-  styleAttr.padding = this.padding + "px";
-  styleAttr.backgroundColor = style.color.background;
-  styleAttr.borderRadius = "3px";
-  styleAttr.MozBorderRadius = "3px";
-  styleAttr.WebkitBorderRadius = "3px";
-  styleAttr.boxShadow = "3px 3px 10px rgba(128, 128, 128, 0.5)";
-  styleAttr.whiteSpace = "nowrap";
-  this.container.appendChild(this.frame);
-}
-
-/**
- * @param {number} x   Horizontal position of the popup window
- * @param {number} y   Vertical position of the popup window
- */
-Popup.prototype.setPosition = function(x, y) {
-  this.x = parseInt(x);
-  this.y = parseInt(y);
-};
-
-/**
- * Set the text for the popup window. This can be HTML code
- * @param {string} text
- */
-Popup.prototype.setText = function(text) {
-  this.frame.innerHTML = text;
-};
-
-/**
- * Show the popup window
- * @param {boolean} show    Optional. Show or hide the window
- */
-Popup.prototype.show = function (show) {
-  if (show === undefined) {
-    show = true;
-  }
-
-  if (show) {
-    var height = this.frame.clientHeight;
-    var width =  this.frame.clientWidth;
-    var maxHeight = this.frame.parentNode.clientHeight;
-    var maxWidth = this.frame.parentNode.clientWidth;
-
-    var top = (this.y - height);
-    if (top + height + this.padding > maxHeight) {
-      top = maxHeight - height - this.padding;
-    }
-    if (top < this.padding) {
-      top = this.padding;
-    }
-
-    var left = this.x;
-    if (left + width + this.padding > maxWidth) {
-      left = maxWidth - width - this.padding;
-    }
-    if (left < this.padding) {
-      left = this.padding;
-    }
-
-    this.frame.style.left = left + "px";
-    this.frame.style.top = top + "px";
-    this.frame.style.visibility = "visible";
-  }
-  else {
-    this.hide();
-  }
-};
-
-/**
- * Hide the popup window
- */
-Popup.prototype.hide = function () {
-  this.frame.style.visibility = "hidden";
-};
-
-/**
- * @class Groups
- * This class can store groups and properties specific for groups.
- */
-function Groups() {
-  this.clear();
-  this.defaultIndex = 0;
-}
-
-
-/**
- * default constants for group colors
- */
-Groups.DEFAULT = [
-  {border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}}, // blue
-  {border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}}, // yellow
-  {border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}}, // red
-  {border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}}, // green
-  {border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}}, // magenta
-  {border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}}, // purple
-  {border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}}, // orange
-  {border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}}, // darkblue
-  {border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}}, // pink
-  {border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}}  // mint
-];
-
-
-/**
- * Clear all groups
- */
-Groups.prototype.clear = function () {
-  this.groups = {};
-  this.groups.length = function()
-  {
-    var i = 0;
-    for ( var p in this ) {
-      if (this.hasOwnProperty(p)) {
-        i++;
-      }
-    }
-    return i;
-  }
-};
-
-
-/**
- * get group properties of a groupname. If groupname is not found, a new group
- * is added.
- * @param {*} groupname        Can be a number, string, Date, etc.
- * @return {Object} group      The created group, containing all group properties
- */
-Groups.prototype.get = function (groupname) {
-  var group = this.groups[groupname];
-
-  if (group == undefined) {
-    // create new group
-    var index = this.defaultIndex % Groups.DEFAULT.length;
-    this.defaultIndex++;
-    group = {};
-    group.color = Groups.DEFAULT[index];
-    this.groups[groupname] = group;
-  }
-
-  return group;
-};
-
-/**
- * Add a custom group style
- * @param {String} groupname
- * @param {Object} style       An object containing borderColor,
- *                             backgroundColor, etc.
- * @return {Object} group      The created group object
- */
-Groups.prototype.add = function (groupname, style) {
-  this.groups[groupname] = style;
-  if (style.color) {
-    style.color = util.parseColor(style.color);
-  }
-  return style;
-};
-
-/**
- * @class Images
- * This class loads images and keeps them stored.
- */
-function Images() {
-  this.images = {};
-
-  this.callback = undefined;
-}
-
-/**
- * Set an onload callback function. This will be called each time an image
- * is loaded
- * @param {function} callback
- */
-Images.prototype.setOnloadCallback = function(callback) {
-  this.callback = callback;
-};
-
-/**
- *
- * @param {string} url          Url of the image
- * @return {Image} img          The image object
- */
-Images.prototype.load = function(url) {
-  var img = this.images[url];
-  if (img == undefined) {
-    // create the image
-    var images = this;
-    img = new Image();
-    this.images[url] = img;
-    img.onload = function() {
-      if (images.callback) {
-        images.callback(this);
-      }
-    };
-    img.src = url;
-  }
-
-  return img;
-};
-
-/**
- * Created by Alex on 2/6/14.
- */
-
-
-var physicsMixin = {
-
-  /**
-   * Toggling barnes Hut calculation on and off.
-   *
-   * @private
-   */
-  _toggleBarnesHut: function () {
-    this.constants.physics.barnesHut.enabled = !this.constants.physics.barnesHut.enabled;
-    this._loadSelectedForceSolver();
-    this.moving = true;
-    this.start();
-  },
-
-
-  /**
-   * This loads the node force solver based on the barnes hut or repulsion algorithm
-   *
-   * @private
-   */
-  _loadSelectedForceSolver: function () {
-    // this overloads the this._calculateNodeForces
-    if (this.constants.physics.barnesHut.enabled == true) {
-      this._clearMixin(repulsionMixin);
-      this._clearMixin(hierarchalRepulsionMixin);
-
-      this.constants.physics.centralGravity = this.constants.physics.barnesHut.centralGravity;
-      this.constants.physics.springLength = this.constants.physics.barnesHut.springLength;
-      this.constants.physics.springConstant = this.constants.physics.barnesHut.springConstant;
-      this.constants.physics.damping = this.constants.physics.barnesHut.damping;
-
-      this._loadMixin(barnesHutMixin);
-    }
-    else if (this.constants.physics.hierarchicalRepulsion.enabled == true) {
-      this._clearMixin(barnesHutMixin);
-      this._clearMixin(repulsionMixin);
-
-      this.constants.physics.centralGravity = this.constants.physics.hierarchicalRepulsion.centralGravity;
-      this.constants.physics.springLength = this.constants.physics.hierarchicalRepulsion.springLength;
-      this.constants.physics.springConstant = this.constants.physics.hierarchicalRepulsion.springConstant;
-      this.constants.physics.damping = this.constants.physics.hierarchicalRepulsion.damping;
-
-      this._loadMixin(hierarchalRepulsionMixin);
-    }
-    else {
-      this._clearMixin(barnesHutMixin);
-      this._clearMixin(hierarchalRepulsionMixin);
-      this.barnesHutTree = undefined;
-
-      this.constants.physics.centralGravity = this.constants.physics.repulsion.centralGravity;
-      this.constants.physics.springLength = this.constants.physics.repulsion.springLength;
-      this.constants.physics.springConstant = this.constants.physics.repulsion.springConstant;
-      this.constants.physics.damping = this.constants.physics.repulsion.damping;
-
-      this._loadMixin(repulsionMixin);
-    }
-  },
-
-  /**
-   * Before calculating the forces, we check if we need to cluster to keep up performance and we check
-   * if there is more than one node. If it is just one node, we dont calculate anything.
-   *
-   * @private
-   */
-  _initializeForceCalculation: function () {
-    // stop calculation if there is only one node
-    if (this.nodeIndices.length == 1) {
-      this.nodes[this.nodeIndices[0]]._setForce(0, 0);
-    }
-    else {
-      // if there are too many nodes on screen, we cluster without repositioning
-      if (this.nodeIndices.length > this.constants.clustering.clusterThreshold && this.constants.clustering.enabled == true) {
-        this.clusterToFit(this.constants.clustering.reduceToNodes, false);
-      }
-
-      // we now start the force calculation
-      this._calculateForces();
-    }
-  },
-
-
-  /**
-   * Calculate the external forces acting on the nodes
-   * Forces are caused by: edges, repulsing forces between nodes, gravity
-   * @private
-   */
-  _calculateForces: function () {
-    // Gravity is required to keep separated groups from floating off
-    // the forces are reset to zero in this loop by using _setForce instead
-    // of _addForce
-
-    this._calculateGravitationalForces();
-    this._calculateNodeForces();
-
-    if (this.constants.smoothCurves == true) {
-      this._calculateSpringForcesWithSupport();
-    }
-    else {
-      this._calculateSpringForces();
-    }
-  },
-
-
-  /**
-   * Smooth curves are created by adding invisible nodes in the center of the edges. These nodes are also
-   * handled in the calculateForces function. We then use a quadratic curve with the center node as control.
-   * This function joins the datanodes and invisible (called support) nodes into one object.
-   * We do this so we do not contaminate this.nodes with the support nodes.
-   *
-   * @private
-   */
-  _updateCalculationNodes: function () {
-    if (this.constants.smoothCurves == true) {
-      this.calculationNodes = {};
-      this.calculationNodeIndices = [];
-
-      for (var nodeId in this.nodes) {
-        if (this.nodes.hasOwnProperty(nodeId)) {
-          this.calculationNodes[nodeId] = this.nodes[nodeId];
-        }
-      }
-      var supportNodes = this.sectors['support']['nodes'];
-      for (var supportNodeId in supportNodes) {
-        if (supportNodes.hasOwnProperty(supportNodeId)) {
-          if (this.edges.hasOwnProperty(supportNodes[supportNodeId].parentEdgeId)) {
-            this.calculationNodes[supportNodeId] = supportNodes[supportNodeId];
-          }
-          else {
-            supportNodes[supportNodeId]._setForce(0, 0);
-          }
-        }
-      }
-
-      for (var idx in this.calculationNodes) {
-        if (this.calculationNodes.hasOwnProperty(idx)) {
-          this.calculationNodeIndices.push(idx);
-        }
-      }
-    }
-    else {
-      this.calculationNodes = this.nodes;
-      this.calculationNodeIndices = this.nodeIndices;
-    }
-  },
-
-
-  /**
-   * this function applies the central gravity effect to keep groups from floating off
-   *
-   * @private
-   */
-  _calculateGravitationalForces: function () {
-    var dx, dy, distance, node, i;
-    var nodes = this.calculationNodes;
-    var gravity = this.constants.physics.centralGravity;
-    var gravityForce = 0;
-
-    for (i = 0; i < this.calculationNodeIndices.length; i++) {
-      node = nodes[this.calculationNodeIndices[i]];
-      node.damping = this.constants.physics.damping; // possibly add function to alter damping properties of clusters.
-      // gravity does not apply when we are in a pocket sector
-      if (this._sector() == "default" && gravity != 0) {
-        dx = -node.x;
-        dy = -node.y;
-        distance = Math.sqrt(dx * dx + dy * dy);
-
-        gravityForce = (distance == 0) ? 0 : (gravity / distance);
-        node.fx = dx * gravityForce;
-        node.fy = dy * gravityForce;
-      }
-      else {
-        node.fx = 0;
-        node.fy = 0;
-      }
-    }
-  },
-
-
-  /**
-   * this function calculates the effects of the springs in the case of unsmooth curves.
-   *
-   * @private
-   */
-  _calculateSpringForces: function () {
-    var edgeLength, edge, edgeId;
-    var dx, dy, fx, fy, springForce, distance;
-    var edges = this.edges;
-
-    // forces caused by the edges, modelled as springs
-    for (edgeId in edges) {
-      if (edges.hasOwnProperty(edgeId)) {
-        edge = edges[edgeId];
-        if (edge.connected) {
-          // only calculate forces if nodes are in the same sector
-          if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
-            edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
-            // this implies that the edges between big clusters are longer
-            edgeLength += (edge.to.clusterSize + edge.from.clusterSize - 2) * this.constants.clustering.edgeGrowth;
-
-            dx = (edge.from.x - edge.to.x);
-            dy = (edge.from.y - edge.to.y);
-            distance = Math.sqrt(dx * dx + dy * dy);
-
-            if (distance == 0) {
-              distance = 0.01;
-            }
-
-            // the 1/distance is so the fx and fy can be calculated without sine or cosine.
-            springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance;
-
-            fx = dx * springForce;
-            fy = dy * springForce;
-
-            edge.from.fx += fx;
-            edge.from.fy += fy;
-            edge.to.fx -= fx;
-            edge.to.fy -= fy;
-          }
-        }
-      }
-    }
-  },
-
-
-  /**
-   * This function calculates the springforces on the nodes, accounting for the support nodes.
-   *
-   * @private
-   */
-  _calculateSpringForcesWithSupport: function () {
-    var edgeLength, edge, edgeId, combinedClusterSize;
-    var edges = this.edges;
-
-    // forces caused by the edges, modelled as springs
-    for (edgeId in edges) {
-      if (edges.hasOwnProperty(edgeId)) {
-        edge = edges[edgeId];
-        if (edge.connected) {
-          // only calculate forces if nodes are in the same sector
-          if (this.nodes.hasOwnProperty(edge.toId) && this.nodes.hasOwnProperty(edge.fromId)) {
-            if (edge.via != null) {
-              var node1 = edge.to;
-              var node2 = edge.via;
-              var node3 = edge.from;
-
-              edgeLength = edge.customLength ? edge.length : this.constants.physics.springLength;
-
-              combinedClusterSize = node1.clusterSize + node3.clusterSize - 2;
-
-              // this implies that the edges between big clusters are longer
-              edgeLength += combinedClusterSize * this.constants.clustering.edgeGrowth;
-              this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
-              this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
-            }
-          }
-        }
-      }
-    }
-  },
-
-
-  /**
-   * This is the code actually performing the calculation for the function above. It is split out to avoid repetition.
-   *
-   * @param node1
-   * @param node2
-   * @param edgeLength
-   * @private
-   */
-  _calculateSpringForce: function (node1, node2, edgeLength) {
-    var dx, dy, fx, fy, springForce, distance;
-
-    dx = (node1.x - node2.x);
-    dy = (node1.y - node2.y);
-    distance = Math.sqrt(dx * dx + dy * dy);
-
-    if (distance == 0) {
-      distance = 0.01;
-    }
-
-    // the 1/distance is so the fx and fy can be calculated without sine or cosine.
-    springForce = this.constants.physics.springConstant * (edgeLength - distance) / distance;
-
-    fx = dx * springForce;
-    fy = dy * springForce;
-
-    node1.fx += fx;
-    node1.fy += fy;
-    node2.fx -= fx;
-    node2.fy -= fy;
-  },
-
-
-  /**
-   * Load the HTML for the physics config and bind it
-   * @private
-   */
-  _loadPhysicsConfiguration: function () {
-    if (this.physicsConfiguration === undefined) {
-      this.backupConstants = {};
-      util.copyObject(this.constants, this.backupConstants);
-
-      var hierarchicalLayoutDirections = ["LR", "RL", "UD", "DU"];
-      this.physicsConfiguration = document.createElement('div');
-      this.physicsConfiguration.className = "PhysicsConfiguration";
-      this.physicsConfiguration.innerHTML = '' +
-        '<table><tr><td><b>Simulation Mode:</b></td></tr>' +
-        '<tr>' +
-        '<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod1" value="BH" checked="checked">Barnes Hut</td>' +
-        '<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod2" value="R">Repulsion</td>' +
-        '<td width="120px"><input type="radio" name="graph_physicsMethod" id="graph_physicsMethod3" value="H">Hierarchical</td>' +
-        '</tr>' +
-        '</table>' +
-        '<table id="graph_BH_table" style="display:none">' +
-        '<tr><td><b>Barnes Hut</b></td></tr>' +
-        '<tr>' +
-        '<td width="150px">gravitationalConstant</td><td>0</td><td><input type="range" min="0" max="20000" value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" step="25" style="width:300px" id="graph_BH_gc"></td><td  width="50px">-20000</td><td><input value="' + (-1 * this.constants.physics.barnesHut.gravitationalConstant) + '" id="graph_BH_gc_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3"  value="' + this.constants.physics.barnesHut.centralGravity + '" step="0.05"  style="width:300px" id="graph_BH_cg"></td><td>3</td><td><input value="' + this.constants.physics.barnesHut.centralGravity + '" id="graph_BH_cg_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="' + this.constants.physics.barnesHut.springLength + '" step="1" style="width:300px" id="graph_BH_sl"></td><td>500</td><td><input value="' + this.constants.physics.barnesHut.springLength + '" id="graph_BH_sl_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="' + this.constants.physics.barnesHut.springConstant + '" step="0.001" style="width:300px" id="graph_BH_sc"></td><td>0.5</td><td><input value="' + this.constants.physics.barnesHut.springConstant + '" id="graph_BH_sc_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="' + this.constants.physics.barnesHut.damping + '" step="0.005" style="width:300px" id="graph_BH_damp"></td><td>0.3</td><td><input value="' + this.constants.physics.barnesHut.damping + '" id="graph_BH_damp_value" style="width:60px"></td>' +
-        '</tr>' +
-        '</table>' +
-        '<table id="graph_R_table" style="display:none">' +
-        '<tr><td><b>Repulsion</b></td></tr>' +
-        '<tr>' +
-        '<td width="150px">nodeDistance</td><td>0</td><td><input type="range" min="0" max="300" value="' + this.constants.physics.repulsion.nodeDistance + '" step="1" style="width:300px" id="graph_R_nd"></td><td width="50px">300</td><td><input value="' + this.constants.physics.repulsion.nodeDistance + '" id="graph_R_nd_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3"  value="' + this.constants.physics.repulsion.centralGravity + '" step="0.05"  style="width:300px" id="graph_R_cg"></td><td>3</td><td><input value="' + this.constants.physics.repulsion.centralGravity + '" id="graph_R_cg_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="' + this.constants.physics.repulsion.springLength + '" step="1" style="width:300px" id="graph_R_sl"></td><td>500</td><td><input value="' + this.constants.physics.repulsion.springLength + '" id="graph_R_sl_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="' + this.constants.physics.repulsion.springConstant + '" step="0.001" style="width:300px" id="graph_R_sc"></td><td>0.5</td><td><input value="' + this.constants.physics.repulsion.springConstant + '" id="graph_R_sc_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="' + this.constants.physics.repulsion.damping + '" step="0.005" style="width:300px" id="graph_R_damp"></td><td>0.3</td><td><input value="' + this.constants.physics.repulsion.damping + '" id="graph_R_damp_value" style="width:60px"></td>' +
-        '</tr>' +
-        '</table>' +
-        '<table id="graph_H_table" style="display:none">' +
-        '<tr><td width="150"><b>Hierarchical</b></td></tr>' +
-        '<tr>' +
-        '<td width="150px">nodeDistance</td><td>0</td><td><input type="range" min="0" max="300" value="' + this.constants.physics.hierarchicalRepulsion.nodeDistance + '" step="1" style="width:300px" id="graph_H_nd"></td><td width="50px">300</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.nodeDistance + '" id="graph_H_nd_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">centralGravity</td><td>0</td><td><input type="range" min="0" max="3"  value="' + this.constants.physics.hierarchicalRepulsion.centralGravity + '" step="0.05"  style="width:300px" id="graph_H_cg"></td><td>3</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.centralGravity + '" id="graph_H_cg_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">springLength</td><td>0</td><td><input type="range" min="0" max="500" value="' + this.constants.physics.hierarchicalRepulsion.springLength + '" step="1" style="width:300px" id="graph_H_sl"></td><td>500</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.springLength + '" id="graph_H_sl_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">springConstant</td><td>0</td><td><input type="range" min="0" max="0.5" value="' + this.constants.physics.hierarchicalRepulsion.springConstant + '" step="0.001" style="width:300px" id="graph_H_sc"></td><td>0.5</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.springConstant + '" id="graph_H_sc_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">damping</td><td>0</td><td><input type="range" min="0" max="0.3" value="' + this.constants.physics.hierarchicalRepulsion.damping + '" step="0.005" style="width:300px" id="graph_H_damp"></td><td>0.3</td><td><input value="' + this.constants.physics.hierarchicalRepulsion.damping + '" id="graph_H_damp_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">direction</td><td>1</td><td><input type="range" min="0" max="3" value="' + hierarchicalLayoutDirections.indexOf(this.constants.hierarchicalLayout.direction) + '" step="1" style="width:300px" id="graph_H_direction"></td><td>4</td><td><input value="' + this.constants.hierarchicalLayout.direction + '" id="graph_H_direction_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">levelSeparation</td><td>1</td><td><input type="range" min="0" max="500" value="' + this.constants.hierarchicalLayout.levelSeparation + '" step="1" style="width:300px" id="graph_H_levsep"></td><td>500</td><td><input value="' + this.constants.hierarchicalLayout.levelSeparation + '" id="graph_H_levsep_value" style="width:60px"></td>' +
-        '</tr>' +
-        '<tr>' +
-        '<td width="150px">nodeSpacing</td><td>1</td><td><input type="range" min="0" max="500" value="' + this.constants.hierarchicalLayout.nodeSpacing + '" step="1" style="width:300px" id="graph_H_nspac"></td><td>500</td><td><input value="' + this.constants.hierarchicalLayout.nodeSpacing + '" id="graph_H_nspac_value" style="width:60px"></td>' +
-        '</tr>' +
-        '</table>' +
-        '<table><tr><td><b>Options:</b></td></tr>' +
-        '<tr>' +
-        '<td width="180px"><input type="button" id="graph_toggleSmooth" value="Toggle smoothCurves" style="width:150px"></td>' +
-        '<td width="180px"><input type="button" id="graph_repositionNodes" value="Reinitialize" style="width:150px"></td>' +
-        '<td width="180px"><input type="button" id="graph_generateOptions" value="Generate Options" style="width:150px"></td>' +
-        '</tr>' +
-        '</table>'
-      this.containerElement.parentElement.insertBefore(this.physicsConfiguration, this.containerElement);
-      this.optionsDiv = document.createElement("div");
-      this.optionsDiv.style.fontSize = "14px";
-      this.optionsDiv.style.fontFamily = "verdana";
-      this.containerElement.parentElement.insertBefore(this.optionsDiv, this.containerElement);
-
-      var rangeElement;
-      rangeElement = document.getElementById('graph_BH_gc');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_gc', -1, "physics_barnesHut_gravitationalConstant");
-      rangeElement = document.getElementById('graph_BH_cg');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_cg', 1, "physics_centralGravity");
-      rangeElement = document.getElementById('graph_BH_sc');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sc', 1, "physics_springConstant");
-      rangeElement = document.getElementById('graph_BH_sl');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_sl', 1, "physics_springLength");
-      rangeElement = document.getElementById('graph_BH_damp');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_BH_damp', 1, "physics_damping");
-
-      rangeElement = document.getElementById('graph_R_nd');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_nd', 1, "physics_repulsion_nodeDistance");
-      rangeElement = document.getElementById('graph_R_cg');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_cg', 1, "physics_centralGravity");
-      rangeElement = document.getElementById('graph_R_sc');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sc', 1, "physics_springConstant");
-      rangeElement = document.getElementById('graph_R_sl');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_sl', 1, "physics_springLength");
-      rangeElement = document.getElementById('graph_R_damp');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_R_damp', 1, "physics_damping");
-
-      rangeElement = document.getElementById('graph_H_nd');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nd', 1, "physics_hierarchicalRepulsion_nodeDistance");
-      rangeElement = document.getElementById('graph_H_cg');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_cg', 1, "physics_centralGravity");
-      rangeElement = document.getElementById('graph_H_sc');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sc', 1, "physics_springConstant");
-      rangeElement = document.getElementById('graph_H_sl');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_sl', 1, "physics_springLength");
-      rangeElement = document.getElementById('graph_H_damp');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_damp', 1, "physics_damping");
-      rangeElement = document.getElementById('graph_H_direction');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_direction', hierarchicalLayoutDirections, "hierarchicalLayout_direction");
-      rangeElement = document.getElementById('graph_H_levsep');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_levsep', 1, "hierarchicalLayout_levelSeparation");
-      rangeElement = document.getElementById('graph_H_nspac');
-      rangeElement.onchange = showValueOfRange.bind(this, 'graph_H_nspac', 1, "hierarchicalLayout_nodeSpacing");
-
-      var radioButton1 = document.getElementById("graph_physicsMethod1");
-      var radioButton2 = document.getElementById("graph_physicsMethod2");
-      var radioButton3 = document.getElementById("graph_physicsMethod3");
-      radioButton2.checked = true;
-      if (this.constants.physics.barnesHut.enabled) {
-        radioButton1.checked = true;
-      }
-      if (this.constants.hierarchicalLayout.enabled) {
-        radioButton3.checked = true;
-      }
-
-      var graph_toggleSmooth = document.getElementById("graph_toggleSmooth");
-      var graph_repositionNodes = document.getElementById("graph_repositionNodes");
-      var graph_generateOptions = document.getElementById("graph_generateOptions");
-
-      graph_toggleSmooth.onclick = graphToggleSmoothCurves.bind(this);
-      graph_repositionNodes.onclick = graphRepositionNodes.bind(this);
-      graph_generateOptions.onclick = graphGenerateOptions.bind(this);
-      if (this.constants.smoothCurves == true) {
-        graph_toggleSmooth.style.background = "#A4FF56";
-      }
-      else {
-        graph_toggleSmooth.style.background = "#FF8532";
-      }
-
-
-      switchConfigurations.apply(this);
-
-      radioButton1.onchange = switchConfigurations.bind(this);
-      radioButton2.onchange = switchConfigurations.bind(this);
-      radioButton3.onchange = switchConfigurations.bind(this);
-    }
-  },
-
-  /**
-   * This overwrites the this.constants.
-   *
-   * @param constantsVariableName
-   * @param value
-   * @private
-   */
-  _overWriteGraphConstants: function (constantsVariableName, value) {
-    var nameArray = constantsVariableName.split("_");
-    if (nameArray.length == 1) {
-      this.constants[nameArray[0]] = value;
-    }
-    else if (nameArray.length == 2) {
-      this.constants[nameArray[0]][nameArray[1]] = value;
-    }
-    else if (nameArray.length == 3) {
-      this.constants[nameArray[0]][nameArray[1]][nameArray[2]] = value;
-    }
-  }
-};
-
-/**
- * this function is bound to the toggle smooth curves button. That is also why it is not in the prototype.
- */
-function graphToggleSmoothCurves () {
-  this.constants.smoothCurves = !this.constants.smoothCurves;
-  var graph_toggleSmooth = document.getElementById("graph_toggleSmooth");
-  if (this.constants.smoothCurves == true) {graph_toggleSmooth.style.background = "#A4FF56";}
-  else                                     {graph_toggleSmooth.style.background = "#FF8532";}
-
-  this._configureSmoothCurves(false);
-};
-
-/**
- * this function is used to scramble the nodes
- *
- */
-function graphRepositionNodes () {
-  for (var nodeId in this.calculationNodes) {
-    if (this.calculationNodes.hasOwnProperty(nodeId)) {
-      this.calculationNodes[nodeId].vx = 0;  this.calculationNodes[nodeId].vy = 0;
-      this.calculationNodes[nodeId].fx = 0;  this.calculationNodes[nodeId].fy = 0;
-    }
-  }
-  if (this.constants.hierarchicalLayout.enabled == true) {
-    this._setupHierarchicalLayout();
-  }
-  else {
-    this.repositionNodes();
-  }
-  this.moving = true;
-  this.start();
-};
-
-/**
- *  this is used to generate an options file from the playing with physics system.
- */
-function graphGenerateOptions () {
-  var options = "No options are required, default values used.";
-  var optionsSpecific = [];
-  var radioButton1 = document.getElementById("graph_physicsMethod1");
-  var radioButton2 = document.getElementById("graph_physicsMethod2");
-  if (radioButton1.checked == true) {
-    if (this.constants.physics.barnesHut.gravitationalConstant != this.backupConstants.physics.barnesHut.gravitationalConstant) {optionsSpecific.push("gravitationalConstant: " + this.constants.physics.barnesHut.gravitationalConstant);}
-    if (this.constants.physics.centralGravity != this.backupConstants.physics.barnesHut.centralGravity)                         {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);}
-    if (this.constants.physics.springLength != this.backupConstants.physics.barnesHut.springLength)                             {optionsSpecific.push("springLength: " + this.constants.physics.springLength);}
-    if (this.constants.physics.springConstant != this.backupConstants.physics.barnesHut.springConstant)                         {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);}
-    if (this.constants.physics.damping != this.backupConstants.physics.barnesHut.damping)                                       {optionsSpecific.push("damping: " + this.constants.physics.damping);}
-    if (optionsSpecific.length != 0) {
-      options = "var options = {";
-      options += "physics: {barnesHut: {";
-      for (var i = 0; i < optionsSpecific.length; i++) {
-        options += optionsSpecific[i];
-        if (i < optionsSpecific.length - 1) {
-          options += ", "
-        }
-      }
-      options += '}}'
-    }
-    if (this.constants.smoothCurves != this.backupConstants.smoothCurves) {
-      if (optionsSpecific.length == 0) {options = "var options = {";}
-      else {options += ", "}
-      options += "smoothCurves: " + this.constants.smoothCurves;
-    }
-    if (options != "No options are required, default values used.") {
-      options += '};'
-    }
-  }
-  else if (radioButton2.checked == true) {
-    options = "var options = {";
-    options += "physics: {barnesHut: {enabled: false}";
-    if (this.constants.physics.repulsion.nodeDistance != this.backupConstants.physics.repulsion.nodeDistance)  {optionsSpecific.push("nodeDistance: " + this.constants.physics.repulsion.nodeDistance);}
-    if (this.constants.physics.centralGravity != this.backupConstants.physics.repulsion.centralGravity)        {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);}
-    if (this.constants.physics.springLength != this.backupConstants.physics.repulsion.springLength)            {optionsSpecific.push("springLength: " + this.constants.physics.springLength);}
-    if (this.constants.physics.springConstant != this.backupConstants.physics.repulsion.springConstant)        {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);}
-    if (this.constants.physics.damping != this.backupConstants.physics.repulsion.damping)                      {optionsSpecific.push("damping: " + this.constants.physics.damping);}
-    if (optionsSpecific.length != 0) {
-      options += ", repulsion: {";
-      for (var i = 0; i < optionsSpecific.length; i++) {
-        options += optionsSpecific[i];
-        if (i < optionsSpecific.length - 1) {
-          options += ", "
-        }
-      }
-      options += '}}'
-    }
-    if (optionsSpecific.length == 0) {options += "}"}
-    if (this.constants.smoothCurves != this.backupConstants.smoothCurves) {
-      options += ", smoothCurves: " + this.constants.smoothCurves;
-    }
-    options += '};'
-  }
-  else {
-    options = "var options = {";
-    if (this.constants.physics.hierarchicalRepulsion.nodeDistance != this.backupConstants.physics.hierarchicalRepulsion.nodeDistance)  {optionsSpecific.push("nodeDistance: " + this.constants.physics.hierarchicalRepulsion.nodeDistance);}
-    if (this.constants.physics.centralGravity != this.backupConstants.physics.hierarchicalRepulsion.centralGravity)        {optionsSpecific.push("centralGravity: " + this.constants.physics.centralGravity);}
-    if (this.constants.physics.springLength != this.backupConstants.physics.hierarchicalRepulsion.springLength)            {optionsSpecific.push("springLength: " + this.constants.physics.springLength);}
-    if (this.constants.physics.springConstant != this.backupConstants.physics.hierarchicalRepulsion.springConstant)        {optionsSpecific.push("springConstant: " + this.constants.physics.springConstant);}
-    if (this.constants.physics.damping != this.backupConstants.physics.hierarchicalRepulsion.damping)                      {optionsSpecific.push("damping: " + this.constants.physics.damping);}
-    if (optionsSpecific.length != 0) {
-      options += "physics: {hierarchicalRepulsion: {";
-      for (var i = 0; i < optionsSpecific.length; i++) {
-        options += optionsSpecific[i];
-        if (i < optionsSpecific.length - 1) {
-          options += ", ";
-        }
-      }
-      options += '}},';
-    }
-    options += 'hierarchicalLayout: {';
-    optionsSpecific = [];
-    if (this.constants.hierarchicalLayout.direction != this.backupConstants.hierarchicalLayout.direction)                       {optionsSpecific.push("direction: " + this.constants.hierarchicalLayout.direction);}
-    if (Math.abs(this.constants.hierarchicalLayout.levelSeparation) != this.backupConstants.hierarchicalLayout.levelSeparation) {optionsSpecific.push("levelSeparation: " + this.constants.hierarchicalLayout.levelSeparation);}
-    if (this.constants.hierarchicalLayout.nodeSpacing != this.backupConstants.hierarchicalLayout.nodeSpacing)                   {optionsSpecific.push("nodeSpacing: " + this.constants.hierarchicalLayout.nodeSpacing);}
-    if (optionsSpecific.length != 0) {
-      for (var i = 0; i < optionsSpecific.length; i++) {
-        options += optionsSpecific[i];
-        if (i < optionsSpecific.length - 1) {
-          options += ", "
-        }
-      }
-      options += '}'
-    }
-    else {
-      options += "enabled:true}";
-    }
-    options += '};'
-  }
-
-
-  this.optionsDiv.innerHTML = options;
-
-};
-
-/**
- * this is used to switch between barnesHut, repulsion and hierarchical.
- *
- */
-function switchConfigurations () {
-  var ids = ["graph_BH_table", "graph_R_table", "graph_H_table"];
-  var radioButton = document.querySelector('input[name="graph_physicsMethod"]:checked').value;
-  var tableId = "graph_" + radioButton + "_table";
-  var table = document.getElementById(tableId);
-  table.style.display = "block";
-  for (var i = 0; i < ids.length; i++) {
-    if (ids[i] != tableId) {
-      table = document.getElementById(ids[i]);
-      table.style.display = "none";
-    }
-  }
-  this._restoreNodes();
-  if (radioButton == "R") {
-    this.constants.hierarchicalLayout.enabled = false;
-    this.constants.physics.hierarchicalRepulsion.enabled = false;
-    this.constants.physics.barnesHut.enabled = false;
-  }
-  else if (radioButton == "H") {
-    if (this.constants.hierarchicalLayout.enabled == false) {
-      this.constants.hierarchicalLayout.enabled = true;
-      this.constants.physics.hierarchicalRepulsion.enabled = true;
-      this.constants.physics.barnesHut.enabled = false;
-      this._setupHierarchicalLayout();
-    }
-  }
-  else {
-    this.constants.hierarchicalLayout.enabled = false;
-    this.constants.physics.hierarchicalRepulsion.enabled = false;
-    this.constants.physics.barnesHut.enabled = true;
-  }
-  this._loadSelectedForceSolver();
-  var graph_toggleSmooth = document.getElementById("graph_toggleSmooth");
-  if (this.constants.smoothCurves == true) {graph_toggleSmooth.style.background = "#A4FF56";}
-  else                                     {graph_toggleSmooth.style.background = "#FF8532";}
-  this.moving = true;
-  this.start();
-
-}
-
-
-/**
- * this generates the ranges depending on the iniital values.
- *
- * @param id
- * @param map
- * @param constantsVariableName
- */
-function showValueOfRange (id,map,constantsVariableName) {
-  var valueId = id + "_value";
-  var rangeValue = document.getElementById(id).value;
-
-  if (map instanceof Array) {
-    document.getElementById(valueId).value = map[parseInt(rangeValue)];
-    this._overWriteGraphConstants(constantsVariableName,map[parseInt(rangeValue)]);
-  }
-  else {
-    document.getElementById(valueId).value = parseInt(map) * parseFloat(rangeValue);
-    this._overWriteGraphConstants(constantsVariableName, parseInt(map) * parseFloat(rangeValue));
-  }
-
-  if (constantsVariableName == "hierarchicalLayout_direction" ||
-    constantsVariableName == "hierarchicalLayout_levelSeparation" ||
-    constantsVariableName == "hierarchicalLayout_nodeSpacing") {
-    this._setupHierarchicalLayout();
-  }
-  this.moving = true;
-  this.start();
-};
-
-
-
-/**
- * Created by Alex on 2/10/14.
- */
-
-var hierarchalRepulsionMixin = {
-
-
-  /**
-   * Calculate the forces the nodes apply on eachother based on a repulsion field.
-   * This field is linearly approximated.
-   *
-   * @private
-   */
-  _calculateNodeForces: function () {
-    var dx, dy, distance, fx, fy, combinedClusterSize,
-      repulsingForce, node1, node2, i, j;
-
-    var nodes = this.calculationNodes;
-    var nodeIndices = this.calculationNodeIndices;
-
-    // approximation constants
-    var b = 5;
-    var a_base = 0.5 * -b;
-
-
-    // repulsing forces between nodes
-    var nodeDistance = this.constants.physics.hierarchicalRepulsion.nodeDistance;
-    var minimumDistance = nodeDistance;
-
-    // we loop from i over all but the last entree in the array
-    // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j
-    for (i = 0; i < nodeIndices.length - 1; i++) {
-
-      node1 = nodes[nodeIndices[i]];
-      for (j = i + 1; j < nodeIndices.length; j++) {
-        node2 = nodes[nodeIndices[j]];
-
-        dx = node2.x - node1.x;
-        dy = node2.y - node1.y;
-        distance = Math.sqrt(dx * dx + dy * dy);
-
-        var a = a_base / minimumDistance;
-        if (distance < 2 * minimumDistance) {
-          repulsingForce = a * distance + b; // linear approx of  1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness))
-
-          // normalize force with
-          if (distance == 0) {
-            distance = 0.01;
-          }
-          else {
-            repulsingForce = repulsingForce / distance;
-          }
-          fx = dx * repulsingForce;
-          fy = dy * repulsingForce;
-
-          node1.fx -= fx;
-          node1.fy -= fy;
-          node2.fx += fx;
-          node2.fy += fy;
-        }
-      }
-    }
-  }
-};
-/**
- * Created by Alex on 2/10/14.
- */
-
-var barnesHutMixin = {
-
-  /**
-   * This function calculates the forces the nodes apply on eachother based on a gravitational model.
-   * The Barnes Hut method is used to speed up this N-body simulation.
-   *
-   * @private
-   */
-  _calculateNodeForces : function() {
-    if (this.constants.physics.barnesHut.gravitationalConstant != 0) {
-      var node;
-      var nodes = this.calculationNodes;
-      var nodeIndices = this.calculationNodeIndices;
-      var nodeCount = nodeIndices.length;
-
-      this._formBarnesHutTree(nodes,nodeIndices);
-
-      var barnesHutTree = this.barnesHutTree;
-
-      // place the nodes one by one recursively
-      for (var i = 0; i < nodeCount; i++) {
-        node = nodes[nodeIndices[i]];
-        // starting with root is irrelevant, it never passes the BarnesHut condition
-        this._getForceContribution(barnesHutTree.root.children.NW,node);
-        this._getForceContribution(barnesHutTree.root.children.NE,node);
-        this._getForceContribution(barnesHutTree.root.children.SW,node);
-        this._getForceContribution(barnesHutTree.root.children.SE,node);
-      }
-    }
-  },
-
-
-  /**
-   * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
-   * If a region contains a single node, we check if it is not itself, then we apply the force.
-   *
-   * @param parentBranch
-   * @param node
-   * @private
-   */
-  _getForceContribution : function(parentBranch,node) {
-    // we get no force contribution from an empty region
-    if (parentBranch.childrenCount > 0) {
-      var dx,dy,distance;
-
-      // get the distance from the center of mass to the node.
-      dx = parentBranch.centerOfMass.x - node.x;
-      dy = parentBranch.centerOfMass.y - node.y;
-      distance = Math.sqrt(dx * dx + dy * dy);
-
-      // BarnesHut condition
-      // original condition : s/d < theta = passed  ===  d/s > 1/theta = passed
-      // calcSize = 1/s --> d * 1/s > 1/theta = passed
-      if (distance * parentBranch.calcSize > this.constants.physics.barnesHut.theta) {
-        // duplicate code to reduce function calls to speed up program
-        if (distance == 0) {
-          distance = 0.1*Math.random();
-          dx = distance;
-        }
-        var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
-        var fx = dx * gravityForce;
-        var fy = dy * gravityForce;
-        node.fx += fx;
-        node.fy += fy;
-      }
-      else {
-        // Did not pass the condition, go into children if available
-        if (parentBranch.childrenCount == 4) {
-          this._getForceContribution(parentBranch.children.NW,node);
-          this._getForceContribution(parentBranch.children.NE,node);
-          this._getForceContribution(parentBranch.children.SW,node);
-          this._getForceContribution(parentBranch.children.SE,node);
-        }
-        else { // parentBranch must have only one node, if it was empty we wouldnt be here
-          if (parentBranch.children.data.id != node.id) { // if it is not self
-            // duplicate code to reduce function calls to speed up program
-            if (distance == 0) {
-              distance = 0.5*Math.random();
-              dx = distance;
-            }
-            var gravityForce = this.constants.physics.barnesHut.gravitationalConstant * parentBranch.mass * node.mass / (distance * distance * distance);
-            var fx = dx * gravityForce;
-            var fy = dy * gravityForce;
-            node.fx += fx;
-            node.fy += fy;
-          }
-        }
-      }
-    }
-  },
-
-  /**
-   * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
-   *
-   * @param nodes
-   * @param nodeIndices
-   * @private
-   */
-  _formBarnesHutTree : function(nodes,nodeIndices) {
-    var node;
-    var nodeCount = nodeIndices.length;
-
-    var minX = Number.MAX_VALUE,
-      minY = Number.MAX_VALUE,
-      maxX =-Number.MAX_VALUE,
-      maxY =-Number.MAX_VALUE;
-
-    // get the range of the nodes
-    for (var i = 0; i < nodeCount; i++) {
-      var x = nodes[nodeIndices[i]].x;
-      var y = nodes[nodeIndices[i]].y;
-      if (x < minX) { minX = x; }
-      if (x > maxX) { maxX = x; }
-      if (y < minY) { minY = y; }
-      if (y > maxY) { maxY = y; }
-    }
-    // make the range a square
-    var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
-    if (sizeDiff > 0) {minY -= 0.5 * sizeDiff; maxY += 0.5 * sizeDiff;} // xSize > ySize
-    else              {minX += 0.5 * sizeDiff; maxX -= 0.5 * sizeDiff;} // xSize < ySize
-
-
-    var minimumTreeSize = 1e-5;
-    var rootSize = Math.max(minimumTreeSize,Math.abs(maxX - minX));
-    var halfRootSize = 0.5 * rootSize;
-    var centerX = 0.5 * (minX + maxX), centerY = 0.5 * (minY + maxY);
-
-    // construct the barnesHutTree
-    var barnesHutTree = {root:{
-      centerOfMass:{x:0,y:0}, // Center of Mass
-      mass:0,
-      range: {minX:centerX-halfRootSize,maxX:centerX+halfRootSize,
-              minY:centerY-halfRootSize,maxY:centerY+halfRootSize},
-
-      size: rootSize,
-      calcSize: 1 / rootSize,
-      children: {data:null},
-      maxWidth: 0,
-      level: 0,
-      childrenCount: 4
-    }};
-    this._splitBranch(barnesHutTree.root);
-
-    // place the nodes one by one recursively
-    for (i = 0; i < nodeCount; i++) {
-      node = nodes[nodeIndices[i]];
-      this._placeInTree(barnesHutTree.root,node);
-    }
-
-    // make global
-    this.barnesHutTree = barnesHutTree
-  },
-
-
-  /**
-   * this updates the mass of a branch. this is increased by adding a node.
-   *
-   * @param parentBranch
-   * @param node
-   * @private
-   */
-  _updateBranchMass : function(parentBranch, node) {
-    var totalMass = parentBranch.mass + node.mass;
-    var totalMassInv = 1/totalMass;
-
-    parentBranch.centerOfMass.x = parentBranch.centerOfMass.x * parentBranch.mass + node.x * node.mass;
-    parentBranch.centerOfMass.x *= totalMassInv;
-
-    parentBranch.centerOfMass.y = parentBranch.centerOfMass.y * parentBranch.mass + node.y * node.mass;
-    parentBranch.centerOfMass.y *= totalMassInv;
-
-    parentBranch.mass = totalMass;
-    var biggestSize = Math.max(Math.max(node.height,node.radius),node.width);
-    parentBranch.maxWidth = (parentBranch.maxWidth < biggestSize) ? biggestSize : parentBranch.maxWidth;
-
-  },
-
-
-  /**
-   * determine in which branch the node will be placed.
-   *
-   * @param parentBranch
-   * @param node
-   * @param skipMassUpdate
-   * @private
-   */
-  _placeInTree : function(parentBranch,node,skipMassUpdate) {
-    if (skipMassUpdate != true || skipMassUpdate === undefined) {
-      // update the mass of the branch.
-      this._updateBranchMass(parentBranch,node);
-    }
-
-    if (parentBranch.children.NW.range.maxX > node.x) { // in NW or SW
-      if (parentBranch.children.NW.range.maxY > node.y) { // in NW
-        this._placeInRegion(parentBranch,node,"NW");
-      }
-      else { // in SW
-        this._placeInRegion(parentBranch,node,"SW");
-      }
-    }
-    else { // in NE or SE
-      if (parentBranch.children.NW.range.maxY > node.y) { // in NE
-        this._placeInRegion(parentBranch,node,"NE");
-      }
-      else { // in SE
-        this._placeInRegion(parentBranch,node,"SE");
-      }
-    }
-  },
-
-
-  /**
-   * actually place the node in a region (or branch)
-   *
-   * @param parentBranch
-   * @param node
-   * @param region
-   * @private
-   */
-  _placeInRegion : function(parentBranch,node,region) {
-    switch (parentBranch.children[region].childrenCount) {
-      case 0: // place node here
-        parentBranch.children[region].children.data = node;
-        parentBranch.children[region].childrenCount = 1;
-        this._updateBranchMass(parentBranch.children[region],node);
-        break;
-      case 1: // convert into children
-        // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
-        // we move one node a pixel and we do not put it in the tree.
-        if (parentBranch.children[region].children.data.x == node.x &&
-            parentBranch.children[region].children.data.y == node.y) {
-          node.x += Math.random();
-          node.y += Math.random();
-        }
-        else {
-          this._splitBranch(parentBranch.children[region]);
-          this._placeInTree(parentBranch.children[region],node);
-        }
-        break;
-      case 4: // place in branch
-        this._placeInTree(parentBranch.children[region],node);
-        break;
-    }
-  },
-
-
-  /**
-   * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
-   * after the split is complete.
-   *
-   * @param parentBranch
-   * @private
-   */
-  _splitBranch : function(parentBranch) {
-    // if the branch is filled with a node, replace the node in the new subset.
-    var containedNode = null;
-    if (parentBranch.childrenCount == 1) {
-      containedNode = parentBranch.children.data;
-      parentBranch.mass = 0; parentBranch.centerOfMass.x = 0; parentBranch.centerOfMass.y = 0;
-    }
-    parentBranch.childrenCount = 4;
-    parentBranch.children.data = null;
-    this._insertRegion(parentBranch,"NW");
-    this._insertRegion(parentBranch,"NE");
-    this._insertRegion(parentBranch,"SW");
-    this._insertRegion(parentBranch,"SE");
-
-    if (containedNode != null) {
-      this._placeInTree(parentBranch,containedNode);
-    }
-  },
-
-
-  /**
-   * This function subdivides the region into four new segments.
-   * Specifically, this inserts a single new segment.
-   * It fills the children section of the parentBranch
-   *
-   * @param parentBranch
-   * @param region
-   * @param parentRange
-   * @private
-   */
-  _insertRegion : function(parentBranch, region) {
-    var minX,maxX,minY,maxY;
-    var childSize = 0.5 * parentBranch.size;
-    switch (region) {
-      case "NW":
-        minX = parentBranch.range.minX;
-        maxX = parentBranch.range.minX + childSize;
-        minY = parentBranch.range.minY;
-        maxY = parentBranch.range.minY + childSize;
-        break;
-      case "NE":
-        minX = parentBranch.range.minX + childSize;
-        maxX = parentBranch.range.maxX;
-        minY = parentBranch.range.minY;
-        maxY = parentBranch.range.minY + childSize;
-        break;
-      case "SW":
-        minX = parentBranch.range.minX;
-        maxX = parentBranch.range.minX + childSize;
-        minY = parentBranch.range.minY + childSize;
-        maxY = parentBranch.range.maxY;
-        break;
-      case "SE":
-        minX = parentBranch.range.minX + childSize;
-        maxX = parentBranch.range.maxX;
-        minY = parentBranch.range.minY + childSize;
-        maxY = parentBranch.range.maxY;
-        break;
-    }
-
-
-    parentBranch.children[region] = {
-      centerOfMass:{x:0,y:0},
-      mass:0,
-      range:{minX:minX,maxX:maxX,minY:minY,maxY:maxY},
-      size: 0.5 * parentBranch.size,
-      calcSize: 2 * parentBranch.calcSize,
-      children: {data:null},
-      maxWidth: 0,
-      level: parentBranch.level+1,
-      childrenCount: 0
-    };
-  },
-
-
-  /**
-   * This function is for debugging purposed, it draws the tree.
-   *
-   * @param ctx
-   * @param color
-   * @private
-   */
-  _drawTree : function(ctx,color) {
-    if (this.barnesHutTree !== undefined) {
-
-      ctx.lineWidth = 1;
-
-      this._drawBranch(this.barnesHutTree.root,ctx,color);
-    }
-  },
-
-
-  /**
-   * This function is for debugging purposes. It draws the branches recursively.
-   *
-   * @param branch
-   * @param ctx
-   * @param color
-   * @private
-   */
-  _drawBranch : function(branch,ctx,color) {
-    if (color === undefined) {
-      color = "#FF0000";
-    }
-
-    if (branch.childrenCount == 4) {
-      this._drawBranch(branch.children.NW,ctx);
-      this._drawBranch(branch.children.NE,ctx);
-      this._drawBranch(branch.children.SE,ctx);
-      this._drawBranch(branch.children.SW,ctx);
-    }
-    ctx.strokeStyle = color;
-    ctx.beginPath();
-    ctx.moveTo(branch.range.minX,branch.range.minY);
-    ctx.lineTo(branch.range.maxX,branch.range.minY);
-    ctx.stroke();
-
-    ctx.beginPath();
-    ctx.moveTo(branch.range.maxX,branch.range.minY);
-    ctx.lineTo(branch.range.maxX,branch.range.maxY);
-    ctx.stroke();
-
-    ctx.beginPath();
-    ctx.moveTo(branch.range.maxX,branch.range.maxY);
-    ctx.lineTo(branch.range.minX,branch.range.maxY);
-    ctx.stroke();
-
-    ctx.beginPath();
-    ctx.moveTo(branch.range.minX,branch.range.maxY);
-    ctx.lineTo(branch.range.minX,branch.range.minY);
-    ctx.stroke();
-
-    /*
-     if (branch.mass > 0) {
-     ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
-     ctx.stroke();
-     }
-     */
-  }
-
-};
-/**
- * Created by Alex on 2/10/14.
- */
-
-var repulsionMixin = {
-
-
-  /**
-   * Calculate the forces the nodes apply on eachother based on a repulsion field.
-   * This field is linearly approximated.
-   *
-   * @private
-   */
-  _calculateNodeForces: function () {
-    var dx, dy, angle, distance, fx, fy, combinedClusterSize,
-      repulsingForce, node1, node2, i, j;
-
-    var nodes = this.calculationNodes;
-    var nodeIndices = this.calculationNodeIndices;
-
-    // approximation constants
-    var a_base = -2 / 3;
-    var b = 4 / 3;
-
-    // repulsing forces between nodes
-    var nodeDistance = this.constants.physics.repulsion.nodeDistance;
-    var minimumDistance = nodeDistance;
-
-    // we loop from i over all but the last entree in the array
-    // j loops from i+1 to the last. This way we do not double count any of the indices, nor i == j
-    for (i = 0; i < nodeIndices.length - 1; i++) {
-      node1 = nodes[nodeIndices[i]];
-      for (j = i + 1; j < nodeIndices.length; j++) {
-        node2 = nodes[nodeIndices[j]];
-        combinedClusterSize = node1.clusterSize + node2.clusterSize - 2;
-
-        dx = node2.x - node1.x;
-        dy = node2.y - node1.y;
-        distance = Math.sqrt(dx * dx + dy * dy);
-
-        minimumDistance = (combinedClusterSize == 0) ? nodeDistance : (nodeDistance * (1 + combinedClusterSize * this.constants.clustering.distanceAmplification));
-        var a = a_base / minimumDistance;
-        if (distance < 2 * minimumDistance) {
-          if (distance < 0.5 * minimumDistance) {
-            repulsingForce = 1.0;
-          }
-          else {
-            repulsingForce = a * distance + b; // linear approx of  1 / (1 + Math.exp((distance / minimumDistance - 1) * steepness))
-          }
-
-          // amplify the repulsion for clusters.
-          repulsingForce *= (combinedClusterSize == 0) ? 1 : 1 + combinedClusterSize * this.constants.clustering.forceAmplification;
-          repulsingForce = repulsingForce / distance;
-
-          fx = dx * repulsingForce;
-          fy = dy * repulsingForce;
-
-          node1.fx -= fx;
-          node1.fy -= fy;
-          node2.fx += fx;
-          node2.fy += fy;
-        }
-      }
-    }
-  }
-};
-var HierarchicalLayoutMixin = {
-
-
-
-  _resetLevels : function() {
-    for (var nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        var node = this.nodes[nodeId];
-        if (node.preassignedLevel == false) {
-          node.level = -1;
-        }
-      }
-    }
-  },
-
-  /**
-   * This is the main function to layout the nodes in a hierarchical way.
-   * It checks if the node details are supplied correctly
-   *
-   * @private
-   */
-  _setupHierarchicalLayout : function() {
-    if (this.constants.hierarchicalLayout.enabled == true && this.nodeIndices.length > 0) {
-      if (this.constants.hierarchicalLayout.direction == "RL" || this.constants.hierarchicalLayout.direction == "DU") {
-        this.constants.hierarchicalLayout.levelSeparation *= -1;
-      }
-      else {
-        this.constants.hierarchicalLayout.levelSeparation = Math.abs(this.constants.hierarchicalLayout.levelSeparation);
-      }
-      // get the size of the largest hubs and check if the user has defined a level for a node.
-      var hubsize = 0;
-      var node, nodeId;
-      var definedLevel = false;
-      var undefinedLevel = false;
-
-      for (nodeId in this.nodes) {
-        if (this.nodes.hasOwnProperty(nodeId)) {
-          node = this.nodes[nodeId];
-          if (node.level != -1) {
-            definedLevel = true;
-          }
-          else {
-            undefinedLevel = true;
-          }
-          if (hubsize < node.edges.length) {
-            hubsize = node.edges.length;
-          }
-        }
-      }
-
-      // if the user defined some levels but not all, alert and run without hierarchical layout
-      if (undefinedLevel == true && definedLevel == true) {
-        alert("To use the hierarchical layout, nodes require either no predefined levels or levels have to be defined for all nodes.");
-        this.zoomExtent(true,this.constants.clustering.enabled);
-        if (!this.constants.clustering.enabled) {
-          this.start();
-        }
-      }
-      else {
-        // setup the system to use hierarchical method.
-        this._changeConstants();
-
-        // define levels if undefined by the users. Based on hubsize
-        if (undefinedLevel == true) {
-          this._determineLevels(hubsize);
-        }
-        // check the distribution of the nodes per level.
-        var distribution = this._getDistribution();
-
-        // place the nodes on the canvas. This also stablilizes the system.
-        this._placeNodesByHierarchy(distribution);
-
-        // start the simulation.
-        this.start();
-      }
-    }
-  },
-
-
-  /**
-   * This function places the nodes on the canvas based on the hierarchial distribution.
-   *
-   * @param {Object} distribution | obtained by the function this._getDistribution()
-   * @private
-   */
-  _placeNodesByHierarchy : function(distribution) {
-    var nodeId, node;
-
-    // start placing all the level 0 nodes first. Then recursively position their branches.
-    for (nodeId in distribution[0].nodes) {
-      if (distribution[0].nodes.hasOwnProperty(nodeId)) {
-        node = distribution[0].nodes[nodeId];
-        if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") {
-          if (node.xFixed) {
-            node.x = distribution[0].minPos;
-            node.xFixed = false;
-
-            distribution[0].minPos += distribution[0].nodeSpacing;
-          }
-        }
-        else {
-          if (node.yFixed) {
-            node.y = distribution[0].minPos;
-            node.yFixed = false;
-
-            distribution[0].minPos += distribution[0].nodeSpacing;
-          }
-        }
-        this._placeBranchNodes(node.edges,node.id,distribution,node.level);
-      }
-    }
-
-    // stabilize the system after positioning. This function calls zoomExtent.
-    this._stabilize();
-  },
-
-
-  /**
-   * This function get the distribution of levels based on hubsize
-   *
-   * @returns {Object}
-   * @private
-   */
-  _getDistribution : function() {
-    var distribution = {};
-    var nodeId, node, level;
-
-    // we fix Y because the hierarchy is vertical, we fix X so we do not give a node an x position for a second time.
-    // the fix of X is removed after the x value has been set.
-    for (nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        node = this.nodes[nodeId];
-        node.xFixed = true;
-        node.yFixed = true;
-        if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") {
-          node.y = this.constants.hierarchicalLayout.levelSeparation*node.level;
-        }
-        else {
-          node.x = this.constants.hierarchicalLayout.levelSeparation*node.level;
-        }
-        if (!distribution.hasOwnProperty(node.level)) {
-          distribution[node.level] = {amount: 0, nodes: {}, minPos:0, nodeSpacing:0};
-        }
-        distribution[node.level].amount += 1;
-        distribution[node.level].nodes[node.id] = node;
-      }
-    }
-
-    // determine the largest amount of nodes of all levels
-    var maxCount = 0;
-    for (level in distribution) {
-      if (distribution.hasOwnProperty(level)) {
-        if (maxCount < distribution[level].amount) {
-          maxCount = distribution[level].amount;
-        }
-      }
-    }
-
-    // set the initial position and spacing of each nodes accordingly
-    for (level in distribution) {
-      if (distribution.hasOwnProperty(level)) {
-        distribution[level].nodeSpacing = (maxCount + 1) * this.constants.hierarchicalLayout.nodeSpacing;
-        distribution[level].nodeSpacing /= (distribution[level].amount + 1);
-        distribution[level].minPos = distribution[level].nodeSpacing - (0.5 * (distribution[level].amount + 1) * distribution[level].nodeSpacing);
-      }
-    }
-
-    return distribution;
-  },
-
-
-  /**
-   * this function allocates nodes in levels based on the recursive branching from the largest hubs.
-   *
-   * @param hubsize
-   * @private
-   */
-  _determineLevels : function(hubsize) {
-    var nodeId, node;
-
-    // determine hubs
-    for (nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        node = this.nodes[nodeId];
-        if (node.edges.length == hubsize) {
-          node.level = 0;
-        }
-      }
-    }
-
-    // branch from hubs
-    for (nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        node = this.nodes[nodeId];
-        if (node.level == 0) {
-          this._setLevel(1,node.edges,node.id);
-        }
-      }
-    }
-  },
-
-
-  /**
-   * Since hierarchical layout does not support:
-   *    - smooth curves (based on the physics),
-   *    - clustering (based on dynamic node counts)
-   *
-   * We disable both features so there will be no problems.
-   *
-   * @private
-   */
-  _changeConstants : function() {
-    this.constants.clustering.enabled = false;
-    this.constants.physics.barnesHut.enabled = false;
-    this.constants.physics.hierarchicalRepulsion.enabled = true;
-    this._loadSelectedForceSolver();
-    this.constants.smoothCurves = false;
-    this._configureSmoothCurves();
-  },
-
-
-  /**
-   * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
-   * on a X position that ensures there will be no overlap.
-   *
-   * @param edges
-   * @param parentId
-   * @param distribution
-   * @param parentLevel
-   * @private
-   */
-  _placeBranchNodes : function(edges, parentId, distribution, parentLevel) {
-    for (var i = 0; i < edges.length; i++) {
-      var childNode = null;
-      if (edges[i].toId == parentId) {
-        childNode = edges[i].from;
-      }
-      else {
-        childNode = edges[i].to;
-      }
-
-      // if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here.
-      var nodeMoved = false;
-      if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") {
-        if (childNode.xFixed && childNode.level > parentLevel) {
-          childNode.xFixed = false;
-          childNode.x = distribution[childNode.level].minPos;
-          nodeMoved = true;
-        }
-      }
-      else {
-        if (childNode.yFixed && childNode.level > parentLevel) {
-          childNode.yFixed = false;
-          childNode.y = distribution[childNode.level].minPos;
-          nodeMoved = true;
-        }
-      }
-
-      if (nodeMoved == true) {
-        distribution[childNode.level].minPos += distribution[childNode.level].nodeSpacing;
-        if (childNode.edges.length > 1) {
-          this._placeBranchNodes(childNode.edges,childNode.id,distribution,childNode.level);
-        }
-      }
-    }
-  },
-
-
-  /**
-   * this function is called recursively to enumerate the barnches of the largest hubs and give each node a level.
-   *
-   * @param level
-   * @param edges
-   * @param parentId
-   * @private
-   */
-  _setLevel : function(level, edges, parentId) {
-    for (var i = 0; i < edges.length; i++) {
-      var childNode = null;
-      if (edges[i].toId == parentId) {
-        childNode = edges[i].from;
-      }
-      else {
-        childNode = edges[i].to;
-      }
-      if (childNode.level == -1 || childNode.level > level) {
-        childNode.level = level;
-        if (edges.length > 1) {
-          this._setLevel(level+1, childNode.edges, childNode.id);
-        }
-      }
-    }
-  },
-
-
-  /**
-   * Unfix nodes
-   *
-   * @private
-   */
-  _restoreNodes : function() {
-    for (nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        this.nodes[nodeId].xFixed = false;
-        this.nodes[nodeId].yFixed = false;
-      }
-    }
-  }
-
-
-};
-/**
- * Created by Alex on 2/4/14.
- */
-
-var manipulationMixin = {
-
-  /**
-   * clears the toolbar div element of children
-   *
-   * @private
-   */
-  _clearManipulatorBar : function() {
-    while (this.manipulationDiv.hasChildNodes()) {
-      this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);
-    }
-  },
-
-  /**
-   * Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore
-   * these functions to their original functionality, we saved them in this.cachedFunctions.
-   * This function restores these functions to their original function.
-   *
-   * @private
-   */
-  _restoreOverloadedFunctions : function() {
-    for (var functionName in this.cachedFunctions) {
-      if (this.cachedFunctions.hasOwnProperty(functionName)) {
-        this[functionName] = this.cachedFunctions[functionName];
-      }
-    }
-  },
-
-  /**
-   * Enable or disable edit-mode.
-   *
-   * @private
-   */
-  _toggleEditMode : function() {
-    this.editMode = !this.editMode;
-    var toolbar = document.getElementById("graph-manipulationDiv");
-    var closeDiv = document.getElementById("graph-manipulation-closeDiv");
-    var editModeDiv = document.getElementById("graph-manipulation-editMode");
-    if (this.editMode == true) {
-      toolbar.style.display="block";
-      closeDiv.style.display="block";
-      editModeDiv.style.display="none";
-      closeDiv.onclick = this._toggleEditMode.bind(this);
-    }
-    else {
-      toolbar.style.display="none";
-      closeDiv.style.display="none";
-      editModeDiv.style.display="block";
-      closeDiv.onclick = null;
-    }
-    this._createManipulatorBar()
-  },
-
-  /**
-   * main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
-   *
-   * @private
-   */
-  _createManipulatorBar : function() {
-    // remove bound functions
-    if (this.boundFunction) {
-      this.off('select', this.boundFunction);
-    }
-    if (this.edgeBeingEdited !== undefined) {
-      this.edgeBeingEdited._disableControlNodes();
-      this.edgeBeingEdited = undefined;
-      this.selectedControlNode = null;
-    }
-
-    // restore overloaded functions
-    this._restoreOverloadedFunctions();
-
-    // resume calculation
-    this.freezeSimulation = false;
-
-    // reset global variables
-    this.blockConnectingEdgeSelection = false;
-    this.forceAppendSelection = false;
-
-    if (this.editMode == true) {
-      while (this.manipulationDiv.hasChildNodes()) {
-        this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);
-      }
-      // add the icons to the manipulator div
-      this.manipulationDiv.innerHTML = "" +
-        "<span class='graph-manipulationUI add' id='graph-manipulate-addNode'>" +
-          "<span class='graph-manipulationLabel'>"+this.constants.labels['add'] +"</span></span>" +
-        "<div class='graph-seperatorLine'></div>" +
-        "<span class='graph-manipulationUI connect' id='graph-manipulate-connectNode'>" +
-          "<span class='graph-manipulationLabel'>"+this.constants.labels['link'] +"</span></span>";
-      if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) {
-        this.manipulationDiv.innerHTML += "" +
-          "<div class='graph-seperatorLine'></div>" +
-          "<span class='graph-manipulationUI edit' id='graph-manipulate-editNode'>" +
-            "<span class='graph-manipulationLabel'>"+this.constants.labels['editNode'] +"</span></span>";
-      }
-      else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) {
-        this.manipulationDiv.innerHTML += "" +
-          "<div class='graph-seperatorLine'></div>" +
-          "<span class='graph-manipulationUI edit' id='graph-manipulate-editEdge'>" +
-          "<span class='graph-manipulationLabel'>"+this.constants.labels['editEdge'] +"</span></span>";
-      }
-      if (this._selectionIsEmpty() == false) {
-        this.manipulationDiv.innerHTML += "" +
-          "<div class='graph-seperatorLine'></div>" +
-          "<span class='graph-manipulationUI delete' id='graph-manipulate-delete'>" +
-            "<span class='graph-manipulationLabel'>"+this.constants.labels['del'] +"</span></span>";
-      }
-
-
-      // bind the icons
-      var addNodeButton = document.getElementById("graph-manipulate-addNode");
-      addNodeButton.onclick = this._createAddNodeToolbar.bind(this);
-      var addEdgeButton = document.getElementById("graph-manipulate-connectNode");
-      addEdgeButton.onclick = this._createAddEdgeToolbar.bind(this);
-      if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) {
-        var editButton = document.getElementById("graph-manipulate-editNode");
-        editButton.onclick = this._editNode.bind(this);
-      }
-      else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) {
-        var editButton = document.getElementById("graph-manipulate-editEdge");
-        editButton.onclick = this._createEditEdgeToolbar.bind(this);
-      }
-      if (this._selectionIsEmpty() == false) {
-        var deleteButton = document.getElementById("graph-manipulate-delete");
-        deleteButton.onclick = this._deleteSelected.bind(this);
-      }
-      var closeDiv = document.getElementById("graph-manipulation-closeDiv");
-      closeDiv.onclick = this._toggleEditMode.bind(this);
-
-      this.boundFunction = this._createManipulatorBar.bind(this);
-      this.on('select', this.boundFunction);
-    }
-    else {
-      this.editModeDiv.innerHTML = "" +
-        "<span class='graph-manipulationUI edit editmode' id='graph-manipulate-editModeButton'>" +
-        "<span class='graph-manipulationLabel'>" + this.constants.labels['edit'] + "</span></span>";
-      var editModeButton = document.getElementById("graph-manipulate-editModeButton");
-      editModeButton.onclick = this._toggleEditMode.bind(this);
-    }
-  },
-
-
-
-  /**
-   * Create the toolbar for adding Nodes
-   *
-   * @private
-   */
-  _createAddNodeToolbar : function() {
-    // clear the toolbar
-    this._clearManipulatorBar();
-    if (this.boundFunction) {
-      this.off('select', this.boundFunction);
-    }
-
-    // create the toolbar contents
-    this.manipulationDiv.innerHTML = "" +
-      "<span class='graph-manipulationUI back' id='graph-manipulate-back'>" +
-      "<span class='graph-manipulationLabel'>" + this.constants.labels['back'] + " </span></span>" +
-      "<div class='graph-seperatorLine'></div>" +
-      "<span class='graph-manipulationUI none' id='graph-manipulate-back'>" +
-      "<span id='graph-manipulatorLabel' class='graph-manipulationLabel'>" + this.constants.labels['addDescription'] + "</span></span>";
-
-    // bind the icon
-    var backButton = document.getElementById("graph-manipulate-back");
-    backButton.onclick = this._createManipulatorBar.bind(this);
-
-    // we use the boundFunction so we can reference it when we unbind it from the "select" event.
-    this.boundFunction = this._addNode.bind(this);
-    this.on('select', this.boundFunction);
-  },
-
-
-  /**
-   * create the toolbar to connect nodes
-   *
-   * @private
-   */
-  _createAddEdgeToolbar : function() {
-    // clear the toolbar
-    this._clearManipulatorBar();
-    this._unselectAll(true);
-    this.freezeSimulation = true;
-
-    if (this.boundFunction) {
-      this.off('select', this.boundFunction);
-    }
-
-    this._unselectAll();
-    this.forceAppendSelection = false;
-    this.blockConnectingEdgeSelection = true;
-
-    this.manipulationDiv.innerHTML = "" +
-      "<span class='graph-manipulationUI back' id='graph-manipulate-back'>" +
-        "<span class='graph-manipulationLabel'>" + this.constants.labels['back'] + " </span></span>" +
-      "<div class='graph-seperatorLine'></div>" +
-      "<span class='graph-manipulationUI none' id='graph-manipulate-back'>" +
-        "<span id='graph-manipulatorLabel' class='graph-manipulationLabel'>" + this.constants.labels['linkDescription'] + "</span></span>";
-
-    // bind the icon
-    var backButton = document.getElementById("graph-manipulate-back");
-    backButton.onclick = this._createManipulatorBar.bind(this);
-
-    // we use the boundFunction so we can reference it when we unbind it from the "select" event.
-    this.boundFunction = this._handleConnect.bind(this);
-    this.on('select', this.boundFunction);
-
-    // temporarily overload functions
-    this.cachedFunctions["_handleTouch"] = this._handleTouch;
-    this.cachedFunctions["_handleOnRelease"] = this._handleOnRelease;
-    this._handleTouch = this._handleConnect;
-    this._handleOnRelease = this._finishConnect;
-
-    // redraw to show the unselect
-    this._redraw();
-  },
-
-  /**
-   * create the toolbar to edit edges
-   *
-   * @private
-   */
-  _createEditEdgeToolbar : function() {
-    // clear the toolbar
-    this._clearManipulatorBar();
-
-    if (this.boundFunction) {
-      this.off('select', this.boundFunction);
-    }
-
-    this.edgeBeingEdited = this._getSelectedEdge();
-    this.edgeBeingEdited._enableControlNodes();
-
-    this.manipulationDiv.innerHTML = "" +
-      "<span class='graph-manipulationUI back' id='graph-manipulate-back'>" +
-      "<span class='graph-manipulationLabel'>" + this.constants.labels['back'] + " </span></span>" +
-      "<div class='graph-seperatorLine'></div>" +
-      "<span class='graph-manipulationUI none' id='graph-manipulate-back'>" +
-      "<span id='graph-manipulatorLabel' class='graph-manipulationLabel'>" + this.constants.labels['editEdgeDescription'] + "</span></span>";
-
-    // bind the icon
-    var backButton = document.getElementById("graph-manipulate-back");
-    backButton.onclick = this._createManipulatorBar.bind(this);
-
-    // temporarily overload functions
-    this.cachedFunctions["_handleTouch"]      = this._handleTouch;
-    this.cachedFunctions["_handleOnRelease"]  = this._handleOnRelease;
-    this.cachedFunctions["_handleTap"]        = this._handleTap;
-    this.cachedFunctions["_handleDragStart"]  = this._handleDragStart;
-    this.cachedFunctions["_handleOnDrag"]     = this._handleOnDrag;
-    this._handleTouch     = this._selectControlNode;
-    this._handleTap       = function () {};
-    this._handleOnDrag    = this._controlNodeDrag;
-    this._handleDragStart = function () {}
-    this._handleOnRelease = this._releaseControlNode;
-
-    // redraw to show the unselect
-    this._redraw();
-  },
-
-
-
-
-
-  /**
-   * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
-   * to walk the user through the process.
-   *
-   * @private
-   */
-  _selectControlNode : function(pointer) {
-    this.edgeBeingEdited.controlNodes.from.unselect();
-    this.edgeBeingEdited.controlNodes.to.unselect();
-    this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y));
-    if (this.selectedControlNode !== null) {
-      this.selectedControlNode.select();
-      this.freezeSimulation = true;
-    }
-    this._redraw();
-  },
-
-  /**
-   * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
-   * to walk the user through the process.
-   *
-   * @private
-   */
-  _controlNodeDrag : function(event) {
-    var pointer = this._getPointer(event.gesture.center);
-    if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) {
-      this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x);
-      this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y);
-    }
-    this._redraw();
-  },
-
-  _releaseControlNode : function(pointer) {
-    var newNode = this._getNodeAt(pointer);
-    if (newNode != null) {
-      if (this.edgeBeingEdited.controlNodes.from.selected == true) {
-        this._editEdge(newNode.id, this.edgeBeingEdited.to.id);
-        this.edgeBeingEdited.controlNodes.from.unselect();
-      }
-      if (this.edgeBeingEdited.controlNodes.to.selected == true) {
-        this._editEdge(this.edgeBeingEdited.from.id, newNode.id);
-        this.edgeBeingEdited.controlNodes.to.unselect();
-      }
-    }
-    else {
-      this.edgeBeingEdited._restoreControlNodes();
-    }
-    this.freezeSimulation = false;
-    this._redraw();
-  },
-
-  /**
-   * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
-   * to walk the user through the process.
-   *
-   * @private
-   */
-  _handleConnect : function(pointer) {
-    if (this._getSelectedNodeCount() == 0) {
-      var node = this._getNodeAt(pointer);
-      if (node != null) {
-        if (node.clusterSize > 1) {
-          alert("Cannot create edges to a cluster.")
-        }
-        else {
-          this._selectObject(node,false);
-          // create a node the temporary line can look at
-          this.sectors['support']['nodes']['targetNode'] = new Node({id:'targetNode'},{},{},this.constants);
-          this.sectors['support']['nodes']['targetNode'].x = node.x;
-          this.sectors['support']['nodes']['targetNode'].y = node.y;
-          this.sectors['support']['nodes']['targetViaNode'] = new Node({id:'targetViaNode'},{},{},this.constants);
-          this.sectors['support']['nodes']['targetViaNode'].x = node.x;
-          this.sectors['support']['nodes']['targetViaNode'].y = node.y;
-          this.sectors['support']['nodes']['targetViaNode'].parentEdgeId = "connectionEdge";
-
-          // create a temporary edge
-          this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:this.sectors['support']['nodes']['targetNode'].id}, this, this.constants);
-          this.edges['connectionEdge'].from = node;
-          this.edges['connectionEdge'].connected = true;
-          this.edges['connectionEdge'].smooth = true;
-          this.edges['connectionEdge'].selected = true;
-          this.edges['connectionEdge'].to = this.sectors['support']['nodes']['targetNode'];
-          this.edges['connectionEdge'].via = this.sectors['support']['nodes']['targetViaNode'];
-
-          this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag;
-          this._handleOnDrag = function(event) {
-            var pointer = this._getPointer(event.gesture.center);
-            this.sectors['support']['nodes']['targetNode'].x = this._XconvertDOMtoCanvas(pointer.x);
-            this.sectors['support']['nodes']['targetNode'].y = this._YconvertDOMtoCanvas(pointer.y);
-            this.sectors['support']['nodes']['targetViaNode'].x = 0.5 * (this._XconvertDOMtoCanvas(pointer.x) + this.edges['connectionEdge'].from.x);
-            this.sectors['support']['nodes']['targetViaNode'].y = this._YconvertDOMtoCanvas(pointer.y);
-          };
-
-          this.moving = true;
-          this.start();
-        }
-      }
-    }
-  },
-
-  _finishConnect : function(pointer) {
-    if (this._getSelectedNodeCount() == 1) {
-
-      // restore the drag function
-      this._handleOnDrag = this.cachedFunctions["_handleOnDrag"];
-      delete this.cachedFunctions["_handleOnDrag"];
-
-      // remember the edge id
-      var connectFromId = this.edges['connectionEdge'].fromId;
-
-      // remove the temporary nodes and edge
-      delete this.edges['connectionEdge'];
-      delete this.sectors['support']['nodes']['targetNode'];
-      delete this.sectors['support']['nodes']['targetViaNode'];
-
-      var node = this._getNodeAt(pointer);
-      if (node != null) {
-        if (node.clusterSize > 1) {
-          alert("Cannot create edges to a cluster.")
-        }
-        else {
-          this._createEdge(connectFromId,node.id);
-          this._createManipulatorBar();
-        }
-      }
-      this._unselectAll();
-    }
-  },
-
-
-  /**
-   * Adds a node on the specified location
-   */
-  _addNode : function() {
-    if (this._selectionIsEmpty() && this.editMode == true) {
-      var positionObject = this._pointerToPositionObject(this.pointerPosition);
-      var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true};
-      if (this.triggerFunctions.add) {
-        if (this.triggerFunctions.add.length == 2) {
-          var me = this;
-          this.triggerFunctions.add(defaultData, function(finalizedData) {
-            me.nodesData.add(finalizedData);
-            me._createManipulatorBar();
-            me.moving = true;
-            me.start();
-          });
-        }
-        else {
-          alert(this.constants.labels['addError']);
-          this._createManipulatorBar();
-          this.moving = true;
-          this.start();
-        }
-      }
-      else {
-        this.nodesData.add(defaultData);
-        this._createManipulatorBar();
-        this.moving = true;
-        this.start();
-      }
-    }
-  },
-
-
-  /**
-   * connect two nodes with a new edge.
-   *
-   * @private
-   */
-  _createEdge : function(sourceNodeId,targetNodeId) {
-    if (this.editMode == true) {
-      var defaultData = {from:sourceNodeId, to:targetNodeId};
-      if (this.triggerFunctions.connect) {
-        if (this.triggerFunctions.connect.length == 2) {
-          var me = this;
-          this.triggerFunctions.connect(defaultData, function(finalizedData) {
-            me.edgesData.add(finalizedData);
-            me.moving = true;
-            me.start();
-          });
-        }
-        else {
-          alert(this.constants.labels["linkError"]);
-          this.moving = true;
-          this.start();
-        }
-      }
-      else {
-        this.edgesData.add(defaultData);
-        this.moving = true;
-        this.start();
-      }
-    }
-  },
-
-  /**
-   * connect two nodes with a new edge.
-   *
-   * @private
-   */
-  _editEdge : function(sourceNodeId,targetNodeId) {
-    if (this.editMode == true) {
-      var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId};
-      if (this.triggerFunctions.editEdge) {
-        if (this.triggerFunctions.editEdge.length == 2) {
-          var me = this;
-          this.triggerFunctions.editEdge(defaultData, function(finalizedData) {
-            me.edgesData.update(finalizedData);
-            me.moving = true;
-            me.start();
-          });
-        }
-        else {
-          alert(this.constants.labels["linkError"]);
-          this.moving = true;
-          this.start();
-        }
-      }
-      else {
-        this.edgesData.update(defaultData);
-        this.moving = true;
-        this.start();
-      }
-    }
-  },
-
-  /**
-   * Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color.
-   *
-   * @private
-   */
-  _editNode : function() {
-    if (this.triggerFunctions.edit && this.editMode == true) {
-      var node = this._getSelectedNode();
-      var data = {id:node.id,
-        label: node.label,
-        group: node.group,
-        shape: node.shape,
-        color: {
-          background:node.color.background,
-          border:node.color.border,
-          highlight: {
-            background:node.color.highlight.background,
-            border:node.color.highlight.border
-          }
-        }};
-      if (this.triggerFunctions.edit.length == 2) {
-        var me = this;
-        this.triggerFunctions.edit(data, function (finalizedData) {
-          me.nodesData.update(finalizedData);
-          me._createManipulatorBar();
-          me.moving = true;
-          me.start();
-        });
-      }
-      else {
-        alert(this.constants.labels["editError"]);
-      }
-    }
-    else {
-      alert(this.constants.labels["editBoundError"]);
-    }
-  },
-
-
-
-
-  /**
-   * delete everything in the selection
-   *
-   * @private
-   */
-  _deleteSelected : function() {
-    if (!this._selectionIsEmpty() && this.editMode == true) {
-      if (!this._clusterInSelection()) {
-        var selectedNodes = this.getSelectedNodes();
-        var selectedEdges = this.getSelectedEdges();
-        if (this.triggerFunctions.del) {
-          var me = this;
-          var data = {nodes: selectedNodes, edges: selectedEdges};
-          if (this.triggerFunctions.del.length = 2) {
-            this.triggerFunctions.del(data, function (finalizedData) {
-              me.edgesData.remove(finalizedData.edges);
-              me.nodesData.remove(finalizedData.nodes);
-              me._unselectAll();
-              me.moving = true;
-              me.start();
-            });
-          }
-          else {
-            alert(this.constants.labels["deleteError"])
-          }
-        }
-        else {
-          this.edgesData.remove(selectedEdges);
-          this.nodesData.remove(selectedNodes);
-          this._unselectAll();
-          this.moving = true;
-          this.start();
-        }
-      }
-      else {
-        alert(this.constants.labels["deleteClusterError"]);
-      }
-    }
-  }
-};
-/**
- * Creation of the SectorMixin var.
- *
- * This contains all the functions the Graph object can use to employ the sector system.
- * The sector system is always used by Graph, though the benefits only apply to the use of clustering.
- * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges.
- *
- * Alex de Mulder
- * 21-01-2013
- */
-var SectorMixin = {
-
-  /**
-   * This function is only called by the setData function of the Graph object.
-   * This loads the global references into the active sector. This initializes the sector.
-   *
-   * @private
-   */
-  _putDataInSector : function() {
-    this.sectors["active"][this._sector()].nodes = this.nodes;
-    this.sectors["active"][this._sector()].edges = this.edges;
-    this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices;
-  },
-
-
-  /**
-   *  /**
-   * This function sets the global references to nodes, edges and nodeIndices back to
-   * those of the supplied (active) sector. If a type is defined, do the specific type
-   *
-   * @param {String} sectorId
-   * @param {String} [sectorType] | "active" or "frozen"
-   * @private
-   */
-  _switchToSector : function(sectorId, sectorType) {
-    if (sectorType === undefined || sectorType == "active") {
-      this._switchToActiveSector(sectorId);
-    }
-    else {
-      this._switchToFrozenSector(sectorId);
-    }
-  },
-
-
-  /**
-   * This function sets the global references to nodes, edges and nodeIndices back to
-   * those of the supplied active sector.
-   *
-   * @param sectorId
-   * @private
-   */
-  _switchToActiveSector : function(sectorId) {
-    this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"];
-    this.nodes       = this.sectors["active"][sectorId]["nodes"];
-    this.edges       = this.sectors["active"][sectorId]["edges"];
-  },
-
-
-  /**
-   * This function sets the global references to nodes, edges and nodeIndices back to
-   * those of the supplied active sector.
-   *
-   * @param sectorId
-   * @private
-   */
-  _switchToSupportSector : function() {
-    this.nodeIndices = this.sectors["support"]["nodeIndices"];
-    this.nodes       = this.sectors["support"]["nodes"];
-    this.edges       = this.sectors["support"]["edges"];
-  },
-
-
-  /**
-   * This function sets the global references to nodes, edges and nodeIndices back to
-   * those of the supplied frozen sector.
-   *
-   * @param sectorId
-   * @private
-   */
-  _switchToFrozenSector : function(sectorId) {
-    this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"];
-    this.nodes       = this.sectors["frozen"][sectorId]["nodes"];
-    this.edges       = this.sectors["frozen"][sectorId]["edges"];
-  },
-
-
-  /**
-   * This function sets the global references to nodes, edges and nodeIndices back to
-   * those of the currently active sector.
-   *
-   * @private
-   */
-  _loadLatestSector : function() {
-    this._switchToSector(this._sector());
-  },
-
-
-  /**
-   * This function returns the currently active sector Id
-   *
-   * @returns {String}
-   * @private
-   */
-  _sector : function() {
-    return this.activeSector[this.activeSector.length-1];
-  },
-
-
-  /**
-   * This function returns the previously active sector Id
-   *
-   * @returns {String}
-   * @private
-   */
-  _previousSector : function() {
-    if (this.activeSector.length > 1) {
-      return this.activeSector[this.activeSector.length-2];
-    }
-    else {
-      throw new TypeError('there are not enough sectors in the this.activeSector array.');
-    }
-  },
-
-
-  /**
-   * We add the active sector at the end of the this.activeSector array
-   * This ensures it is the currently active sector returned by _sector() and it reaches the top
-   * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack.
-   *
-   * @param newId
-   * @private
-   */
-  _setActiveSector : function(newId) {
-    this.activeSector.push(newId);
-  },
-
-
-  /**
-   * We remove the currently active sector id from the active sector stack. This happens when
-   * we reactivate the previously active sector
-   *
-   * @private
-   */
-  _forgetLastSector : function() {
-    this.activeSector.pop();
-  },
-
-
-  /**
-   * This function creates a new active sector with the supplied newId. This newId
-   * is the expanding node id.
-   *
-   * @param {String} newId   | Id of the new active sector
-   * @private
-   */
-  _createNewSector : function(newId) {
-    // create the new sector
-    this.sectors["active"][newId] = {"nodes":{},
-                                     "edges":{},
-                                     "nodeIndices":[],
-                                     "formationScale": this.scale,
-                                     "drawingNode": undefined};
-
-    // create the new sector render node. This gives visual feedback that you are in a new sector.
-    this.sectors["active"][newId]['drawingNode'] = new Node(
-        {id:newId,
-          color: {
-            background: "#eaefef",
-            border: "495c5e"
-          }
-        },{},{},this.constants);
-    this.sectors["active"][newId]['drawingNode'].clusterSize = 2;
-  },
-
-
-  /**
-   * This function removes the currently active sector. This is called when we create a new
-   * active sector.
-   *
-   * @param {String} sectorId   | Id of the active sector that will be removed
-   * @private
-   */
-  _deleteActiveSector : function(sectorId) {
-    delete this.sectors["active"][sectorId];
-  },
-
-
-  /**
-   * This function removes the currently active sector. This is called when we reactivate
-   * the previously active sector.
-   *
-   * @param {String} sectorId   | Id of the active sector that will be removed
-   * @private
-   */
-  _deleteFrozenSector : function(sectorId) {
-    delete this.sectors["frozen"][sectorId];
-  },
-
-
-  /**
-   * Freezing an active sector means moving it from the "active" object to the "frozen" object.
-   * We copy the references, then delete the active entree.
-   *
-   * @param sectorId
-   * @private
-   */
-  _freezeSector : function(sectorId) {
-    // we move the set references from the active to the frozen stack.
-    this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId];
-
-    // we have moved the sector data into the frozen set, we now remove it from the active set
-    this._deleteActiveSector(sectorId);
-  },
-
-
-  /**
-   * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen"
-   * object to the "active" object.
-   *
-   * @param sectorId
-   * @private
-   */
-  _activateSector : function(sectorId) {
-    // we move the set references from the frozen to the active stack.
-    this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId];
-
-    // we have moved the sector data into the active set, we now remove it from the frozen stack
-    this._deleteFrozenSector(sectorId);
-  },
-
-
-  /**
-   * This function merges the data from the currently active sector with a frozen sector. This is used
-   * in the process of reverting back to the previously active sector.
-   * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it
-   * upon the creation of a new active sector.
-   *
-   * @param sectorId
-   * @private
-   */
-  _mergeThisWithFrozen : function(sectorId) {
-    // copy all nodes
-    for (var nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId];
-      }
-    }
-
-    // copy all edges (if not fully clustered, else there are no edges)
-    for (var edgeId in this.edges) {
-      if (this.edges.hasOwnProperty(edgeId)) {
-        this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId];
-      }
-    }
-
-    // merge the nodeIndices
-    for (var i = 0; i < this.nodeIndices.length; i++) {
-      this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]);
-    }
-  },
-
-
-  /**
-   * This clusters the sector to one cluster. It was a single cluster before this process started so
-   * we revert to that state. The clusterToFit function with a maximum size of 1 node does this.
-   *
-   * @private
-   */
-  _collapseThisToSingleCluster : function() {
-    this.clusterToFit(1,false);
-  },
-
-
-  /**
-   * We create a new active sector from the node that we want to open.
-   *
-   * @param node
-   * @private
-   */
-  _addSector : function(node) {
-    // this is the currently active sector
-    var sector = this._sector();
-
-//    // this should allow me to select nodes from a frozen set.
-//    if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) {
-//      console.log("the node is part of the active sector");
-//    }
-//    else {
-//      console.log("I dont know what happened!!");
-//    }
-
-    // when we switch to a new sector, we remove the node that will be expanded from the current nodes list.
-    delete this.nodes[node.id];
-
-    var unqiueIdentifier = util.randomUUID();
-
-    // we fully freeze the currently active sector
-    this._freezeSector(sector);
-
-    // we create a new active sector. This sector has the Id of the node to ensure uniqueness
-    this._createNewSector(unqiueIdentifier);
-
-    // we add the active sector to the sectors array to be able to revert these steps later on
-    this._setActiveSector(unqiueIdentifier);
-
-    // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier
-    this._switchToSector(this._sector());
-
-    // finally we add the node we removed from our previous active sector to the new active sector
-    this.nodes[node.id] = node;
-  },
-
-
-  /**
-   * We close the sector that is currently open and revert back to the one before.
-   * If the active sector is the "default" sector, nothing happens.
-   *
-   * @private
-   */
-  _collapseSector : function() {
-    // the currently active sector
-    var sector = this._sector();
-
-    // we cannot collapse the default sector
-    if (sector != "default") {
-      if ((this.nodeIndices.length == 1) ||
-       (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) ||
-       (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) {
-        var previousSector = this._previousSector();
-
-        // we collapse the sector back to a single cluster
-        this._collapseThisToSingleCluster();
-
-        // we move the remaining nodes, edges and nodeIndices to the previous sector.
-        // This previous sector is the one we will reactivate
-        this._mergeThisWithFrozen(previousSector);
-
-        // the previously active (frozen) sector now has all the data from the currently active sector.
-        // we can now delete the active sector.
-        this._deleteActiveSector(sector);
-
-        // we activate the previously active (and currently frozen) sector.
-        this._activateSector(previousSector);
-
-        // we load the references from the newly active sector into the global references
-        this._switchToSector(previousSector);
-
-        // we forget the previously active sector because we reverted to the one before
-        this._forgetLastSector();
-
-        // finally, we update the node index list.
-        this._updateNodeIndexList();
-
-        // we refresh the list with calulation nodes and calculation node indices.
-        this._updateCalculationNodes();
-      }
-    }
-  },
-
-
-  /**
-   * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation().
-   *
-   * @param {String} runFunction  |   This is the NAME of a function we want to call in all active sectors
-   *                              |   we dont pass the function itself because then the "this" is the window object
-   *                              |   instead of the Graph object
-   * @param {*} [argument]            |   Optional: arguments to pass to the runFunction
-   * @private
-   */
-  _doInAllActiveSectors : function(runFunction,argument) {
-    if (argument === undefined) {
-      for (var sector in this.sectors["active"]) {
-        if (this.sectors["active"].hasOwnProperty(sector)) {
-          // switch the global references to those of this sector
-          this._switchToActiveSector(sector);
-          this[runFunction]();
-        }
-      }
-    }
-    else {
-      for (var sector in this.sectors["active"]) {
-        if (this.sectors["active"].hasOwnProperty(sector)) {
-          // switch the global references to those of this sector
-          this._switchToActiveSector(sector);
-          var args = Array.prototype.splice.call(arguments, 1);
-          if (args.length > 1) {
-            this[runFunction](args[0],args[1]);
-          }
-          else {
-            this[runFunction](argument);
-          }
-        }
-      }
-    }
-    // we revert the global references back to our active sector
-    this._loadLatestSector();
-  },
-
-
-  /**
-   * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation().
-   *
-   * @param {String} runFunction  |   This is the NAME of a function we want to call in all active sectors
-   *                              |   we dont pass the function itself because then the "this" is the window object
-   *                              |   instead of the Graph object
-   * @param {*} [argument]        |   Optional: arguments to pass to the runFunction
-   * @private
-   */
-  _doInSupportSector : function(runFunction,argument) {
-    if (argument === undefined) {
-      this._switchToSupportSector();
-      this[runFunction]();
-    }
-    else {
-      this._switchToSupportSector();
-      var args = Array.prototype.splice.call(arguments, 1);
-      if (args.length > 1) {
-        this[runFunction](args[0],args[1]);
-      }
-      else {
-        this[runFunction](argument);
-      }
-    }
-    // we revert the global references back to our active sector
-    this._loadLatestSector();
-  },
-
-
-  /**
-   * This runs a function in all frozen sectors. This is used in the _redraw().
-   *
-   * @param {String} runFunction  |   This is the NAME of a function we want to call in all active sectors
-   *                              |   we don't pass the function itself because then the "this" is the window object
-   *                              |   instead of the Graph object
-   * @param {*} [argument]            |   Optional: arguments to pass to the runFunction
-   * @private
-   */
-  _doInAllFrozenSectors : function(runFunction,argument) {
-    if (argument === undefined) {
-      for (var sector in this.sectors["frozen"]) {
-        if (this.sectors["frozen"].hasOwnProperty(sector)) {
-          // switch the global references to those of this sector
-          this._switchToFrozenSector(sector);
-          this[runFunction]();
-        }
-      }
-    }
-    else {
-      for (var sector in this.sectors["frozen"]) {
-        if (this.sectors["frozen"].hasOwnProperty(sector)) {
-          // switch the global references to those of this sector
-          this._switchToFrozenSector(sector);
-          var args = Array.prototype.splice.call(arguments, 1);
-          if (args.length > 1) {
-            this[runFunction](args[0],args[1]);
-          }
-          else {
-            this[runFunction](argument);
-          }
-        }
-      }
-    }
-    this._loadLatestSector();
-  },
-
-
-  /**
-   * This runs a function in all sectors. This is used in the _redraw().
-   *
-   * @param {String} runFunction  |   This is the NAME of a function we want to call in all active sectors
-   *                              |   we don't pass the function itself because then the "this" is the window object
-   *                              |   instead of the Graph object
-   * @param {*} [argument]        |   Optional: arguments to pass to the runFunction
-   * @private
-   */
-  _doInAllSectors : function(runFunction,argument) {
-    var args = Array.prototype.splice.call(arguments, 1);
-    if (argument === undefined) {
-      this._doInAllActiveSectors(runFunction);
-      this._doInAllFrozenSectors(runFunction);
-    }
-    else {
-      if (args.length > 1) {
-        this._doInAllActiveSectors(runFunction,args[0],args[1]);
-        this._doInAllFrozenSectors(runFunction,args[0],args[1]);
-      }
-      else {
-        this._doInAllActiveSectors(runFunction,argument);
-        this._doInAllFrozenSectors(runFunction,argument);
-      }
-    }
-  },
-
-
-  /**
-   * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the
-   * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it.
-   *
-   * @private
-   */
-  _clearNodeIndexList : function() {
-    var sector = this._sector();
-    this.sectors["active"][sector]["nodeIndices"] = [];
-    this.nodeIndices = this.sectors["active"][sector]["nodeIndices"];
-  },
-
-
-  /**
-   * Draw the encompassing sector node
-   *
-   * @param ctx
-   * @param sectorType
-   * @private
-   */
-  _drawSectorNodes : function(ctx,sectorType) {
-    var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node;
-    for (var sector in this.sectors[sectorType]) {
-      if (this.sectors[sectorType].hasOwnProperty(sector)) {
-        if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) {
-
-          this._switchToSector(sector,sectorType);
-
-          minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9;
-          for (var nodeId in this.nodes) {
-            if (this.nodes.hasOwnProperty(nodeId)) {
-              node = this.nodes[nodeId];
-              node.resize(ctx);
-              if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;}
-              if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;}
-              if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;}
-              if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;}
-            }
-          }
-          node = this.sectors[sectorType][sector]["drawingNode"];
-          node.x = 0.5 * (maxX + minX);
-          node.y = 0.5 * (maxY + minY);
-          node.width = 2 * (node.x - minX);
-          node.height = 2 * (node.y - minY);
-          node.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2));
-          node.setScale(this.scale);
-          node._drawCircle(ctx);
-        }
-      }
-    }
-  },
-
-  _drawAllSectorNodes : function(ctx) {
-    this._drawSectorNodes(ctx,"frozen");
-    this._drawSectorNodes(ctx,"active");
-    this._loadLatestSector();
-  }
-};
-
-/**
- * Creation of the ClusterMixin var.
- *
- * This contains all the functions the Graph object can use to employ clustering
- *
- * Alex de Mulder
- * 21-01-2013
- */
-var ClusterMixin = {
-
- /**
-  * This is only called in the constructor of the graph object
-  *
-  */
- startWithClustering : function() {
-   // cluster if the data set is big
-   this.clusterToFit(this.constants.clustering.initialMaxNodes, true);
-
-   // updates the lables after clustering
-   this.updateLabels();
-
-   // this is called here because if clusterin is disabled, the start and stabilize are called in
-   // the setData function.
-   if (this.stabilize) {
-     this._stabilize();
-   }
-   this.start();
- },
-
-  /**
-   * This function clusters until the initialMaxNodes has been reached
-   *
-   * @param {Number}  maxNumberOfNodes
-   * @param {Boolean} reposition
-   */
-  clusterToFit : function(maxNumberOfNodes, reposition) {
-    var numberOfNodes = this.nodeIndices.length;
-
-    var maxLevels = 50;
-    var level = 0;
-
-    // we first cluster the hubs, then we pull in the outliers, repeat
-    while (numberOfNodes > maxNumberOfNodes && level < maxLevels) {
-      if (level % 3 == 0) {
-        this.forceAggregateHubs(true);
-        this.normalizeClusterLevels();
-      }
-      else {
-        this.increaseClusterLevel(); // this also includes a cluster normalization
-      }
-
-      numberOfNodes = this.nodeIndices.length;
-      level += 1;
-    }
-
-    // after the clustering we reposition the nodes to reduce the initial chaos
-    if (level > 0 && reposition == true) {
-      this.repositionNodes();
-    }
-    this._updateCalculationNodes();
-  },
-
-  /**
-   * This function can be called to open up a specific cluster. It is only called by
-   * It will unpack the cluster back one level.
-   *
-   * @param node    | Node object: cluster to open.
-   */
-  openCluster : function(node) {
-    var isMovingBeforeClustering = this.moving;
-    if (node.clusterSize > this.constants.clustering.sectorThreshold && this._nodeInActiveArea(node) &&
-      !(this._sector() == "default" && this.nodeIndices.length == 1)) {
-      // this loads a new sector, loads the nodes and edges and nodeIndices of it.
-      this._addSector(node);
-      var level = 0;
-
-      // we decluster until we reach a decent number of nodes
-      while ((this.nodeIndices.length < this.constants.clustering.initialMaxNodes) && (level < 10)) {
-        this.decreaseClusterLevel();
-        level += 1;
-      }
-
-    }
-    else {
-      this._expandClusterNode(node,false,true);
-
-      // update the index list, dynamic edges and labels
-      this._updateNodeIndexList();
-      this._updateDynamicEdges();
-      this._updateCalculationNodes();
-      this.updateLabels();
-    }
-
-    // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded
-    if (this.moving != isMovingBeforeClustering) {
-      this.start();
-    }
-  },
-
-
-  /**
-   * This calls the updateClustes with default arguments
-   */
-  updateClustersDefault : function() {
-    if (this.constants.clustering.enabled == true) {
-      this.updateClusters(0,false,false);
-    }
-  },
-
-
-  /**
-   * This function can be called to increase the cluster level. This means that the nodes with only one edge connection will
-   * be clustered with their connected node. This can be repeated as many times as needed.
-   * This can be called externally (by a keybind for instance) to reduce the complexity of big datasets.
-   */
-  increaseClusterLevel : function() {
-    this.updateClusters(-1,false,true);
-  },
-
-
-  /**
-   * This function can be called to decrease the cluster level. This means that the nodes with only one edge connection will
-   * be unpacked if they are a cluster. This can be repeated as many times as needed.
-   * This can be called externally (by a key-bind for instance) to look into clusters without zooming.
-   */
-  decreaseClusterLevel : function() {
-    this.updateClusters(1,false,true);
-  },
-
-
-  /**
-   * This is the main clustering function. It clusters and declusters on zoom or forced
-   * This function clusters on zoom, it can be called with a predefined zoom direction
-   * If out, check if we can form clusters, if in, check if we can open clusters.
-   * This function is only called from _zoom()
-   *
-   * @param {Number} zoomDirection  | -1 / 0 / +1   for  zoomOut / determineByZoom / zoomIn
-   * @param {Boolean} recursive     | enabled or disable recursive calling of the opening of clusters
-   * @param {Boolean} force         | enabled or disable forcing
-   * @param {Boolean} doNotStart    | if true do not call start
-   *
-   */
-  updateClusters : function(zoomDirection,recursive,force,doNotStart) {
-    var isMovingBeforeClustering = this.moving;
-    var amountOfNodes = this.nodeIndices.length;
-
-    // on zoom out collapse the sector if the scale is at the level the sector was made
-    if (this.previousScale > this.scale && zoomDirection == 0) {
-      this._collapseSector();
-    }
-
-    // check if we zoom in or out
-    if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out
-      // forming clusters when forced pulls outliers in. When not forced, the edge length of the
-      // outer nodes determines if it is being clustered
-      this._formClusters(force);
-    }
-    else if (this.previousScale < this.scale || zoomDirection == 1) { // zoom in
-      if (force == true) {
-        // _openClusters checks for each node if the formationScale of the cluster is smaller than
-        // the current scale and if so, declusters. When forced, all clusters are reduced by one step
-        this._openClusters(recursive,force);
-      }
-      else {
-        // if a cluster takes up a set percentage of the active window
-        this._openClustersBySize();
-      }
-    }
-    this._updateNodeIndexList();
-
-    // if a cluster was NOT formed and the user zoomed out, we try clustering by hubs
-    if (this.nodeIndices.length == amountOfNodes && (this.previousScale > this.scale || zoomDirection == -1))  {
-      this._aggregateHubs(force);
-      this._updateNodeIndexList();
-    }
-
-    // we now reduce chains.
-    if (this.previousScale > this.scale || zoomDirection == -1) { // zoom out
-      this.handleChains();
-      this._updateNodeIndexList();
-    }
-
-    this.previousScale = this.scale;
-
-    // rest of the update the index list, dynamic edges and labels
-    this._updateDynamicEdges();
-    this.updateLabels();
-
-    // if a cluster was formed, we increase the clusterSession
-    if (this.nodeIndices.length < amountOfNodes) { // this means a clustering operation has taken place
-      this.clusterSession += 1;
-      // if clusters have been made, we normalize the cluster level
-      this.normalizeClusterLevels();
-    }
-
-    if (doNotStart == false || doNotStart === undefined) {
-      // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded
-      if (this.moving != isMovingBeforeClustering) {
-        this.start();
-      }
-    }
-
-    this._updateCalculationNodes();
-  },
-
-  /**
-   * This function handles the chains. It is called on every updateClusters().
-   */
-  handleChains : function() {
-    // after clustering we check how many chains there are
-    var chainPercentage = this._getChainFraction();
-    if (chainPercentage > this.constants.clustering.chainThreshold) {
-      this._reduceAmountOfChains(1 - this.constants.clustering.chainThreshold / chainPercentage)
-
-    }
-  },
-
-  /**
-   * this functions starts clustering by hubs
-   * The minimum hub threshold is set globally
-   *
-   * @private
-   */
-  _aggregateHubs : function(force) {
-    this._getHubSize();
-    this._formClustersByHub(force,false);
-  },
-
-
-  /**
-   * This function is fired by keypress. It forces hubs to form.
-   *
-   */
-  forceAggregateHubs : function(doNotStart) {
-    var isMovingBeforeClustering = this.moving;
-    var amountOfNodes = this.nodeIndices.length;
-
-    this._aggregateHubs(true);
-
-    // update the index list, dynamic edges and labels
-    this._updateNodeIndexList();
-    this._updateDynamicEdges();
-    this.updateLabels();
-
-    // if a cluster was formed, we increase the clusterSession
-    if (this.nodeIndices.length != amountOfNodes) {
-      this.clusterSession += 1;
-    }
-
-    if (doNotStart == false || doNotStart === undefined) {
-      // if the simulation was settled, we restart the simulation if a cluster has been formed or expanded
-      if (this.moving != isMovingBeforeClustering) {
-        this.start();
-      }
-    }
-  },
-
-  /**
-   * If a cluster takes up more than a set percentage of the screen, open the cluster
-   *
-   * @private
-   */
-  _openClustersBySize : function() {
-    for (var nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        var node = this.nodes[nodeId];
-        if (node.inView() == true) {
-          if ((node.width*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) ||
-              (node.height*this.scale > this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) {
-            this.openCluster(node);
-          }
-        }
-      }
-    }
-  },
-
-
-  /**
-   * This function loops over all nodes in the nodeIndices list. For each node it checks if it is a cluster and if it
-   * has to be opened based on the current zoom level.
-   *
-   * @private
-   */
-  _openClusters : function(recursive,force) {
-    for (var i = 0; i < this.nodeIndices.length; i++) {
-      var node = this.nodes[this.nodeIndices[i]];
-      this._expandClusterNode(node,recursive,force);
-      this._updateCalculationNodes();
-    }
-  },
-
-  /**
-   * This function checks if a node has to be opened. This is done by checking the zoom level.
-   * If the node contains child nodes, this function is recursively called on the child nodes as well.
-   * This recursive behaviour is optional and can be set by the recursive argument.
-   *
-   * @param {Node}    parentNode    | to check for cluster and expand
-   * @param {Boolean} recursive     | enabled or disable recursive calling
-   * @param {Boolean} force         | enabled or disable forcing
-   * @param {Boolean} [openAll]     | This will recursively force all nodes in the parent to be released
-   * @private
-   */
-  _expandClusterNode : function(parentNode, recursive, force, openAll) {
-    // first check if node is a cluster
-    if (parentNode.clusterSize > 1) {
-      // this means that on a double tap event or a zoom event, the cluster fully unpacks if it is smaller than 20
-      if (parentNode.clusterSize < this.constants.clustering.sectorThreshold) {
-        openAll = true;
-      }
-      recursive = openAll ? true : recursive;
-
-      // if the last child has been added on a smaller scale than current scale decluster
-      if (parentNode.formationScale < this.scale || force == true) {
-        // we will check if any of the contained child nodes should be removed from the cluster
-        for (var containedNodeId in parentNode.containedNodes) {
-          if (parentNode.containedNodes.hasOwnProperty(containedNodeId)) {
-            var childNode = parentNode.containedNodes[containedNodeId];
-
-            // force expand will expand the largest cluster size clusters. Since we cluster from outside in, we assume that
-            // the largest cluster is the one that comes from outside
-            if (force == true) {
-              if (childNode.clusterSession == parentNode.clusterSessions[parentNode.clusterSessions.length-1]
-                  || openAll) {
-                this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll);
-              }
-            }
-            else {
-              if (this._nodeInActiveArea(parentNode)) {
-                this._expelChildFromParent(parentNode,containedNodeId,recursive,force,openAll);
-              }
-            }
-          }
-        }
-      }
-    }
-  },
-
-  /**
-   * ONLY CALLED FROM _expandClusterNode
-   *
-   * This function will expel a child_node from a parent_node. This is to de-cluster the node. This function will remove
-   * the child node from the parent contained_node object and put it back into the global nodes object.
-   * The same holds for the edge that was connected to the child node. It is moved back into the global edges object.
-   *
-   * @param {Node}    parentNode        | the parent node
-   * @param {String}  containedNodeId   | child_node id as it is contained in the containedNodes object of the parent node
-   * @param {Boolean} recursive         | This will also check if the child needs to be expanded.
-   *                                      With force and recursive both true, the entire cluster is unpacked
-   * @param {Boolean} force             | This will disregard the zoom level and will expel this child from the parent
-   * @param {Boolean} openAll           | This will recursively force all nodes in the parent to be released
-   * @private
-   */
-   _expelChildFromParent : function(parentNode, containedNodeId, recursive, force, openAll) {
-    var childNode = parentNode.containedNodes[containedNodeId];
-
-    // if child node has been added on smaller scale than current, kick out
-    if (childNode.formationScale < this.scale || force == true) {
-      // unselect all selected items
-      this._unselectAll();
-
-      // put the child node back in the global nodes object
-      this.nodes[containedNodeId] = childNode;
-
-      // release the contained edges from this childNode back into the global edges
-      this._releaseContainedEdges(parentNode,childNode);
-
-      // reconnect rerouted edges to the childNode
-      this._connectEdgeBackToChild(parentNode,childNode);
-
-      // validate all edges in dynamicEdges
-      this._validateEdges(parentNode);
-
-      // undo the changes from the clustering operation on the parent node
-      parentNode.mass -= childNode.mass;
-      parentNode.clusterSize -= childNode.clusterSize;
-      parentNode.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize);
-      parentNode.dynamicEdgesLength = parentNode.dynamicEdges.length;
-
-      // place the child node near the parent, not at the exact same location to avoid chaos in the system
-      childNode.x = parentNode.x + parentNode.growthIndicator * (0.5 - Math.random());
-      childNode.y = parentNode.y + parentNode.growthIndicator * (0.5 - Math.random());
-
-      // remove node from the list
-      delete parentNode.containedNodes[containedNodeId];
-
-      // check if there are other childs with this clusterSession in the parent.
-      var othersPresent = false;
-      for (var childNodeId in parentNode.containedNodes) {
-        if (parentNode.containedNodes.hasOwnProperty(childNodeId)) {
-          if (parentNode.containedNodes[childNodeId].clusterSession == childNode.clusterSession) {
-            othersPresent = true;
-            break;
-          }
-        }
-      }
-      // if there are no others, remove the cluster session from the list
-      if (othersPresent == false) {
-        parentNode.clusterSessions.pop();
-      }
-
-      this._repositionBezierNodes(childNode);
-//      this._repositionBezierNodes(parentNode);
-
-      // remove the clusterSession from the child node
-      childNode.clusterSession = 0;
-
-      // recalculate the size of the node on the next time the node is rendered
-      parentNode.clearSizeCache();
-
-      // restart the simulation to reorganise all nodes
-      this.moving = true;
-    }
-
-    // check if a further expansion step is possible if recursivity is enabled
-    if (recursive == true) {
-      this._expandClusterNode(childNode,recursive,force,openAll);
-    }
-  },
-
-
-  /**
-   * position the bezier nodes at the center of the edges
-   *
-   * @param node
-   * @private
-   */
-  _repositionBezierNodes : function(node) {
-    for (var i = 0; i < node.dynamicEdges.length; i++) {
-      node.dynamicEdges[i].positionBezierNode();
-    }
-  },
-
-
-  /**
-   * This function checks if any nodes at the end of their trees have edges below a threshold length
-   * This function is called only from updateClusters()
-   * forceLevelCollapse ignores the length of the edge and collapses one level
-   * This means that a node with only one edge will be clustered with its connected node
-   *
-   * @private
-   * @param {Boolean} force
-   */
-  _formClusters : function(force) {
-    if (force == false) {
-      this._formClustersByZoom();
-    }
-    else {
-      this._forceClustersByZoom();
-    }
-  },
-
-
-  /**
-   * This function handles the clustering by zooming out, this is based on a minimum edge distance
-   *
-   * @private
-   */
-  _formClustersByZoom : function() {
-    var dx,dy,length,
-        minLength = this.constants.clustering.clusterEdgeThreshold/this.scale;
-
-    // check if any edges are shorter than minLength and start the clustering
-    // the clustering favours the node with the larger mass
-    for (var edgeId in this.edges) {
-      if (this.edges.hasOwnProperty(edgeId)) {
-        var edge = this.edges[edgeId];
-        if (edge.connected) {
-          if (edge.toId != edge.fromId) {
-            dx = (edge.to.x - edge.from.x);
-            dy = (edge.to.y - edge.from.y);
-            length = Math.sqrt(dx * dx + dy * dy);
-
-
-            if (length < minLength) {
-              // first check which node is larger
-              var parentNode = edge.from;
-              var childNode = edge.to;
-              if (edge.to.mass > edge.from.mass) {
-                parentNode = edge.to;
-                childNode = edge.from;
-              }
-
-              if (childNode.dynamicEdgesLength == 1) {
-                this._addToCluster(parentNode,childNode,false);
-              }
-              else if (parentNode.dynamicEdgesLength == 1) {
-                this._addToCluster(childNode,parentNode,false);
-              }
-            }
-          }
-        }
-      }
-    }
-  },
-
-  /**
-   * This function forces the graph to cluster all nodes with only one connecting edge to their
-   * connected node.
-   *
-   * @private
-   */
-  _forceClustersByZoom : function() {
-    for (var nodeId in this.nodes) {
-      // another node could have absorbed this child.
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        var childNode = this.nodes[nodeId];
-
-        // the edges can be swallowed by another decrease
-        if (childNode.dynamicEdgesLength == 1 && childNode.dynamicEdges.length != 0) {
-          var edge = childNode.dynamicEdges[0];
-          var parentNode = (edge.toId == childNode.id) ? this.nodes[edge.fromId] : this.nodes[edge.toId];
-
-          // group to the largest node
-          if (childNode.id != parentNode.id) {
-            if (parentNode.mass > childNode.mass) {
-              this._addToCluster(parentNode,childNode,true);
-            }
-            else {
-              this._addToCluster(childNode,parentNode,true);
-            }
-          }
-        }
-      }
-    }
-  },
-
-
-  /**
-   * To keep the nodes of roughly equal size we normalize the cluster levels.
-   * This function clusters a node to its smallest connected neighbour.
-   *
-   * @param node
-   * @private
-   */
-  _clusterToSmallestNeighbour : function(node) {
-    var smallestNeighbour = -1;
-    var smallestNeighbourNode = null;
-    for (var i = 0; i < node.dynamicEdges.length; i++) {
-      if (node.dynamicEdges[i] !== undefined) {
-        var neighbour = null;
-        if (node.dynamicEdges[i].fromId != node.id) {
-          neighbour = node.dynamicEdges[i].from;
-        }
-        else if (node.dynamicEdges[i].toId != node.id) {
-          neighbour = node.dynamicEdges[i].to;
-        }
-
-
-        if (neighbour != null && smallestNeighbour > neighbour.clusterSessions.length) {
-          smallestNeighbour = neighbour.clusterSessions.length;
-          smallestNeighbourNode = neighbour;
-        }
-      }
-    }
-
-    if (neighbour != null && this.nodes[neighbour.id] !== undefined) {
-      this._addToCluster(neighbour, node, true);
-    }
-  },
-
-
-  /**
-   * This function forms clusters from hubs, it loops over all nodes
-   *
-   * @param {Boolean} force         |   Disregard zoom level
-   * @param {Boolean} onlyEqual     |   This only clusters a hub with a specific number of edges
-   * @private
-   */
-  _formClustersByHub : function(force, onlyEqual) {
-    // we loop over all nodes in the list
-    for (var nodeId in this.nodes) {
-      // we check if it is still available since it can be used by the clustering in this loop
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        this._formClusterFromHub(this.nodes[nodeId],force,onlyEqual);
-      }
-    }
-  },
-
-  /**
-   * This function forms a cluster from a specific preselected hub node
-   *
-   * @param {Node}    hubNode       |   the node we will cluster as a hub
-   * @param {Boolean} force         |   Disregard zoom level
-   * @param {Boolean} onlyEqual     |   This only clusters a hub with a specific number of edges
-   * @param {Number} [absorptionSizeOffset] |
-   * @private
-   */
-  _formClusterFromHub : function(hubNode, force, onlyEqual, absorptionSizeOffset) {
-    if (absorptionSizeOffset === undefined) {
-      absorptionSizeOffset = 0;
-    }
-    // we decide if the node is a hub
-    if ((hubNode.dynamicEdgesLength >= this.hubThreshold && onlyEqual == false) ||
-      (hubNode.dynamicEdgesLength == this.hubThreshold && onlyEqual == true)) {
-      // initialize variables
-      var dx,dy,length;
-      var minLength = this.constants.clustering.clusterEdgeThreshold/this.scale;
-      var allowCluster = false;
-
-      // we create a list of edges because the dynamicEdges change over the course of this loop
-      var edgesIdarray = [];
-      var amountOfInitialEdges = hubNode.dynamicEdges.length;
-      for (var j = 0; j < amountOfInitialEdges; j++) {
-        edgesIdarray.push(hubNode.dynamicEdges[j].id);
-      }
-
-      // if the hub clustering is not forces, we check if one of the edges connected
-      // to a cluster is small enough based on the constants.clustering.clusterEdgeThreshold
-      if (force == false) {
-        allowCluster = false;
-        for (j = 0; j < amountOfInitialEdges; j++) {
-          var edge = this.edges[edgesIdarray[j]];
-          if (edge !== undefined) {
-            if (edge.connected) {
-              if (edge.toId != edge.fromId) {
-                dx = (edge.to.x - edge.from.x);
-                dy = (edge.to.y - edge.from.y);
-                length = Math.sqrt(dx * dx + dy * dy);
-
-                if (length < minLength) {
-                  allowCluster = true;
-                  break;
-                }
-              }
-            }
-          }
-        }
-      }
-
-      // start the clustering if allowed
-      if ((!force && allowCluster) || force) {
-        // we loop over all edges INITIALLY connected to this hub
-        for (j = 0; j < amountOfInitialEdges; j++) {
-          edge = this.edges[edgesIdarray[j]];
-          // the edge can be clustered by this function in a previous loop
-          if (edge !== undefined) {
-            var childNode = this.nodes[(edge.fromId == hubNode.id) ? edge.toId : edge.fromId];
-            // we do not want hubs to merge with other hubs nor do we want to cluster itself.
-            if ((childNode.dynamicEdges.length <= (this.hubThreshold + absorptionSizeOffset)) &&
-                (childNode.id != hubNode.id)) {
-              this._addToCluster(hubNode,childNode,force);
-            }
-          }
-        }
-      }
-    }
-  },
-
-
-
-  /**
-   * This function adds the child node to the parent node, creating a cluster if it is not already.
-   *
-   * @param {Node} parentNode           | this is the node that will house the child node
-   * @param {Node} childNode            | this node will be deleted from the global this.nodes and stored in the parent node
-   * @param {Boolean} force             | true will only update the remainingEdges at the very end of the clustering, ensuring single level collapse
-   * @private
-   */
-  _addToCluster : function(parentNode, childNode, force) {
-    // join child node in the parent node
-    parentNode.containedNodes[childNode.id] = childNode;
-
-    // manage all the edges connected to the child and parent nodes
-    for (var i = 0; i < childNode.dynamicEdges.length; i++) {
-      var edge = childNode.dynamicEdges[i];
-      if (edge.toId == parentNode.id || edge.fromId == parentNode.id) { // edge connected to parentNode
-        this._addToContainedEdges(parentNode,childNode,edge);
-      }
-      else {
-        this._connectEdgeToCluster(parentNode,childNode,edge);
-      }
-    }
-    // a contained node has no dynamic edges.
-    childNode.dynamicEdges = [];
-
-    // remove circular edges from clusters
-    this._containCircularEdgesFromNode(parentNode,childNode);
-
-
-    // remove the childNode from the global nodes object
-    delete this.nodes[childNode.id];
-
-    // update the properties of the child and parent
-    var massBefore = parentNode.mass;
-    childNode.clusterSession = this.clusterSession;
-    parentNode.mass += childNode.mass;
-    parentNode.clusterSize += childNode.clusterSize;
-    parentNode.fontSize = Math.min(this.constants.clustering.maxFontSize, this.constants.nodes.fontSize + this.constants.clustering.fontSizeMultiplier*parentNode.clusterSize);
-
-    // keep track of the clustersessions so we can open the cluster up as it has been formed.
-    if (parentNode.clusterSessions[parentNode.clusterSessions.length - 1] != this.clusterSession) {
-      parentNode.clusterSessions.push(this.clusterSession);
-    }
-
-    // forced clusters only open from screen size and double tap
-    if (force == true) {
-      // parentNode.formationScale = Math.pow(1 - (1.0/11.0),this.clusterSession+3);
-      parentNode.formationScale = 0;
-    }
-    else {
-      parentNode.formationScale = this.scale; // The latest child has been added on this scale
-    }
-
-    // recalculate the size of the node on the next time the node is rendered
-    parentNode.clearSizeCache();
-
-    // set the pop-out scale for the childnode
-    parentNode.containedNodes[childNode.id].formationScale = parentNode.formationScale;
-
-    // nullify the movement velocity of the child, this is to avoid hectic behaviour
-    childNode.clearVelocity();
-
-    // the mass has altered, preservation of energy dictates the velocity to be updated
-    parentNode.updateVelocity(massBefore);
-
-    // restart the simulation to reorganise all nodes
-    this.moving = true;
-  },
-
-
-  /**
-   * This function will apply the changes made to the remainingEdges during the formation of the clusters.
-   * This is a seperate function to allow for level-wise collapsing of the node barnesHutTree.
-   * It has to be called if a level is collapsed. It is called by _formClusters().
-   * @private
-   */
-  _updateDynamicEdges : function() {
-    for (var i = 0; i < this.nodeIndices.length; i++) {
-      var node = this.nodes[this.nodeIndices[i]];
-      node.dynamicEdgesLength = node.dynamicEdges.length;
-
-      // this corrects for multiple edges pointing at the same other node
-      var correction = 0;
-      if (node.dynamicEdgesLength > 1) {
-        for (var j = 0; j < node.dynamicEdgesLength - 1; j++) {
-          var edgeToId = node.dynamicEdges[j].toId;
-          var edgeFromId = node.dynamicEdges[j].fromId;
-          for (var k = j+1; k < node.dynamicEdgesLength; k++) {
-            if ((node.dynamicEdges[k].toId == edgeToId && node.dynamicEdges[k].fromId == edgeFromId) ||
-                (node.dynamicEdges[k].fromId == edgeToId && node.dynamicEdges[k].toId == edgeFromId)) {
-              correction += 1;
-            }
-          }
-        }
-      }
-      node.dynamicEdgesLength -= correction;
-    }
-  },
-
-
-  /**
-   * This adds an edge from the childNode to the contained edges of the parent node
-   *
-   * @param parentNode    | Node object
-   * @param childNode     | Node object
-   * @param edge          | Edge object
-   * @private
-   */
-  _addToContainedEdges : function(parentNode, childNode, edge) {
-    // create an array object if it does not yet exist for this childNode
-    if (!(parentNode.containedEdges.hasOwnProperty(childNode.id))) {
-      parentNode.containedEdges[childNode.id] = []
-    }
-    // add this edge to the list
-    parentNode.containedEdges[childNode.id].push(edge);
-
-    // remove the edge from the global edges object
-    delete this.edges[edge.id];
-
-    // remove the edge from the parent object
-    for (var i = 0; i < parentNode.dynamicEdges.length; i++) {
-      if (parentNode.dynamicEdges[i].id == edge.id) {
-        parentNode.dynamicEdges.splice(i,1);
-        break;
-      }
-    }
-  },
-
-  /**
-   * This function connects an edge that was connected to a child node to the parent node.
-   * It keeps track of which nodes it has been connected to with the originalId array.
-   *
-   * @param {Node} parentNode    | Node object
-   * @param {Node} childNode     | Node object
-   * @param {Edge} edge          | Edge object
-   * @private
-   */
-  _connectEdgeToCluster : function(parentNode, childNode, edge) {
-    // handle circular edges
-    if (edge.toId == edge.fromId) {
-      this._addToContainedEdges(parentNode, childNode, edge);
-    }
-    else {
-      if (edge.toId == childNode.id) {    // edge connected to other node on the "to" side
-        edge.originalToId.push(childNode.id);
-        edge.to = parentNode;
-        edge.toId = parentNode.id;
-      }
-      else {          // edge connected to other node with the "from" side
-
-        edge.originalFromId.push(childNode.id);
-        edge.from = parentNode;
-        edge.fromId = parentNode.id;
-      }
-
-      this._addToReroutedEdges(parentNode,childNode,edge);
-    }
-  },
-
-
-  /**
-   * If a node is connected to itself, a circular edge is drawn. When clustering we want to contain
-   * these edges inside of the cluster.
-   *
-   * @param parentNode
-   * @param childNode
-   * @private
-   */
-  _containCircularEdgesFromNode : function(parentNode, childNode) {
-    // manage all the edges connected to the child and parent nodes
-    for (var i = 0; i < parentNode.dynamicEdges.length; i++) {
-      var edge = parentNode.dynamicEdges[i];
-      // handle circular edges
-      if (edge.toId == edge.fromId) {
-        this._addToContainedEdges(parentNode, childNode, edge);
-      }
-    }
-  },
-
-
-  /**
-   * This adds an edge from the childNode to the rerouted edges of the parent node
-   *
-   * @param parentNode    | Node object
-   * @param childNode     | Node object
-   * @param edge          | Edge object
-   * @private
-   */
-  _addToReroutedEdges : function(parentNode, childNode, edge) {
-    // create an array object if it does not yet exist for this childNode
-    // we store the edge in the rerouted edges so we can restore it when the cluster pops open
-    if (!(parentNode.reroutedEdges.hasOwnProperty(childNode.id))) {
-      parentNode.reroutedEdges[childNode.id] = [];
-    }
-    parentNode.reroutedEdges[childNode.id].push(edge);
-
-    // this edge becomes part of the dynamicEdges of the cluster node
-    parentNode.dynamicEdges.push(edge);
-   },
-
-
-
-  /**
-   * This function connects an edge that was connected to a cluster node back to the child node.
-   *
-   * @param parentNode    | Node object
-   * @param childNode     | Node object
-   * @private
-   */
-  _connectEdgeBackToChild : function(parentNode, childNode) {
-    if (parentNode.reroutedEdges.hasOwnProperty(childNode.id)) {
-      for (var i = 0; i < parentNode.reroutedEdges[childNode.id].length; i++) {
-        var edge = parentNode.reroutedEdges[childNode.id][i];
-        if (edge.originalFromId[edge.originalFromId.length-1] == childNode.id) {
-          edge.originalFromId.pop();
-          edge.fromId = childNode.id;
-          edge.from = childNode;
-        }
-        else {
-          edge.originalToId.pop();
-          edge.toId = childNode.id;
-          edge.to = childNode;
-        }
-
-        // append this edge to the list of edges connecting to the childnode
-        childNode.dynamicEdges.push(edge);
-
-        // remove the edge from the parent object
-        for (var j = 0; j < parentNode.dynamicEdges.length; j++) {
-          if (parentNode.dynamicEdges[j].id == edge.id) {
-            parentNode.dynamicEdges.splice(j,1);
-            break;
-          }
-        }
-      }
-      // remove the entry from the rerouted edges
-      delete parentNode.reroutedEdges[childNode.id];
-    }
-  },
-
-
-  /**
-   * When loops are clustered, an edge can be both in the rerouted array and the contained array.
-   * This function is called last to verify that all edges in dynamicEdges are in fact connected to the
-   * parentNode
-   *
-   * @param parentNode    | Node object
-   * @private
-   */
-  _validateEdges : function(parentNode) {
-    for (var i = 0; i < parentNode.dynamicEdges.length; i++) {
-      var edge = parentNode.dynamicEdges[i];
-      if (parentNode.id != edge.toId && parentNode.id != edge.fromId) {
-        parentNode.dynamicEdges.splice(i,1);
-      }
-    }
-  },
-
-
-  /**
-   * This function released the contained edges back into the global domain and puts them back into the
-   * dynamic edges of both parent and child.
-   *
-   * @param {Node} parentNode    |
-   * @param {Node} childNode     |
-   * @private
-   */
-  _releaseContainedEdges : function(parentNode, childNode) {
-    for (var i = 0; i < parentNode.containedEdges[childNode.id].length; i++) {
-      var edge = parentNode.containedEdges[childNode.id][i];
-
-      // put the edge back in the global edges object
-      this.edges[edge.id] = edge;
-
-      // put the edge back in the dynamic edges of the child and parent
-      childNode.dynamicEdges.push(edge);
-      parentNode.dynamicEdges.push(edge);
-    }
-    // remove the entry from the contained edges
-    delete parentNode.containedEdges[childNode.id];
-
-  },
-
-
-
-
-  // ------------------- UTILITY FUNCTIONS ---------------------------- //
-
-
-  /**
-   * This updates the node labels for all nodes (for debugging purposes)
-   */
-  updateLabels : function() {
-    var nodeId;
-    // update node labels
-    for (nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        var node = this.nodes[nodeId];
-        if (node.clusterSize > 1) {
-          node.label = "[".concat(String(node.clusterSize),"]");
-        }
-      }
-    }
-
-    // update node labels
-    for (nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        node = this.nodes[nodeId];
-        if (node.clusterSize == 1) {
-          if (node.originalLabel !== undefined) {
-            node.label = node.originalLabel;
-          }
-          else {
-            node.label = String(node.id);
-          }
-        }
-      }
-    }
-
-//    /* Debug Override */
-//    for (nodeId in this.nodes) {
-//      if (this.nodes.hasOwnProperty(nodeId)) {
-//        node = this.nodes[nodeId];
-//        node.label = String(node.level);
-//      }
-//    }
-
-  },
-
-
-  /**
-   * We want to keep the cluster level distribution rather small. This means we do not want unclustered nodes
-   * if the rest of the nodes are already a few cluster levels in.
-   * To fix this we use this function. It determines the min and max cluster level and sends nodes that have not
-   * clustered enough to the clusterToSmallestNeighbours function.
-   */
-  normalizeClusterLevels : function() {
-    var maxLevel = 0;
-    var minLevel = 1e9;
-    var clusterLevel = 0;
-    var nodeId;
-
-    // we loop over all nodes in the list
-    for (nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        clusterLevel = this.nodes[nodeId].clusterSessions.length;
-        if (maxLevel < clusterLevel) {maxLevel = clusterLevel;}
-        if (minLevel > clusterLevel) {minLevel = clusterLevel;}
-      }
-    }
-
-    if (maxLevel - minLevel > this.constants.clustering.clusterLevelDifference) {
-      var amountOfNodes = this.nodeIndices.length;
-      var targetLevel = maxLevel - this.constants.clustering.clusterLevelDifference;
-      // we loop over all nodes in the list
-      for (nodeId in this.nodes) {
-        if (this.nodes.hasOwnProperty(nodeId)) {
-          if (this.nodes[nodeId].clusterSessions.length < targetLevel) {
-            this._clusterToSmallestNeighbour(this.nodes[nodeId]);
-          }
-        }
-      }
-      this._updateNodeIndexList();
-      this._updateDynamicEdges();
-      // if a cluster was formed, we increase the clusterSession
-      if (this.nodeIndices.length != amountOfNodes) {
-        this.clusterSession += 1;
-      }
-    }
-  },
-
-
-
-  /**
-   * This function determines if the cluster we want to decluster is in the active area
-   * this means around the zoom center
-   *
-   * @param {Node} node
-   * @returns {boolean}
-   * @private
-   */
-  _nodeInActiveArea : function(node) {
-    return (
-      Math.abs(node.x - this.areaCenter.x) <= this.constants.clustering.activeAreaBoxSize/this.scale
-        &&
-      Math.abs(node.y - this.areaCenter.y) <= this.constants.clustering.activeAreaBoxSize/this.scale
-      )
-  },
-
-
-  /**
-   * This is an adaptation of the original repositioning function. This is called if the system is clustered initially
-   * It puts large clusters away from the center and randomizes the order.
-   *
-   */
-  repositionNodes : function() {
-    for (var i = 0; i < this.nodeIndices.length; i++) {
-      var node = this.nodes[this.nodeIndices[i]];
-      if ((node.xFixed == false || node.yFixed == false)) {
-        var radius = 10 * 0.1*this.nodeIndices.length * Math.min(100,node.mass);
-        var angle = 2 * Math.PI * Math.random();
-        if (node.xFixed == false) {node.x = radius * Math.cos(angle);}
-        if (node.yFixed == false) {node.y = radius * Math.sin(angle);}
-        this._repositionBezierNodes(node);
-      }
-    }
-  },
-
-
-  /**
-   * We determine how many connections denote an important hub.
-   * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%)
-   *
-   * @private
-   */
-  _getHubSize : function() {
-    var average = 0;
-    var averageSquared = 0;
-    var hubCounter = 0;
-    var largestHub = 0;
-
-    for (var i = 0; i < this.nodeIndices.length; i++) {
-
-      var node = this.nodes[this.nodeIndices[i]];
-      if (node.dynamicEdgesLength > largestHub) {
-        largestHub = node.dynamicEdgesLength;
-      }
-      average += node.dynamicEdgesLength;
-      averageSquared += Math.pow(node.dynamicEdgesLength,2);
-      hubCounter += 1;
-    }
-    average = average / hubCounter;
-    averageSquared = averageSquared / hubCounter;
-
-    var variance = averageSquared - Math.pow(average,2);
-
-    var standardDeviation = Math.sqrt(variance);
-
-    this.hubThreshold = Math.floor(average + 2*standardDeviation);
-
-    // always have at least one to cluster
-    if (this.hubThreshold > largestHub) {
-      this.hubThreshold = largestHub;
-    }
-
-  //  console.log("average",average,"averageSQ",averageSquared,"var",variance,"std",standardDeviation);
-  //  console.log("hubThreshold:",this.hubThreshold);
-  },
-
-
-  /**
-   * We reduce the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods
-   * with this amount we can cluster specifically on these chains.
-   *
-   * @param   {Number} fraction     | between 0 and 1, the percentage of chains to reduce
-   * @private
-   */
-  _reduceAmountOfChains : function(fraction) {
-    this.hubThreshold = 2;
-    var reduceAmount = Math.floor(this.nodeIndices.length * fraction);
-    for (var nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) {
-          if (reduceAmount > 0) {
-            this._formClusterFromHub(this.nodes[nodeId],true,true,1);
-            reduceAmount -= 1;
-          }
-        }
-      }
-    }
-  },
-
-  /**
-   * We get the amount of "extension nodes" or chains. These are not quickly clustered with the outliers and hubs methods
-   * with this amount we can cluster specifically on these chains.
-   *
-   * @private
-   */
-  _getChainFraction : function() {
-    var chains = 0;
-    var total = 0;
-    for (var nodeId in this.nodes) {
-      if (this.nodes.hasOwnProperty(nodeId)) {
-        if (this.nodes[nodeId].dynamicEdgesLength == 2 && this.nodes[nodeId].dynamicEdges.length >= 2) {
-          chains += 1;
-        }
-        total += 1;
-      }
-    }
-    return chains/total;
-  }
-
-};
-
-
-var SelectionMixin = {
-
-  /**
-   * This function can be called from the _doInAllSectors function
-   *
-   * @param object
-   * @param overlappingNodes
-   * @private
-   */
-  _getNodesOverlappingWith : function(object, overlappingNodes) {
-    var nodes = this.nodes;
-    for (var nodeId in nodes) {
-      if (nodes.hasOwnProperty(nodeId)) {
-        if (nodes[nodeId].isOverlappingWith(object)) {
-          overlappingNodes.push(nodeId);
-        }
-      }
-    }
-  },
-
-  /**
-   * retrieve all nodes overlapping with given object
-   * @param {Object} object  An object with parameters left, top, right, bottom
-   * @return {Number[]}   An array with id's of the overlapping nodes
-   * @private
-   */
-  _getAllNodesOverlappingWith : function (object) {
-    var overlappingNodes = [];
-    this._doInAllActiveSectors("_getNodesOverlappingWith",object,overlappingNodes);
-    return overlappingNodes;
-  },
-
-
-  /**
-   * Return a position object in canvasspace from a single point in screenspace
-   *
-   * @param pointer
-   * @returns {{left: number, top: number, right: number, bottom: number}}
-   * @private
-   */
-  _pointerToPositionObject : function(pointer) {
-    var x = this._XconvertDOMtoCanvas(pointer.x);
-    var y = this._YconvertDOMtoCanvas(pointer.y);
-
-    return {left:   x,
-            top:    y,
-            right:  x,
-            bottom: y};
-  },
-
-
-  /**
-   * Get the top node at the a specific point (like a click)
-   *
-   * @param {{x: Number, y: Number}} pointer
-   * @return {Node | null} node
-   * @private
-   */
-  _getNodeAt : function (pointer) {
-    // we first check if this is an navigation controls element
-    var positionObject = this._pointerToPositionObject(pointer);
-    var overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
-
-    // if there are overlapping nodes, select the last one, this is the
-    // one which is drawn on top of the others
-    if (overlappingNodes.length > 0) {
-       return this.nodes[overlappingNodes[overlappingNodes.length - 1]];
-    }
-    else {
-      return null;
-    }
-  },
-
-
-  /**
-   * retrieve all edges overlapping with given object, selector is around center
-   * @param {Object} object  An object with parameters left, top, right, bottom
-   * @return {Number[]}   An array with id's of the overlapping nodes
-   * @private
-   */
-  _getEdgesOverlappingWith : function (object, overlappingEdges) {
-    var edges = this.edges;
-    for (var edgeId in edges) {
-      if (edges.hasOwnProperty(edgeId)) {
-        if (edges[edgeId].isOverlappingWith(object)) {
-          overlappingEdges.push(edgeId);
-        }
-      }
-    }
-  },
-
-
-  /**
-   * retrieve all nodes overlapping with given object
-   * @param {Object} object  An object with parameters left, top, right, bottom
-   * @return {Number[]}   An array with id's of the overlapping nodes
-   * @private
-   */
-  _getAllEdgesOverlappingWith : function (object) {
-    var overlappingEdges = [];
-    this._doInAllActiveSectors("_getEdgesOverlappingWith",object,overlappingEdges);
-    return overlappingEdges;
-  },
-
-  /**
-   * Place holder. To implement change the _getNodeAt to a _getObjectAt. Have the _getObjectAt call
-   * _getNodeAt and _getEdgesAt, then priortize the selection to user preferences.
-   *
-   * @param pointer
-   * @returns {null}
-   * @private
-   */
-  _getEdgeAt : function(pointer) {
-    var positionObject = this._pointerToPositionObject(pointer);
-    var overlappingEdges = this._getAllEdgesOverlappingWith(positionObject);
-
-    if (overlappingEdges.length > 0) {
-      return this.edges[overlappingEdges[overlappingEdges.length - 1]];
-    }
-    else {
-      return null;
-    }
-  },
-
-
-  /**
-   * Add object to the selection array.
-   *
-   * @param obj
-   * @private
-   */
-  _addToSelection : function(obj) {
-    if (obj instanceof Node) {
-      this.selectionObj.nodes[obj.id] = obj;
-    }
-    else {
-      this.selectionObj.edges[obj.id] = obj;
-    }
-  },
-
-  /**
-   * Add object to the selection array.
-   *
-   * @param obj
-   * @private
-   */
-  _addToHover : function(obj) {
-    if (obj instanceof Node) {
-      this.hoverObj.nodes[obj.id] = obj;
-    }
-    else {
-      this.hoverObj.edges[obj.id] = obj;
-    }
-  },
-
-
-  /**
-   * Remove a single option from selection.
-   *
-   * @param {Object} obj
-   * @private
-   */
-  _removeFromSelection : function(obj) {
-    if (obj instanceof Node) {
-      delete this.selectionObj.nodes[obj.id];
-    }
-    else {
-      delete this.selectionObj.edges[obj.id];
-    }
-  },
-
-  /**
-   * Unselect all. The selectionObj is useful for this.
-   *
-   * @param {Boolean} [doNotTrigger] | ignore trigger
-   * @private
-   */
-  _unselectAll : function(doNotTrigger) {
-    if (doNotTrigger === undefined) {
-      doNotTrigger = false;
-    }
-    for(var nodeId in this.selectionObj.nodes) {
-      if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        this.selectionObj.nodes[nodeId].unselect();
-      }
-    }
-    for(var edgeId in this.selectionObj.edges) {
-      if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
-        this.selectionObj.edges[edgeId].unselect();
-      }
-    }
-
-    this.selectionObj = {nodes:{},edges:{}};
-
-    if (doNotTrigger == false) {
-      this.emit('select', this.getSelection());
-    }
-  },
-
-  /**
-   * Unselect all clusters. The selectionObj is useful for this.
-   *
-   * @param {Boolean} [doNotTrigger] | ignore trigger
-   * @private
-   */
-  _unselectClusters : function(doNotTrigger) {
-    if (doNotTrigger === undefined) {
-      doNotTrigger = false;
-    }
-
-    for (var nodeId in this.selectionObj.nodes) {
-      if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        if (this.selectionObj.nodes[nodeId].clusterSize > 1) {
-          this.selectionObj.nodes[nodeId].unselect();
-          this._removeFromSelection(this.selectionObj.nodes[nodeId]);
-        }
-      }
-    }
-
-    if (doNotTrigger == false) {
-      this.emit('select', this.getSelection());
-    }
-  },
-
-
-  /**
-   * return the number of selected nodes
-   *
-   * @returns {number}
-   * @private
-   */
-  _getSelectedNodeCount : function() {
-    var count = 0;
-    for (var nodeId in this.selectionObj.nodes) {
-      if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        count += 1;
-      }
-    }
-    return count;
-  },
-
-  /**
-   * return the selected node
-   *
-   * @returns {number}
-   * @private
-   */
-  _getSelectedNode : function() {
-    for (var nodeId in this.selectionObj.nodes) {
-      if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        return this.selectionObj.nodes[nodeId];
-      }
-    }
-    return null;
-  },
-
-  /**
-   * return the selected edge
-   *
-   * @returns {number}
-   * @private
-   */
-  _getSelectedEdge : function() {
-    for (var edgeId in this.selectionObj.edges) {
-      if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
-        return this.selectionObj.edges[edgeId];
-      }
-    }
-    return null;
-  },
-
-
-  /**
-   * return the number of selected edges
-   *
-   * @returns {number}
-   * @private
-   */
-  _getSelectedEdgeCount : function() {
-    var count = 0;
-    for (var edgeId in this.selectionObj.edges) {
-      if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
-        count += 1;
-      }
-    }
-    return count;
-  },
-
-
-  /**
-   * return the number of selected objects.
-   *
-   * @returns {number}
-   * @private
-   */
-  _getSelectedObjectCount : function() {
-    var count = 0;
-    for(var nodeId in this.selectionObj.nodes) {
-      if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        count += 1;
-      }
-    }
-    for(var edgeId in this.selectionObj.edges) {
-      if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
-        count += 1;
-      }
-    }
-    return count;
-  },
-
-  /**
-   * Check if anything is selected
-   *
-   * @returns {boolean}
-   * @private
-   */
-  _selectionIsEmpty : function() {
-    for(var nodeId in this.selectionObj.nodes) {
-      if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        return false;
-      }
-    }
-    for(var edgeId in this.selectionObj.edges) {
-      if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
-        return false;
-      }
-    }
-    return true;
-  },
-
-
-  /**
-   * check if one of the selected nodes is a cluster.
-   *
-   * @returns {boolean}
-   * @private
-   */
-  _clusterInSelection : function() {
-    for(var nodeId in this.selectionObj.nodes) {
-      if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        if (this.selectionObj.nodes[nodeId].clusterSize > 1) {
-          return true;
-        }
-      }
-    }
-    return false;
-  },
-
-  /**
-   * select the edges connected to the node that is being selected
-   *
-   * @param {Node} node
-   * @private
-   */
-  _selectConnectedEdges : function(node) {
-    for (var i = 0; i < node.dynamicEdges.length; i++) {
-      var edge = node.dynamicEdges[i];
-      edge.select();
-      this._addToSelection(edge);
-    }
-  },
-
-  /**
-   * select the edges connected to the node that is being selected
-   *
-   * @param {Node} node
-   * @private
-   */
-  _hoverConnectedEdges : function(node) {
-    for (var i = 0; i < node.dynamicEdges.length; i++) {
-      var edge = node.dynamicEdges[i];
-      edge.hover = true;
-      this._addToHover(edge);
-    }
-  },
-
-
-  /**
-   * unselect the edges connected to the node that is being selected
-   *
-   * @param {Node} node
-   * @private
-   */
-  _unselectConnectedEdges : function(node) {
-    for (var i = 0; i < node.dynamicEdges.length; i++) {
-      var edge = node.dynamicEdges[i];
-      edge.unselect();
-      this._removeFromSelection(edge);
-    }
-  },
-
-
-
-
-  /**
-   * This is called when someone clicks on a node. either select or deselect it.
-   * If there is an existing selection and we don't want to append to it, clear the existing selection
-   *
-   * @param {Node || Edge} object
-   * @param {Boolean} append
-   * @param {Boolean} [doNotTrigger] | ignore trigger
-   * @private
-   */
-  _selectObject : function(object, append, doNotTrigger) {
-    if (doNotTrigger === undefined) {
-      doNotTrigger = false;
-    }
-
-    if (this._selectionIsEmpty() == false && append == false && this.forceAppendSelection == false) {
-      this._unselectAll(true);
-    }
-
-    if (object.selected == false) {
-      object.select();
-      this._addToSelection(object);
-      if (object instanceof Node && this.blockConnectingEdgeSelection == false) {
-        this._selectConnectedEdges(object);
-      }
-    }
-    else {
-      object.unselect();
-      this._removeFromSelection(object);
-    }
-
-    if (doNotTrigger == false) {
-      this.emit('select', this.getSelection());
-    }
-  },
-
-
-  /**
-   * This is called when someone clicks on a node. either select or deselect it.
-   * If there is an existing selection and we don't want to append to it, clear the existing selection
-   *
-   * @param {Node || Edge} object
-   * @private
-   */
-  _blurObject : function(object) {
-    if (object.hover == true) {
-      object.hover = false;
-      this.emit("blurNode",{node:object.id});
-    }
-  },
-
-  /**
-   * This is called when someone clicks on a node. either select or deselect it.
-   * If there is an existing selection and we don't want to append to it, clear the existing selection
-   *
-   * @param {Node || Edge} object
-   * @private
-   */
-  _hoverObject : function(object) {
-    if (object.hover == false) {
-      object.hover = true;
-      this._addToHover(object);
-      if (object instanceof Node) {
-        this.emit("hoverNode",{node:object.id});
-      }
-    }
-    if (object instanceof Node) {
-      this._hoverConnectedEdges(object);
-    }
-  },
-
-
-  /**
-   * handles the selection part of the touch, only for navigation controls elements;
-   * Touch is triggered before tap, also before hold. Hold triggers after a while.
-   * This is the most responsive solution
-   *
-   * @param {Object} pointer
-   * @private
-   */
-  _handleTouch : function(pointer) {
-  },
-
-
-  /**
-   * handles the selection part of the tap;
-   *
-   * @param {Object} pointer
-   * @private
-   */
-  _handleTap : function(pointer) {
-    var node = this._getNodeAt(pointer);
-    if (node != null) {
-      this._selectObject(node,false);
-    }
-    else {
-      var edge = this._getEdgeAt(pointer);
-      if (edge != null) {
-        this._selectObject(edge,false);
-      }
-      else {
-        this._unselectAll();
-      }
-    }
-    this.emit("click", this.getSelection());
-    this._redraw();
-  },
-
-
-  /**
-   * handles the selection part of the double tap and opens a cluster if needed
-   *
-   * @param {Object} pointer
-   * @private
-   */
-  _handleDoubleTap : function(pointer) {
-    var node = this._getNodeAt(pointer);
-    if (node != null && node !== undefined) {
-      // we reset the areaCenter here so the opening of the node will occur
-      this.areaCenter =  {"x" : this._XconvertDOMtoCanvas(pointer.x),
-                          "y" : this._YconvertDOMtoCanvas(pointer.y)};
-      this.openCluster(node);
-    }
-    this.emit("doubleClick", this.getSelection());
-  },
-
-
-  /**
-   * Handle the onHold selection part
-   *
-   * @param pointer
-   * @private
-   */
-  _handleOnHold : function(pointer) {
-    var node = this._getNodeAt(pointer);
-    if (node != null) {
-      this._selectObject(node,true);
-    }
-    else {
-      var edge = this._getEdgeAt(pointer);
-      if (edge != null) {
-        this._selectObject(edge,true);
-      }
-    }
-    this._redraw();
-  },
-
-
-  /**
-   * handle the onRelease event. These functions are here for the navigation controls module.
-   *
-    * @private
-   */
-  _handleOnRelease : function(pointer) {
-
-  },
-
-
-
-  /**
-   *
-   * retrieve the currently selected objects
-   * @return {Number[] | String[]} selection    An array with the ids of the
-   *                                            selected nodes.
-   */
-  getSelection : function() {
-    var nodeIds = this.getSelectedNodes();
-    var edgeIds = this.getSelectedEdges();
-    return {nodes:nodeIds, edges:edgeIds};
-  },
-
-  /**
-   *
-   * retrieve the currently selected nodes
-   * @return {String} selection    An array with the ids of the
-   *                                            selected nodes.
-   */
-  getSelectedNodes : function() {
-    var idArray = [];
-    for(var nodeId in this.selectionObj.nodes) {
-      if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        idArray.push(nodeId);
-      }
-    }
-    return idArray
-  },
-
-  /**
-   *
-   * retrieve the currently selected edges
-   * @return {Array} selection    An array with the ids of the
-   *                                            selected nodes.
-   */
-  getSelectedEdges : function() {
-    var idArray = [];
-    for(var edgeId in this.selectionObj.edges) {
-      if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
-        idArray.push(edgeId);
-      }
-    }
-    return idArray;
-  },
-
-
-  /**
-   * select zero or more nodes
-   * @param {Number[] | String[]} selection     An array with the ids of the
-   *                                            selected nodes.
-   */
-  setSelection : function(selection) {
-    var i, iMax, id;
-
-    if (!selection || (selection.length == undefined))
-      throw 'Selection must be an array with ids';
-
-    // first unselect any selected node
-    this._unselectAll(true);
-
-    for (i = 0, iMax = selection.length; i < iMax; i++) {
-      id = selection[i];
-
-      var node = this.nodes[id];
-      if (!node) {
-        throw new RangeError('Node with id "' + id + '" not found');
-      }
-      this._selectObject(node,true,true);
-    }
-    this.redraw();
-  },
-
-
-  /**
-   * Validate the selection: remove ids of nodes which no longer exist
-   * @private
-   */
-  _updateSelection : function () {
-    for(var nodeId in this.selectionObj.nodes) {
-      if(this.selectionObj.nodes.hasOwnProperty(nodeId)) {
-        if (!this.nodes.hasOwnProperty(nodeId)) {
-          delete this.selectionObj.nodes[nodeId];
-        }
-      }
-    }
-    for(var edgeId in this.selectionObj.edges) {
-      if(this.selectionObj.edges.hasOwnProperty(edgeId)) {
-        if (!this.edges.hasOwnProperty(edgeId)) {
-          delete this.selectionObj.edges[edgeId];
-        }
-      }
-    }
-  }
-};
-
-
-
-/**
- * Created by Alex on 1/22/14.
- */
-
-var NavigationMixin = {
-
-  _cleanNavigation : function() {
-    // clean up previosu navigation items
-    var wrapper = document.getElementById('graph-navigation_wrapper');
-    if (wrapper != null) {
-      this.containerElement.removeChild(wrapper);
-    }
-    document.onmouseup = null;
-  },
-
-  /**
-   * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
-   * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
-   * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
-   * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
-   *
-   * @private
-   */
-  _loadNavigationElements : function() {
-    this._cleanNavigation();
-
-    this.navigationDivs = {};
-    var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends'];
-    var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','zoomExtent'];
-
-    this.navigationDivs['wrapper'] = document.createElement('div');
-    this.navigationDivs['wrapper'].id = "graph-navigation_wrapper";
-    this.navigationDivs['wrapper'].style.position = "absolute";
-    this.navigationDivs['wrapper'].style.width = this.frame.canvas.clientWidth + "px";
-    this.navigationDivs['wrapper'].style.height = this.frame.canvas.clientHeight + "px";
-    this.containerElement.insertBefore(this.navigationDivs['wrapper'],this.frame);
-
-    for (var i = 0; i < navigationDivs.length; i++) {
-      this.navigationDivs[navigationDivs[i]] = document.createElement('div');
-      this.navigationDivs[navigationDivs[i]].id = "graph-navigation_" + navigationDivs[i];
-      this.navigationDivs[navigationDivs[i]].className = "graph-navigation " + navigationDivs[i];
-      this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]);
-      this.navigationDivs[navigationDivs[i]].onmousedown = this[navigationDivActions[i]].bind(this);
-    }
-
-    document.onmouseup = this._stopMovement.bind(this);
-  },
-
-  /**
-   * this stops all movement induced by the navigation buttons
-   *
-   * @private
-   */
-  _stopMovement : function() {
-    this._xStopMoving();
-    this._yStopMoving();
-    this._stopZoom();
-  },
-
-
-  /**
-   * stops the actions performed by page up and down etc.
-   *
-   * @param event
-   * @private
-   */
-  _preventDefault : function(event) {
-    if (event !== undefined) {
-      if (event.preventDefault) {
-        event.preventDefault();
-      } else {
-        event.returnValue = false;
-      }
-    }
-  },
-
-
-  /**
-   * move the screen up
-   * By using the increments, instead of adding a fixed number to the translation, we keep fluent and
-   * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently
-   * To avoid this behaviour, we do the translation in the start loop.
-   *
-   * @private
-   */
-  _moveUp : function(event) {
-    this.yIncrement = this.constants.keyboard.speed.y;
-    this.start(); // if there is no node movement, the calculation wont be done
-    this._preventDefault(event);
-    if (this.navigationDivs) {
-      this.navigationDivs['up'].className += " active";
-    }
-  },
-
-
-  /**
-   * move the screen down
-   * @private
-   */
-  _moveDown : function(event) {
-    this.yIncrement = -this.constants.keyboard.speed.y;
-    this.start(); // if there is no node movement, the calculation wont be done
-    this._preventDefault(event);
-    if (this.navigationDivs) {
-      this.navigationDivs['down'].className += " active";
-    }
-  },
-
-
-  /**
-   * move the screen left
-   * @private
-   */
-  _moveLeft : function(event) {
-    this.xIncrement = this.constants.keyboard.speed.x;
-    this.start(); // if there is no node movement, the calculation wont be done
-    this._preventDefault(event);
-    if (this.navigationDivs) {
-      this.navigationDivs['left'].className += " active";
-    }
-  },
-
-
-  /**
-   * move the screen right
-   * @private
-   */
-  _moveRight : function(event) {
-    this.xIncrement = -this.constants.keyboard.speed.y;
-    this.start(); // if there is no node movement, the calculation wont be done
-    this._preventDefault(event);
-    if (this.navigationDivs) {
-      this.navigationDivs['right'].className += " active";
-    }
-  },
-
-
-  /**
-   * Zoom in, using the same method as the movement.
-   * @private
-   */
-  _zoomIn : function(event) {
-    this.zoomIncrement = this.constants.keyboard.speed.zoom;
-    this.start(); // if there is no node movement, the calculation wont be done
-    this._preventDefault(event);
-    if (this.navigationDivs) {
-      this.navigationDivs['zoomIn'].className += " active";
-    }
-  },
-
-
-  /**
-   * Zoom out
-   * @private
-   */
-  _zoomOut : function() {
-    this.zoomIncrement = -this.constants.keyboard.speed.zoom;
-    this.start(); // if there is no node movement, the calculation wont be done
-    this._preventDefault(event);
-    if (this.navigationDivs) {
-      this.navigationDivs['zoomOut'].className += " active";
-    }
-  },
-
-
-  /**
-   * Stop zooming and unhighlight the zoom controls
-   * @private
-   */
-  _stopZoom : function() {
-    this.zoomIncrement = 0;
-    if (this.navigationDivs) {
-      this.navigationDivs['zoomIn'].className = this.navigationDivs['zoomIn'].className.replace(" active","");
-      this.navigationDivs['zoomOut'].className = this.navigationDivs['zoomOut'].className.replace(" active","");
-    }
-  },
-
-
-  /**
-   * Stop moving in the Y direction and unHighlight the up and down
-   * @private
-   */
-  _yStopMoving : function() {
-    this.yIncrement = 0;
-    if (this.navigationDivs) {
-      this.navigationDivs['up'].className = this.navigationDivs['up'].className.replace(" active","");
-      this.navigationDivs['down'].className = this.navigationDivs['down'].className.replace(" active","");
-    }
-  },
-
-
-  /**
-   * Stop moving in the X direction and unHighlight left and right.
-   * @private
-   */
-  _xStopMoving : function() {
-    this.xIncrement = 0;
-    if (this.navigationDivs) {
-      this.navigationDivs['left'].className = this.navigationDivs['left'].className.replace(" active","");
-      this.navigationDivs['right'].className = this.navigationDivs['right'].className.replace(" active","");
-    }
-  }
-
-
-};
-
-/**
- * Created by Alex on 2/10/14.
- */
-
-
-var graphMixinLoaders = {
-
-  /**
-   * Load a mixin into the graph object
-   *
-   * @param {Object} sourceVariable | this object has to contain functions.
-   * @private
-   */
-  _loadMixin: function (sourceVariable) {
-    for (var mixinFunction in sourceVariable) {
-      if (sourceVariable.hasOwnProperty(mixinFunction)) {
-        Graph.prototype[mixinFunction] = sourceVariable[mixinFunction];
-      }
-    }
-  },
-
-
-  /**
-   * removes a mixin from the graph object.
-   *
-   * @param {Object} sourceVariable | this object has to contain functions.
-   * @private
-   */
-  _clearMixin: function (sourceVariable) {
-    for (var mixinFunction in sourceVariable) {
-      if (sourceVariable.hasOwnProperty(mixinFunction)) {
-        Graph.prototype[mixinFunction] = undefined;
-      }
-    }
-  },
-
-
-  /**
-   * Mixin the physics system and initialize the parameters required.
-   *
-   * @private
-   */
-  _loadPhysicsSystem: function () {
-    this._loadMixin(physicsMixin);
-    this._loadSelectedForceSolver();
-    if (this.constants.configurePhysics == true) {
-      this._loadPhysicsConfiguration();
-    }
-  },
-
-
-  /**
-   * Mixin the cluster system and initialize the parameters required.
-   *
-   * @private
-   */
-  _loadClusterSystem: function () {
-    this.clusterSession = 0;
-    this.hubThreshold = 5;
-    this._loadMixin(ClusterMixin);
-  },
-
-
-  /**
-   * Mixin the sector system and initialize the parameters required
-   *
-   * @private
-   */
-  _loadSectorSystem: function () {
-    this.sectors = {};
-    this.activeSector = ["default"];
-    this.sectors["active"] = {};
-    this.sectors["active"]["default"] = {"nodes": {},
-        "edges": {},
-        "nodeIndices": [],
-        "formationScale": 1.0,
-        "drawingNode": undefined };
-    this.sectors["frozen"] = {};
-      this.sectors["support"] = {"nodes": {},
-        "edges": {},
-        "nodeIndices": [],
-        "formationScale": 1.0,
-        "drawingNode": undefined };
-
-    this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"];  // the node indices list is used to speed up the computation of the repulsion fields
-
-    this._loadMixin(SectorMixin);
-  },
-
-
-  /**
-   * Mixin the selection system and initialize the parameters required
-   *
-   * @private
-   */
-  _loadSelectionSystem: function () {
-    this.selectionObj = {nodes: {}, edges: {}};
-
-    this._loadMixin(SelectionMixin);
-  },
-
-
-  /**
-   * Mixin the navigationUI (User Interface) system and initialize the parameters required
-   *
-   * @private
-   */
-  _loadManipulationSystem: function () {
-    // reset global variables -- these are used by the selection of nodes and edges.
-    this.blockConnectingEdgeSelection = false;
-    this.forceAppendSelection = false;
-
-    if (this.constants.dataManipulation.enabled == true) {
-      // load the manipulator HTML elements. All styling done in css.
-      if (this.manipulationDiv === undefined) {
-        this.manipulationDiv = document.createElement('div');
-        this.manipulationDiv.className = 'graph-manipulationDiv';
-        this.manipulationDiv.id = 'graph-manipulationDiv';
-        if (this.editMode == true) {
-          this.manipulationDiv.style.display = "block";
-        }
-        else {
-          this.manipulationDiv.style.display = "none";
-        }
-        this.containerElement.insertBefore(this.manipulationDiv, this.frame);
-      }
-
-      if (this.editModeDiv === undefined) {
-        this.editModeDiv = document.createElement('div');
-        this.editModeDiv.className = 'graph-manipulation-editMode';
-        this.editModeDiv.id = 'graph-manipulation-editMode';
-        if (this.editMode == true) {
-          this.editModeDiv.style.display = "none";
-        }
-        else {
-          this.editModeDiv.style.display = "block";
-        }
-        this.containerElement.insertBefore(this.editModeDiv, this.frame);
-      }
-
-      if (this.closeDiv === undefined) {
-        this.closeDiv = document.createElement('div');
-        this.closeDiv.className = 'graph-manipulation-closeDiv';
-        this.closeDiv.id = 'graph-manipulation-closeDiv';
-        this.closeDiv.style.display = this.manipulationDiv.style.display;
-        this.containerElement.insertBefore(this.closeDiv, this.frame);
-      }
-
-      // load the manipulation functions
-      this._loadMixin(manipulationMixin);
-
-      // create the manipulator toolbar
-      this._createManipulatorBar();
-    }
-    else {
-      if (this.manipulationDiv !== undefined) {
-        // removes all the bindings and overloads
-        this._createManipulatorBar();
-        // remove the manipulation divs
-        this.containerElement.removeChild(this.manipulationDiv);
-        this.containerElement.removeChild(this.editModeDiv);
-        this.containerElement.removeChild(this.closeDiv);
-
-        this.manipulationDiv = undefined;
-        this.editModeDiv = undefined;
-        this.closeDiv = undefined;
-        // remove the mixin functions
-        this._clearMixin(manipulationMixin);
-      }
-    }
-  },
-
-
-  /**
-   * Mixin the navigation (User Interface) system and initialize the parameters required
-   *
-   * @private
-   */
-  _loadNavigationControls: function () {
-    this._loadMixin(NavigationMixin);
-
-    // the clean function removes the button divs, this is done to remove the bindings.
-    this._cleanNavigation();
-    if (this.constants.navigation.enabled == true) {
-      this._loadNavigationElements();
-    }
-  },
-
-
-  /**
-   * Mixin the hierarchical layout system.
-   *
-   * @private
-   */
-  _loadHierarchySystem: function () {
-    this._loadMixin(HierarchicalLayoutMixin);
-  }
-
-};
-
-/**
- * @constructor Graph
- * Create a graph visualization, displaying nodes and edges.
- *
- * @param {Element} container   The DOM element in which the Graph will
- *                                  be created. Normally a div element.
- * @param {Object} data         An object containing parameters
- *                              {Array} nodes
- *                              {Array} edges
- * @param {Object} options      Options
- */
-function Graph (container, data, options) {
-
-  this._initializeMixinLoaders();
-
-  // create variables and set default values
-  this.containerElement = container;
-  this.width = '100%';
-  this.height = '100%';
-
-  // render and calculation settings
-  this.renderRefreshRate = 60;                         // hz (fps)
-  this.renderTimestep = 1000 / this.renderRefreshRate; // ms -- saves calculation later on
-  this.renderTime = 0.5 * this.renderTimestep;         // measured time it takes to render a frame
-  this.maxPhysicsTicksPerRender = 3;                   // max amount of physics ticks per render step.
-  this.physicsDiscreteStepsize = 0.50;                 // discrete stepsize of the simulation
-
-  this.stabilize = true;  // stabilize before displaying the graph
-  this.selectable = true;
-  this.initializing = true;
-
-  // these functions are triggered when the dataset is edited
-  this.triggerFunctions = {add:null,edit:null,editEdge:null,connect:null,del:null};
-
-  // set constant values
-  this.constants = {
-    nodes: {
-      radiusMin: 5,
-      radiusMax: 20,
-      radius: 5,
-      shape: 'ellipse',
-      image: undefined,
-      widthMin: 16, // px
-      widthMax: 64, // px
-      fixed: false,
-      fontColor: 'black',
-      fontSize: 14, // px
-      fontFace: 'verdana',
-      level: -1,
-      color: {
-          border: '#2B7CE9',
-          background: '#97C2FC',
-        highlight: {
-          border: '#2B7CE9',
-          background: '#D2E5FF'
-        },
-        hover: {
-          border: '#2B7CE9',
-          background: '#D2E5FF'
-        }
-      },
-      borderColor: '#2B7CE9',
-      backgroundColor: '#97C2FC',
-      highlightColor: '#D2E5FF',
-      group: undefined
-    },
-    edges: {
-      widthMin: 1,
-      widthMax: 15,
-      width: 1,
-      hoverWidth: 1.5,
-      style: 'line',
-      color: {
-        color:'#848484',
-        highlight:'#848484',
-        hover: '#848484'
-      },
-      fontColor: '#343434',
-      fontSize: 14, // px
-      fontFace: 'arial',
-      fontFill: 'white',
-      arrowScaleFactor: 1,
-      dash: {
-        length: 10,
-        gap: 5,
-        altLength: undefined
-      }
-    },
-    configurePhysics:false,
-    physics: {
-      barnesHut: {
-        enabled: true,
-        theta: 1 / 0.6, // inverted to save time during calculation
-        gravitationalConstant: -2000,
-        centralGravity: 0.3,
-        springLength: 95,
-        springConstant: 0.04,
-        damping: 0.09
-      },
-      repulsion: {
-        centralGravity: 0.1,
-        springLength: 200,
-        springConstant: 0.05,
-        nodeDistance: 100,
-        damping: 0.09
-      },
-      hierarchicalRepulsion: {
-        enabled: false,
-        centralGravity: 0.0,
-        springLength: 100,
-        springConstant: 0.01,
-        nodeDistance: 60,
-        damping: 0.09
-      },
-      damping: null,
-      centralGravity: null,
-      springLength: null,
-      springConstant: null
-    },
-    clustering: {                   // Per Node in Cluster = PNiC
-      enabled: false,               // (Boolean)             | global on/off switch for clustering.
-      initialMaxNodes: 100,         // (# nodes)             | if the initial amount of nodes is larger than this, we cluster until the total number is less than this threshold.
-      clusterThreshold:500,         // (# nodes)             | during calculate forces, we check if the total number of nodes is larger than this. If it is, cluster until reduced to reduceToNodes
-      reduceToNodes:300,            // (# nodes)             | during calculate forces, we check if the total number of nodes is larger than clusterThreshold. If it is, cluster until reduced to this
-      chainThreshold: 0.4,          // (% of all drawn nodes)| maximum percentage of allowed chainnodes (long strings of connected nodes) within all nodes. (lower means less chains).
-      clusterEdgeThreshold: 20,     // (px)                  | edge length threshold. if smaller, this node is clustered.
-      sectorThreshold: 100,         // (# nodes in cluster)  | cluster size threshold. If larger, expanding in own sector.
-      screenSizeThreshold: 0.2,     // (% of canvas)         | relative size threshold. If the width or height of a clusternode takes up this much of the screen, decluster node.
-      fontSizeMultiplier: 4.0,      // (px PNiC)             | how much the cluster font size grows per node in cluster (in px).
-      maxFontSize: 1000,
-      forceAmplification: 0.1,      // (multiplier PNiC)     | factor of increase fo the repulsion force of a cluster (per node in cluster).
-      distanceAmplification: 0.1,   // (multiplier PNiC)     | factor how much the repulsion distance of a cluster increases (per node in cluster).
-      edgeGrowth: 20,               // (px PNiC)             | amount of clusterSize connected to the edge is multiplied with this and added to edgeLength.
-      nodeScaling: {width:  1,      // (px PNiC)             | growth of the width  per node in cluster.
-                    height: 1,      // (px PNiC)             | growth of the height per node in cluster.
-                    radius: 1},     // (px PNiC)             | growth of the radius per node in cluster.
-      maxNodeSizeIncrements: 600,   // (# increments)        | max growth of the width  per node in cluster.
-      activeAreaBoxSize: 80,       // (px)                  | box area around the curser where clusters are popped open.
-      clusterLevelDifference: 2
-    },
-    navigation: {
-      enabled: false
-    },
-    keyboard: {
-      enabled: false,
-      speed: {x: 10, y: 10, zoom: 0.02}
-    },
-    dataManipulation: {
-      enabled: false,
-      initiallyVisible: false
-    },
-    hierarchicalLayout: {
-      enabled:false,
-      levelSeparation: 150,
-      nodeSpacing: 100,
-      direction: "UD"   // UD, DU, LR, RL
-    },
-    freezeForStabilization: false,
-    smoothCurves: true,
-    maxVelocity:  10,
-    minVelocity:  0.1,   // px/s
-    stabilizationIterations: 1000,  // maximum number of iteration to stabilize
-    labels:{
-      add:"Add Node",
-      edit:"Edit",
-      link:"Add Link",
-      del:"Delete selected",
-      editNode:"Edit Node",
-      editEdge:"Edit Edge",
-      back:"Back",
-      addDescription:"Click in an empty space to place a new node.",
-      linkDescription:"Click on a node and drag the edge to another node to connect them.",
-      editEdgeDescription:"Click on the control points and drag them to a node to connect to it.",
-      addError:"The function for add does not support two arguments (data,callback).",
-      linkError:"The function for connect does not support two arguments (data,callback).",
-      editError:"The function for edit does not support two arguments (data, callback).",
-      editBoundError:"No edit function has been bound to this button.",
-      deleteError:"The function for delete does not support two arguments (data, callback).",
-      deleteClusterError:"Clusters cannot be deleted."
-    },
-    tooltip: {
-      delay: 300,
-      fontColor: 'black',
-      fontSize: 14, // px
-      fontFace: 'verdana',
-      color: {
-        border: '#666',
-        background: '#FFFFC6'
-      }
-    },
-    dragGraph: true,
-    dragNodes: true,
-    zoomable: true,
-    hover: false
-  };
-  this.hoverObj = {nodes:{},edges:{}};
-
-
-  // Node variables
-  var graph = this;
-  this.groups = new Groups(); // object with groups
-  this.images = new Images(); // object with images
-  this.images.setOnloadCallback(function () {
-    graph._redraw();
-  });
-
-  // keyboard navigation variables
-  this.xIncrement = 0;
-  this.yIncrement = 0;
-  this.zoomIncrement = 0;
-
-  // loading all the mixins:
-  // load the force calculation functions, grouped under the physics system.
-  this._loadPhysicsSystem();
-  // create a frame and canvas
-  this._create();
-  // load the sector system.    (mandatory, fully integrated with Graph)
-  this._loadSectorSystem();
-  // load the cluster system.   (mandatory, even when not using the cluster system, there are function calls to it)
-  this._loadClusterSystem();
-  // load the selection system. (mandatory, required by Graph)
-  this._loadSelectionSystem();
-  // load the selection system. (mandatory, required by Graph)
-  this._loadHierarchySystem();
-
-  // apply options
-  this._setTranslation(this.frame.clientWidth / 2, this.frame.clientHeight / 2);
-  this._setScale(1);
-  this.setOptions(options);
-
-  // other vars
-  this.freezeSimulation = false;// freeze the simulation
-  this.cachedFunctions = {};
-
-  // containers for nodes and edges
-  this.calculationNodes = {};
-  this.calculationNodeIndices = [];
-  this.nodeIndices = [];        // array with all the indices of the nodes. Used to speed up forces calculation
-  this.nodes = {};              // object with Node objects
-  this.edges = {};              // object with Edge objects
-
-  // position and scale variables and objects
-  this.canvasTopLeft     = {"x": 0,"y": 0};   // coordinates of the top left of the canvas.     they will be set during _redraw.
-  this.canvasBottomRight = {"x": 0,"y": 0};   // coordinates of the bottom right of the canvas. they will be set during _redraw
-  this.pointerPosition = {"x": 0,"y": 0};   // coordinates of the bottom right of the canvas. they will be set during _redraw
-  this.areaCenter = {};               // object with x and y elements used for determining the center of the zoom action
-  this.scale = 1;                     // defining the global scale variable in the constructor
-  this.previousScale = this.scale;    // this is used to check if the zoom operation is zooming in or out
-
-  // datasets or dataviews
-  this.nodesData = null;      // A DataSet or DataView
-  this.edgesData = null;      // A DataSet or DataView
-
-  // create event listeners used to subscribe on the DataSets of the nodes and edges
-  this.nodesListeners = {
-    'add': function (event, params) {
-      graph._addNodes(params.items);
-      graph.start();
-    },
-    'update': function (event, params) {
-      graph._updateNodes(params.items);
-      graph.start();
-    },
-    'remove': function (event, params) {
-      graph._removeNodes(params.items);
-      graph.start();
-    }
-  };
-  this.edgesListeners = {
-    'add': function (event, params) {
-      graph._addEdges(params.items);
-      graph.start();
-    },
-    'update': function (event, params) {
-      graph._updateEdges(params.items);
-      graph.start();
-    },
-    'remove': function (event, params) {
-      graph._removeEdges(params.items);
-      graph.start();
-    }
-  };
-
-  // properties for the animation
-  this.moving = true;
-  this.timer = undefined; // Scheduling function. Is definded in this.start();
-
-  // load data (the disable start variable will be the same as the enabled clustering)
-  this.setData(data,this.constants.clustering.enabled || this.constants.hierarchicalLayout.enabled);
-
-  // hierarchical layout
-  this.initializing = false;
-  if (this.constants.hierarchicalLayout.enabled == true) {
-    this._setupHierarchicalLayout();
-  }
-  else {
-    // zoom so all data will fit on the screen, if clustering is enabled, we do not want start to be called here.
-    if (this.stabilize == false) {
-      this.zoomExtent(true,this.constants.clustering.enabled);
-    }
-  }
-
-  // if clustering is disabled, the simulation will have started in the setData function
-  if (this.constants.clustering.enabled) {
-    this.startWithClustering();
-  }
-}
-
-// Extend Graph with an Emitter mixin
-Emitter(Graph.prototype);
-
-/**
- * Get the script path where the vis.js library is located
- *
- * @returns {string | null} path   Path or null when not found. Path does not
- *                                 end with a slash.
- * @private
- */
-Graph.prototype._getScriptPath = function() {
-  var scripts = document.getElementsByTagName( 'script' );
-
-  // find script named vis.js or vis.min.js
-  for (var i = 0; i < scripts.length; i++) {
-    var src = scripts[i].src;
-    var match = src && /\/?vis(.min)?\.js$/.exec(src);
-    if (match) {
-      // return path without the script name
-      return src.substring(0, src.length - match[0].length);
-    }
-  }
-
-  return null;
-};
-
-
-/**
- * Find the center position of the graph
- * @private
- */
-Graph.prototype._getRange = function() {
-  var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node;
-  for (var nodeId in this.nodes) {
-    if (this.nodes.hasOwnProperty(nodeId)) {
-      node = this.nodes[nodeId];
-      if (minX > (node.x)) {minX = node.x;}
-      if (maxX < (node.x)) {maxX = node.x;}
-      if (minY > (node.y)) {minY = node.y;}
-      if (maxY < (node.y)) {maxY = node.y;}
-    }
-  }
-  if (minX == 1e9 && maxX == -1e9 && minY == 1e9 && maxY == -1e9) {
-    minY = 0, maxY = 0, minX = 0, maxX = 0;
-  }
-  return {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
-};
-
-
-/**
- * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
- * @returns {{x: number, y: number}}
- * @private
- */
-Graph.prototype._findCenter = function(range) {
-  return {x: (0.5 * (range.maxX + range.minX)),
-          y: (0.5 * (range.maxY + range.minY))};
-};
-
-
-/**
- * center the graph
- *
- * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
- */
-Graph.prototype._centerGraph = function(range) {
-  var center = this._findCenter(range);
-
-  center.x *= this.scale;
-  center.y *= this.scale;
-  center.x -= 0.5 * this.frame.canvas.clientWidth;
-  center.y -= 0.5 * this.frame.canvas.clientHeight;
-
-  this._setTranslation(-center.x,-center.y); // set at 0,0
-};
-
-
-/**
- * This function zooms out to fit all data on screen based on amount of nodes
- *
- * @param {Boolean} [initialZoom]  | zoom based on fitted formula or range, true = fitted, default = false;
- * @param {Boolean} [disableStart] | If true, start is not called.
- */
-Graph.prototype.zoomExtent = function(initialZoom, disableStart) {
-  if (initialZoom === undefined) {
-    initialZoom = false;
-  }
-  if (disableStart === undefined) {
-    disableStart = false;
-  }
-
-  var range = this._getRange();
-  var zoomLevel;
-
-  if (initialZoom == true) {
-    var numberOfNodes = this.nodeIndices.length;
-    if (this.constants.smoothCurves == true) {
-      if (this.constants.clustering.enabled == true &&
-        numberOfNodes >= this.constants.clustering.initialMaxNodes) {
-        zoomLevel = 49.07548 / (numberOfNodes + 142.05338) + 9.1444e-04; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
-      }
-      else {
-        zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
-      }
-    }
-    else {
-      if (this.constants.clustering.enabled == true &&
-          numberOfNodes >= this.constants.clustering.initialMaxNodes) {
-        zoomLevel = 77.5271985 / (numberOfNodes + 187.266146) + 4.76710517e-05; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
-      }
-      else {
-        zoomLevel = 30.5062972 / (numberOfNodes + 19.93597763) + 0.08413486; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
-      }
-    }
-
-    // correct for larger canvasses.
-    var factor = Math.min(this.frame.canvas.clientWidth / 600, this.frame.canvas.clientHeight / 600);
-    zoomLevel *= factor;
-  }
-  else {
-    var xDistance = (Math.abs(range.minX) + Math.abs(range.maxX)) * 1.1;
-    var yDistance = (Math.abs(range.minY) + Math.abs(range.maxY)) * 1.1;
-
-    var xZoomLevel = this.frame.canvas.clientWidth / xDistance;
-    var yZoomLevel = this.frame.canvas.clientHeight / yDistance;
-
-    zoomLevel = (xZoomLevel <= yZoomLevel) ? xZoomLevel : yZoomLevel;
-  }
-
-  if (zoomLevel > 1.0) {
-    zoomLevel = 1.0;
-  }
-
-
-  this._setScale(zoomLevel);
-  this._centerGraph(range);
-  if (disableStart == false) {
-    this.moving = true;
-    this.start();
-  }
-};
-
-
-/**
- * Update the this.nodeIndices with the most recent node index list
- * @private
- */
-Graph.prototype._updateNodeIndexList = function() {
-  this._clearNodeIndexList();
-  for (var idx in this.nodes) {
-    if (this.nodes.hasOwnProperty(idx)) {
-      this.nodeIndices.push(idx);
-    }
-  }
-};
-
-
-/**
- * Set nodes and edges, and optionally options as well.
- *
- * @param {Object} data              Object containing parameters:
- *                                   {Array | DataSet | DataView} [nodes] Array with nodes
- *                                   {Array | DataSet | DataView} [edges] Array with edges
- *                                   {String} [dot] String containing data in DOT format
- *                                   {Options} [options] Object with options
- * @param {Boolean} [disableStart]   | optional: disable the calling of the start function.
- */
-Graph.prototype.setData = function(data, disableStart) {
-  if (disableStart === undefined) {
-    disableStart = false;
-  }
-
-  if (data && data.dot && (data.nodes || data.edges)) {
-    throw new SyntaxError('Data must contain either parameter "dot" or ' +
-        ' parameter pair "nodes" and "edges", but not both.');
-  }
-
-  // set options
-  this.setOptions(data && data.options);
-
-  // set all data
-  if (data && data.dot) {
-    // parse DOT file
-    if(data && data.dot) {
-      var dotData = vis.util.DOTToGraph(data.dot);
-      this.setData(dotData);
-      return;
-    }
-  }
-  else {
-    this._setNodes(data && data.nodes);
-    this._setEdges(data && data.edges);
-  }
-
-  this._putDataInSector();
-
-  if (!disableStart) {
-    // find a stable position or start animating to a stable position
-    if (this.stabilize) {
-      var me = this;
-      setTimeout(function() {me._stabilize(); me.start();},0)
-    }
-    else {
-      this.start();
-    }
-  }
-};
-
-/**
- * Set options
- * @param {Object} options
- * @param {Boolean} [initializeView] | set zoom and translation to default.
- */
-Graph.prototype.setOptions = function (options) {
-  if (options) {
-    var prop;
-    // retrieve parameter values
-    if (options.width !== undefined)           {this.width = options.width;}
-    if (options.height !== undefined)          {this.height = options.height;}
-    if (options.stabilize !== undefined)       {this.stabilize = options.stabilize;}
-    if (options.selectable !== undefined)      {this.selectable = options.selectable;}
-    if (options.smoothCurves !== undefined)    {this.constants.smoothCurves = options.smoothCurves;}
-    if (options.freezeForStabilization !== undefined)    {this.constants.freezeForStabilization = options.freezeForStabilization;}
-    if (options.configurePhysics !== undefined){this.constants.configurePhysics = options.configurePhysics;}
-    if (options.stabilizationIterations !== undefined)   {this.constants.stabilizationIterations = options.stabilizationIterations;}
-    if (options.dragGraph !== undefined)       {this.constants.dragGraph = options.dragGraph;}
-    if (options.dragNodes !== undefined)       {this.constants.dragNodes = options.dragNodes;}
-    if (options.zoomable !== undefined)        {this.constants.zoomable = options.zoomable;}
-    if (options.hover !== undefined)           {this.constants.hover = options.hover;}
-
-    if (options.labels !== undefined)  {
-      for (prop in options.labels) {
-        if (options.labels.hasOwnProperty(prop)) {
-          this.constants.labels[prop] = options.labels[prop];
-        }
-      }
-    }
-
-    if (options.onAdd) {
-        this.triggerFunctions.add = options.onAdd;
-      }
-
-    if (options.onEdit) {
-      this.triggerFunctions.edit = options.onEdit;
-    }
-
-    if (options.onEditEdge) {
-      this.triggerFunctions.editEdge = options.onEditEdge;
-    }
-
-    if (options.onConnect) {
-      this.triggerFunctions.connect = options.onConnect;
-    }
-
-    if (options.onDelete) {
-      this.triggerFunctions.del = options.onDelete;
-    }
-
-    if (options.physics) {
-      if (options.physics.barnesHut) {
-        this.constants.physics.barnesHut.enabled = true;
-        for (prop in options.physics.barnesHut) {
-          if (options.physics.barnesHut.hasOwnProperty(prop)) {
-            this.constants.physics.barnesHut[prop] = options.physics.barnesHut[prop];
-          }
-        }
-      }
-
-      if (options.physics.repulsion) {
-        this.constants.physics.barnesHut.enabled = false;
-        for (prop in options.physics.repulsion) {
-          if (options.physics.repulsion.hasOwnProperty(prop)) {
-            this.constants.physics.repulsion[prop] = options.physics.repulsion[prop];
-          }
-        }
-      }
-
-      if (options.physics.hierarchicalRepulsion) {
-        this.constants.hierarchicalLayout.enabled = true;
-        this.constants.physics.hierarchicalRepulsion.enabled = true;
-        this.constants.physics.barnesHut.enabled = false;
-        for (prop in options.physics.hierarchicalRepulsion) {
-          if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) {
-            this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop];
-          }
-        }
-      }
-    }
-
-    if (options.hierarchicalLayout) {
-      this.constants.hierarchicalLayout.enabled = true;
-      for (prop in options.hierarchicalLayout) {
-        if (options.hierarchicalLayout.hasOwnProperty(prop)) {
-          this.constants.hierarchicalLayout[prop] = options.hierarchicalLayout[prop];
-        }
-      }
-    }
-    else if (options.hierarchicalLayout !== undefined)  {
-      this.constants.hierarchicalLayout.enabled = false;
-    }
-
-    if (options.clustering) {
-      this.constants.clustering.enabled = true;
-      for (prop in options.clustering) {
-        if (options.clustering.hasOwnProperty(prop)) {
-          this.constants.clustering[prop] = options.clustering[prop];
-        }
-      }
-    }
-    else if (options.clustering !== undefined)  {
-      this.constants.clustering.enabled = false;
-    }
-
-    if (options.navigation) {
-      this.constants.navigation.enabled = true;
-      for (prop in options.navigation) {
-        if (options.navigation.hasOwnProperty(prop)) {
-          this.constants.navigation[prop] = options.navigation[prop];
-        }
-      }
-    }
-    else if (options.navigation !== undefined) {
-      this.constants.navigation.enabled = false;
-    }
-
-    if (options.keyboard) {
-      this.constants.keyboard.enabled = true;
-      for (prop in options.keyboard) {
-        if (options.keyboard.hasOwnProperty(prop)) {
-          this.constants.keyboard[prop] = options.keyboard[prop];
-        }
-      }
-    }
-    else if (options.keyboard !== undefined)  {
-      this.constants.keyboard.enabled = false;
-    }
-
-    if (options.dataManipulation) {
-      this.constants.dataManipulation.enabled = true;
-      for (prop in options.dataManipulation) {
-        if (options.dataManipulation.hasOwnProperty(prop)) {
-          this.constants.dataManipulation[prop] = options.dataManipulation[prop];
-        }
-      }
-      this.editMode = this.constants.dataManipulation.initiallyVisible;
-    }
-    else if (options.dataManipulation !== undefined)  {
-      this.constants.dataManipulation.enabled = false;
-    }
-
-    // TODO: work out these options and document them
-    if (options.edges) {
-      for (prop in options.edges) {
-        if (options.edges.hasOwnProperty(prop)) {
-          if (typeof options.edges[prop] != "object") {
-            this.constants.edges[prop] = options.edges[prop];
-          }
-        }
-      }
-
-
-      if (options.edges.color !== undefined) {
-        if (util.isString(options.edges.color)) {
-          this.constants.edges.color = {};
-          this.constants.edges.color.color = options.edges.color;
-          this.constants.edges.color.highlight = options.edges.color;
-          this.constants.edges.color.hover = options.edges.color;
-        }
-        else {
-          if (options.edges.color.color !== undefined)     {this.constants.edges.color.color = options.edges.color.color;}
-          if (options.edges.color.highlight !== undefined) {this.constants.edges.color.highlight = options.edges.color.highlight;}
-          if (options.edges.color.hover !== undefined)     {this.constants.edges.color.hover = options.edges.color.hover;}
-        }
-      }
-
-      if (!options.edges.fontColor) {
-        if (options.edges.color !== undefined) {
-          if (util.isString(options.edges.color))           {this.constants.edges.fontColor = options.edges.color;}
-          else if (options.edges.color.color !== undefined) {this.constants.edges.fontColor = options.edges.color.color;}
-        }
-      }
-
-      // Added to support dashed lines
-      // David Jordan
-      // 2012-08-08
-      if (options.edges.dash) {
-        if (options.edges.dash.length !== undefined) {
-          this.constants.edges.dash.length = options.edges.dash.length;
-        }
-        if (options.edges.dash.gap !== undefined) {
-          this.constants.edges.dash.gap = options.edges.dash.gap;
-        }
-        if (options.edges.dash.altLength !== undefined) {
-          this.constants.edges.dash.altLength = options.edges.dash.altLength;
-        }
-      }
-    }
-
-    if (options.nodes) {
-      for (prop in options.nodes) {
-        if (options.nodes.hasOwnProperty(prop)) {
-          this.constants.nodes[prop] = options.nodes[prop];
-        }
-      }
-
-      if (options.nodes.color) {
-        this.constants.nodes.color = util.parseColor(options.nodes.color);
-      }
-
-      /*
-       if (options.nodes.widthMin) this.constants.nodes.radiusMin = options.nodes.widthMin;
-       if (options.nodes.widthMax) this.constants.nodes.radiusMax = options.nodes.widthMax;
-       */
-    }
-    if (options.groups) {
-      for (var groupname in options.groups) {
-        if (options.groups.hasOwnProperty(groupname)) {
-          var group = options.groups[groupname];
-          this.groups.add(groupname, group);
-        }
-      }
-    }
-
-    if (options.tooltip) {
-      for (prop in options.tooltip) {
-        if (options.tooltip.hasOwnProperty(prop)) {
-          this.constants.tooltip[prop] = options.tooltip[prop];
-        }
-      }
-      if (options.tooltip.color) {
-        this.constants.tooltip.color = util.parseColor(options.tooltip.color);
-      }
-    }
-  }
-
-
-  // (Re)loading the mixins that can be enabled or disabled in the options.
-  // load the force calculation functions, grouped under the physics system.
-  this._loadPhysicsSystem();
-  // load the navigation system.
-  this._loadNavigationControls();
-  // load the data manipulation system
-  this._loadManipulationSystem();
-  // configure the smooth curves
-  this._configureSmoothCurves();
-
-
-  // bind keys. If disabled, this will not do anything;
-  this._createKeyBinds();
-  this.setSize(this.width, this.height);
-  this.moving = true;
-  this.start();
-
-};
-
-/**
- * Create the main frame for the Graph.
- * This function is executed once when a Graph object is created. The frame
- * contains a canvas, and this canvas contains all objects like the axis and
- * nodes.
- * @private
- */
-Graph.prototype._create = function () {
-  // remove all elements from the container element.
-  while (this.containerElement.hasChildNodes()) {
-    this.containerElement.removeChild(this.containerElement.firstChild);
-  }
-
-  this.frame = document.createElement('div');
-  this.frame.className = 'graph-frame';
-  this.frame.style.position = 'relative';
-  this.frame.style.overflow = 'hidden';
-
-  // create the graph canvas (HTML canvas element)
-  this.frame.canvas = document.createElement( 'canvas' );
-  this.frame.canvas.style.position = 'relative';
-  this.frame.appendChild(this.frame.canvas);
-  if (!this.frame.canvas.getContext) {
-    var noCanvas = document.createElement( 'DIV' );
-    noCanvas.style.color = 'red';
-    noCanvas.style.fontWeight =  'bold' ;
-    noCanvas.style.padding =  '10px';
-    noCanvas.innerHTML =  'Error: your browser does not support HTML canvas';
-    this.frame.canvas.appendChild(noCanvas);
-  }
-
-  var me = this;
-  this.drag = {};
-  this.pinch = {};
-  this.hammer = Hammer(this.frame.canvas, {
-    prevent_default: true
-  });
-  this.hammer.on('tap',       me._onTap.bind(me) );
-  this.hammer.on('doubletap', me._onDoubleTap.bind(me) );
-  this.hammer.on('hold',      me._onHold.bind(me) );
-  this.hammer.on('pinch',     me._onPinch.bind(me) );
-  this.hammer.on('touch',     me._onTouch.bind(me) );
-  this.hammer.on('dragstart', me._onDragStart.bind(me) );
-  this.hammer.on('drag',      me._onDrag.bind(me) );
-  this.hammer.on('dragend',   me._onDragEnd.bind(me) );
-  this.hammer.on('release',   me._onRelease.bind(me) );
-  this.hammer.on('mousewheel',me._onMouseWheel.bind(me) );
-  this.hammer.on('DOMMouseScroll',me._onMouseWheel.bind(me) ); // for FF
-  this.hammer.on('mousemove', me._onMouseMoveTitle.bind(me) );
-
-  // add the frame to the container element
-  this.containerElement.appendChild(this.frame);
-
-};
-
-
-/**
- * Binding the keys for keyboard navigation. These functions are defined in the NavigationMixin
- * @private
- */
-Graph.prototype._createKeyBinds = function() {
-  var me = this;
-  this.mousetrap = mousetrap;
-
-  this.mousetrap.reset();
-
-  if (this.constants.keyboard.enabled == true) {
-    this.mousetrap.bind("up",   this._moveUp.bind(me)   , "keydown");
-    this.mousetrap.bind("up",   this._yStopMoving.bind(me), "keyup");
-    this.mousetrap.bind("down", this._moveDown.bind(me) , "keydown");
-    this.mousetrap.bind("down", this._yStopMoving.bind(me), "keyup");
-    this.mousetrap.bind("left", this._moveLeft.bind(me) , "keydown");
-    this.mousetrap.bind("left", this._xStopMoving.bind(me), "keyup");
-    this.mousetrap.bind("right",this._moveRight.bind(me), "keydown");
-    this.mousetrap.bind("right",this._xStopMoving.bind(me), "keyup");
-    this.mousetrap.bind("=",    this._zoomIn.bind(me),    "keydown");
-    this.mousetrap.bind("=",    this._stopZoom.bind(me),    "keyup");
-    this.mousetrap.bind("-",    this._zoomOut.bind(me),   "keydown");
-    this.mousetrap.bind("-",    this._stopZoom.bind(me),    "keyup");
-    this.mousetrap.bind("[",    this._zoomIn.bind(me),    "keydown");
-    this.mousetrap.bind("[",    this._stopZoom.bind(me),    "keyup");
-    this.mousetrap.bind("]",    this._zoomOut.bind(me),   "keydown");
-    this.mousetrap.bind("]",    this._stopZoom.bind(me),    "keyup");
-    this.mousetrap.bind("pageup",this._zoomIn.bind(me),   "keydown");
-    this.mousetrap.bind("pageup",this._stopZoom.bind(me),   "keyup");
-    this.mousetrap.bind("pagedown",this._zoomOut.bind(me),"keydown");
-    this.mousetrap.bind("pagedown",this._stopZoom.bind(me), "keyup");
-  }
-
-  if (this.constants.dataManipulation.enabled == true) {
-    this.mousetrap.bind("escape",this._createManipulatorBar.bind(me));
-    this.mousetrap.bind("del",this._deleteSelected.bind(me));
-  }
-};
-
-/**
- * Get the pointer location from a touch location
- * @param {{pageX: Number, pageY: Number}} touch
- * @return {{x: Number, y: Number}} pointer
- * @private
- */
-Graph.prototype._getPointer = function (touch) {
-  return {
-    x: touch.pageX - vis.util.getAbsoluteLeft(this.frame.canvas),
-    y: touch.pageY - vis.util.getAbsoluteTop(this.frame.canvas)
-  };
-};
-
-/**
- * On start of a touch gesture, store the pointer
- * @param event
- * @private
- */
-Graph.prototype._onTouch = function (event) {
-  this.drag.pointer = this._getPointer(event.gesture.center);
-  this.drag.pinched = false;
-  this.pinch.scale = this._getScale();
-
-  this._handleTouch(this.drag.pointer);
-};
-
-/**
- * handle drag start event
- * @private
- */
-Graph.prototype._onDragStart = function () {
-  this._handleDragStart();
-};
-
-
-/**
- * This function is called by _onDragStart.
- * It is separated out because we can then overload it for the datamanipulation system.
- *
- * @private
- */
-Graph.prototype._handleDragStart = function() {
-  var drag = this.drag;
-  var node = this._getNodeAt(drag.pointer);
-  // note: drag.pointer is set in _onTouch to get the initial touch location
-
-  drag.dragging = true;
-  drag.selection = [];
-  drag.translation = this._getTranslation();
-  drag.nodeId = null;
-
-  if (node != null) {
-    drag.nodeId = node.id;
-    // select the clicked node if not yet selected
-    if (!node.isSelected()) {
-      this._selectObject(node,false);
-    }
-
-    // create an array with the selected nodes and their original location and status
-    for (var objectId in this.selectionObj.nodes) {
-      if (this.selectionObj.nodes.hasOwnProperty(objectId)) {
-        var object = this.selectionObj.nodes[objectId];
-        var s = {
-          id: object.id,
-          node: object,
-
-          // store original x, y, xFixed and yFixed, make the node temporarily Fixed
-          x: object.x,
-          y: object.y,
-          xFixed: object.xFixed,
-          yFixed: object.yFixed
-        };
-
-        object.xFixed = true;
-        object.yFixed = true;
-
-        drag.selection.push(s);
-      }
-    }
-  }
-};
-
-
-/**
- * handle drag event
- * @private
- */
-Graph.prototype._onDrag = function (event) {
-  this._handleOnDrag(event)
-};
-
-
-/**
- * This function is called by _onDrag.
- * It is separated out because we can then overload it for the datamanipulation system.
- *
- * @private
- */
-Graph.prototype._handleOnDrag = function(event) {
-  if (this.drag.pinched) {
-    return;
-  }
-
-  var pointer = this._getPointer(event.gesture.center);
-
-  var me = this,
-    drag = this.drag,
-    selection = drag.selection;
-  if (selection && selection.length && this.constants.dragNodes == true) {
-    // calculate delta's and new location
-    var deltaX = pointer.x - drag.pointer.x,
-      deltaY = pointer.y - drag.pointer.y;
-
-    // update position of all selected nodes
-    selection.forEach(function (s) {
-      var node = s.node;
-
-      if (!s.xFixed) {
-        node.x = me._XconvertDOMtoCanvas(me._XconvertCanvasToDOM(s.x) + deltaX);
-      }
-
-      if (!s.yFixed) {
-        node.y = me._YconvertDOMtoCanvas(me._YconvertCanvasToDOM(s.y) + deltaY);
-      }
-    });
-
-    // start _animationStep if not yet running
-    if (!this.moving) {
-      this.moving = true;
-      this.start();
-    }
-  }
-  else {
-    if (this.constants.dragGraph == true) {
-      // move the graph
-      var diffX = pointer.x - this.drag.pointer.x;
-      var diffY = pointer.y - this.drag.pointer.y;
-
-      this._setTranslation(
-        this.drag.translation.x + diffX,
-        this.drag.translation.y + diffY);
-      this._redraw();
-      this.moving = true;
-      this.start();
-    }
-  }
-};
-
-/**
- * handle drag start event
- * @private
- */
-Graph.prototype._onDragEnd = function () {
-  this.drag.dragging = false;
-  var selection = this.drag.selection;
-  if (selection) {
-    selection.forEach(function (s) {
-      // restore original xFixed and yFixed
-      s.node.xFixed = s.xFixed;
-      s.node.yFixed = s.yFixed;
-    });
-  }
-};
-
-/**
- * handle tap/click event: select/unselect a node
- * @private
- */
-Graph.prototype._onTap = function (event) {
-  var pointer = this._getPointer(event.gesture.center);
-  this.pointerPosition = pointer;
-  this._handleTap(pointer);
-
-};
-
-
-/**
- * handle doubletap event
- * @private
- */
-Graph.prototype._onDoubleTap = function (event) {
-  var pointer = this._getPointer(event.gesture.center);
-  this._handleDoubleTap(pointer);
-};
-
-
-/**
- * handle long tap event: multi select nodes
- * @private
- */
-Graph.prototype._onHold = function (event) {
-  var pointer = this._getPointer(event.gesture.center);
-  this.pointerPosition = pointer;
-  this._handleOnHold(pointer);
-};
-
-/**
- * handle the release of the screen
- *
- * @private
- */
-Graph.prototype._onRelease = function (event) {
-  var pointer = this._getPointer(event.gesture.center);
-  this._handleOnRelease(pointer);
-};
-
-/**
- * Handle pinch event
- * @param event
- * @private
- */
-Graph.prototype._onPinch = function (event) {
-  var pointer = this._getPointer(event.gesture.center);
-
-  this.drag.pinched = true;
-  if (!('scale' in this.pinch)) {
-    this.pinch.scale = 1;
-  }
-
-  // TODO: enabled moving while pinching?
-  var scale = this.pinch.scale * event.gesture.scale;
-  this._zoom(scale, pointer)
-};
-
-/**
- * Zoom the graph in or out
- * @param {Number} scale a number around 1, and between 0.01 and 10
- * @param {{x: Number, y: Number}} pointer    Position on screen
- * @return {Number} appliedScale    scale is limited within the boundaries
- * @private
- */
-Graph.prototype._zoom = function(scale, pointer) {
-  if (this.constants.zoomable == true) {
-    var scaleOld = this._getScale();
-    if (scale < 0.00001) {
-      scale = 0.00001;
-    }
-    if (scale > 10) {
-      scale = 10;
-    }
-  // + this.frame.canvas.clientHeight / 2
-    var translation = this._getTranslation();
-
-    var scaleFrac = scale / scaleOld;
-    var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
-    var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
-
-    this.areaCenter = {"x" : this._XconvertDOMtoCanvas(pointer.x),
-                       "y" : this._YconvertDOMtoCanvas(pointer.y)};
-
-    this._setScale(scale);
-    this._setTranslation(tx, ty);
-    this.updateClustersDefault();
-    this._redraw();
-
-    if (scaleOld < scale) {
-      this.emit("zoom", {direction:"+"});
-    }
-    else {
-      this.emit("zoom", {direction:"-"});
-    }
-
-    return scale;
-  }
-};
-
-
-/**
- * Event handler for mouse wheel event, used to zoom the timeline
- * See http://adomas.org/javascript-mouse-wheel/
- *     https://github.com/EightMedia/hammer.js/issues/256
- * @param {MouseEvent}  event
- * @private
- */
-Graph.prototype._onMouseWheel = function(event) {
-  // retrieve delta
-  var delta = 0;
-  if (event.wheelDelta) { /* IE/Opera. */
-    delta = event.wheelDelta/120;
-  } else if (event.detail) { /* Mozilla case. */
-    // In Mozilla, sign of delta is different than in IE.
-    // Also, delta is multiple of 3.
-    delta = -event.detail/3;
-  }
-
-  // If delta is nonzero, handle it.
-  // Basically, delta is now positive if wheel was scrolled up,
-  // and negative, if wheel was scrolled down.
-  if (delta) {
-
-    // calculate the new scale
-    var scale = this._getScale();
-    var zoom = delta / 10;
-    if (delta < 0) {
-      zoom = zoom / (1 - zoom);
-    }
-    scale *= (1 + zoom);
-
-    // calculate the pointer location
-    var gesture = util.fakeGesture(this, event);
-    var pointer = this._getPointer(gesture.center);
-
-    // apply the new scale
-    this._zoom(scale, pointer);
-  }
-
-  // Prevent default actions caused by mouse wheel.
-  event.preventDefault();
-};
-
-
-/**
- * Mouse move handler for checking whether the title moves over a node with a title.
- * @param  {Event} event
- * @private
- */
-Graph.prototype._onMouseMoveTitle = function (event) {
-  var gesture = util.fakeGesture(this, event);
-  var pointer = this._getPointer(gesture.center);
-
-  // check if the previously selected node is still selected
-  if (this.popupObj) {
-    this._checkHidePopup(pointer);
-  }
-
-  // start a timeout that will check if the mouse is positioned above
-  // an element
-  var me = this;
-  var checkShow = function() {
-    me._checkShowPopup(pointer);
-  };
-  if (this.popupTimer) {
-    clearInterval(this.popupTimer); // stop any running calculationTimer
-  }
-  if (!this.drag.dragging) {
-    this.popupTimer = setTimeout(checkShow, this.constants.tooltip.delay);
-  }
-
-
-  /**
-   * Adding hover highlights
-   */
-  if (this.constants.hover == true) {
-    // removing all hover highlights
-    for (var edgeId in this.hoverObj.edges) {
-      if (this.hoverObj.edges.hasOwnProperty(edgeId)) {
-        this.hoverObj.edges[edgeId].hover = false;
-        delete this.hoverObj.edges[edgeId];
-      }
-    }
-
-    // adding hover highlights
-    var obj = this._getNodeAt(pointer);
-    if (obj == null) {
-      obj = this._getEdgeAt(pointer);
-    }
-    if (obj != null) {
-      this._hoverObject(obj);
-    }
-
-    // removing all node hover highlights except for the selected one.
-    for (var nodeId in this.hoverObj.nodes) {
-      if (this.hoverObj.nodes.hasOwnProperty(nodeId)) {
-        if (obj instanceof Node && obj.id != nodeId || obj instanceof Edge || obj == null) {
-          this._blurObject(this.hoverObj.nodes[nodeId]);
-          delete this.hoverObj.nodes[nodeId];
-        }
-      }
-    }
-    this.redraw();
-  }
-};
-
-/**
- * Check if there is an element on the given position in the graph
- * (a node or edge). If so, and if this element has a title,
- * show a popup window with its title.
- *
- * @param {{x:Number, y:Number}} pointer
- * @private
- */
-Graph.prototype._checkShowPopup = function (pointer) {
-  var obj = {
-    left:   this._XconvertDOMtoCanvas(pointer.x),
-    top:    this._YconvertDOMtoCanvas(pointer.y),
-    right:  this._XconvertDOMtoCanvas(pointer.x),
-    bottom: this._YconvertDOMtoCanvas(pointer.y)
-  };
-
-  var id;
-  var lastPopupNode = this.popupObj;
-
-  if (this.popupObj == undefined) {
-    // search the nodes for overlap, select the top one in case of multiple nodes
-    var nodes = this.nodes;
-    for (id in nodes) {
-      if (nodes.hasOwnProperty(id)) {
-        var node = nodes[id];
-        if (node.getTitle() !== undefined && node.isOverlappingWith(obj)) {
-          this.popupObj = node;
-          break;
-        }
-      }
-    }
-  }
-
-  if (this.popupObj === undefined) {
-    // search the edges for overlap
-    var edges = this.edges;
-    for (id in edges) {
-      if (edges.hasOwnProperty(id)) {
-        var edge = edges[id];
-        if (edge.connected && (edge.getTitle() !== undefined) &&
-            edge.isOverlappingWith(obj)) {
-          this.popupObj = edge;
-          break;
-        }
-      }
-    }
-  }
-
-  if (this.popupObj) {
-    // show popup message window
-    if (this.popupObj != lastPopupNode) {
-      var me = this;
-      if (!me.popup) {
-        me.popup = new Popup(me.frame, me.constants.tooltip);
-      }
-
-      // adjust a small offset such that the mouse cursor is located in the
-      // bottom left location of the popup, and you can easily move over the
-      // popup area
-      me.popup.setPosition(pointer.x - 3, pointer.y - 3);
-      me.popup.setText(me.popupObj.getTitle());
-      me.popup.show();
-    }
-  }
-  else {
-    if (this.popup) {
-      this.popup.hide();
-    }
-  }
-};
-
-
-/**
- * Check if the popup must be hided, which is the case when the mouse is no
- * longer hovering on the object
- * @param {{x:Number, y:Number}} pointer
- * @private
- */
-Graph.prototype._checkHidePopup = function (pointer) {
-  if (!this.popupObj || !this._getNodeAt(pointer) ) {
-    this.popupObj = undefined;
-    if (this.popup) {
-      this.popup.hide();
-    }
-  }
-};
-
-
-/**
- * Set a new size for the graph
- * @param {string} width   Width in pixels or percentage (for example '800px'
- *                         or '50%')
- * @param {string} height  Height in pixels or percentage  (for example '400px'
- *                         or '30%')
- */
-Graph.prototype.setSize = function(width, height) {
-  this.frame.style.width = width;
-  this.frame.style.height = height;
-
-  this.frame.canvas.style.width = '100%';
-  this.frame.canvas.style.height = '100%';
-
-  this.frame.canvas.width = this.frame.canvas.clientWidth;
-  this.frame.canvas.height = this.frame.canvas.clientHeight;
-
-  if (this.manipulationDiv !== undefined) {
-    this.manipulationDiv.style.width = this.frame.canvas.clientWidth + "px";
-  }
-  if (this.navigationDivs !== undefined) {
-    if (this.navigationDivs['wrapper'] !== undefined) {
-      this.navigationDivs['wrapper'].style.width = this.frame.canvas.clientWidth + "px";
-      this.navigationDivs['wrapper'].style.height = this.frame.canvas.clientHeight + "px";
-    }
-  }
-
-  this.emit('resize', {width:this.frame.canvas.width,height:this.frame.canvas.height});
-};
-
-/**
- * Set a data set with nodes for the graph
- * @param {Array | DataSet | DataView} nodes         The data containing the nodes.
- * @private
- */
-Graph.prototype._setNodes = function(nodes) {
-  var oldNodesData = this.nodesData;
-
-  if (nodes instanceof DataSet || nodes instanceof DataView) {
-    this.nodesData = nodes;
-  }
-  else if (nodes instanceof Array) {
-    this.nodesData = new DataSet();
-    this.nodesData.add(nodes);
-  }
-  else if (!nodes) {
-    this.nodesData = new DataSet();
-  }
-  else {
-    throw new TypeError('Array or DataSet expected');
-  }
-
-  if (oldNodesData) {
-    // unsubscribe from old dataset
-    util.forEach(this.nodesListeners, function (callback, event) {
-      oldNodesData.off(event, callback);
-    });
-  }
-
-  // remove drawn nodes
-  this.nodes = {};
-
-  if (this.nodesData) {
-    // subscribe to new dataset
-    var me = this;
-    util.forEach(this.nodesListeners, function (callback, event) {
-      me.nodesData.on(event, callback);
-    });
-
-    // draw all new nodes
-    var ids = this.nodesData.getIds();
-    this._addNodes(ids);
-  }
-  this._updateSelection();
-};
-
-/**
- * Add nodes
- * @param {Number[] | String[]} ids
- * @private
- */
-Graph.prototype._addNodes = function(ids) {
-  var id;
-  for (var i = 0, len = ids.length; i < len; i++) {
-    id = ids[i];
-    var data = this.nodesData.get(id);
-    var node = new Node(data, this.images, this.groups, this.constants);
-    this.nodes[id] = node; // note: this may replace an existing node
-
-    if ((node.xFixed == false || node.yFixed == false) && (node.x === null || node.y === null)) {
-      var radius = 10 * 0.1*ids.length;
-      var angle = 2 * Math.PI * Math.random();
-      if (node.xFixed == false) {node.x = radius * Math.cos(angle);}
-      if (node.yFixed == false) {node.y = radius * Math.sin(angle);}
-    }
-    this.moving = true;
-  }
-  this._updateNodeIndexList();
-  if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) {
-    this._resetLevels();
-    this._setupHierarchicalLayout();
-  }
-  this._updateCalculationNodes();
-  this._reconnectEdges();
-  this._updateValueRange(this.nodes);
-  this.updateLabels();
-};
-
-/**
- * Update existing nodes, or create them when not yet existing
- * @param {Number[] | String[]} ids
- * @private
- */
-Graph.prototype._updateNodes = function(ids) {
-  var nodes = this.nodes,
-      nodesData = this.nodesData;
-  for (var i = 0, len = ids.length; i < len; i++) {
-    var id = ids[i];
-    var node = nodes[id];
-    var data = nodesData.get(id);
-    if (node) {
-      // update node
-      node.setProperties(data, this.constants);
-    }
-    else {
-      // create node
-      node = new Node(properties, this.images, this.groups, this.constants);
-      nodes[id] = node;
-    }
-  }
-  this.moving = true;
-  if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) {
-    this._resetLevels();
-    this._setupHierarchicalLayout();
-  }
-  this._updateNodeIndexList();
-  this._reconnectEdges();
-  this._updateValueRange(nodes);
-};
-
-/**
- * Remove existing nodes. If nodes do not exist, the method will just ignore it.
- * @param {Number[] | String[]} ids
- * @private
- */
-Graph.prototype._removeNodes = function(ids) {
-  var nodes = this.nodes;
-  for (var i = 0, len = ids.length; i < len; i++) {
-    var id = ids[i];
-    delete nodes[id];
-  }
-  this._updateNodeIndexList();
-  if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) {
-    this._resetLevels();
-    this._setupHierarchicalLayout();
-  }
-  this._updateCalculationNodes();
-  this._reconnectEdges();
-  this._updateSelection();
-  this._updateValueRange(nodes);
-};
-
-/**
- * Load edges by reading the data table
- * @param {Array | DataSet | DataView} edges    The data containing the edges.
- * @private
- * @private
- */
-Graph.prototype._setEdges = function(edges) {
-  var oldEdgesData = this.edgesData;
-
-  if (edges instanceof DataSet || edges instanceof DataView) {
-    this.edgesData = edges;
-  }
-  else if (edges instanceof Array) {
-    this.edgesData = new DataSet();
-    this.edgesData.add(edges);
-  }
-  else if (!edges) {
-    this.edgesData = new DataSet();
-  }
-  else {
-    throw new TypeError('Array or DataSet expected');
-  }
-
-  if (oldEdgesData) {
-    // unsubscribe from old dataset
-    util.forEach(this.edgesListeners, function (callback, event) {
-      oldEdgesData.off(event, callback);
-    });
-  }
-
-  // remove drawn edges
-  this.edges = {};
-
-  if (this.edgesData) {
-    // subscribe to new dataset
-    var me = this;
-    util.forEach(this.edgesListeners, function (callback, event) {
-      me.edgesData.on(event, callback);
-    });
-
-    // draw all new nodes
-    var ids = this.edgesData.getIds();
-    this._addEdges(ids);
-  }
-
-  this._reconnectEdges();
-};
-
-/**
- * Add edges
- * @param {Number[] | String[]} ids
- * @private
- */
-Graph.prototype._addEdges = function (ids) {
-  var edges = this.edges,
-      edgesData = this.edgesData;
-
-  for (var i = 0, len = ids.length; i < len; i++) {
-    var id = ids[i];
-
-    var oldEdge = edges[id];
-    if (oldEdge) {
-      oldEdge.disconnect();
-    }
-
-    var data = edgesData.get(id, {"showInternalIds" : true});
-    edges[id] = new Edge(data, this, this.constants);
-  }
-
-  this.moving = true;
-  this._updateValueRange(edges);
-  this._createBezierNodes();
-  if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) {
-    this._resetLevels();
-    this._setupHierarchicalLayout();
-  }
-  this._updateCalculationNodes();
-};
-
-/**
- * Update existing edges, or create them when not yet existing
- * @param {Number[] | String[]} ids
- * @private
- */
-Graph.prototype._updateEdges = function (ids) {
-  var edges = this.edges,
-      edgesData = this.edgesData;
-  for (var i = 0, len = ids.length; i < len; i++) {
-    var id = ids[i];
-
-    var data = edgesData.get(id);
-    var edge = edges[id];
-    if (edge) {
-      // update edge
-      edge.disconnect();
-      edge.setProperties(data, this.constants);
-      edge.connect();
-    }
-    else {
-      // create edge
-      edge = new Edge(data, this, this.constants);
-      this.edges[id] = edge;
-    }
-  }
-
-  this._createBezierNodes();
-  if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) {
-    this._resetLevels();
-    this._setupHierarchicalLayout();
-  }
-  this.moving = true;
-  this._updateValueRange(edges);
-};
-
-/**
- * Remove existing edges. Non existing ids will be ignored
- * @param {Number[] | String[]} ids
- * @private
- */
-Graph.prototype._removeEdges = function (ids) {
-  var edges = this.edges;
-  for (var i = 0, len = ids.length; i < len; i++) {
-    var id = ids[i];
-    var edge = edges[id];
-    if (edge) {
-      if (edge.via != null) {
-        delete this.sectors['support']['nodes'][edge.via.id];
-      }
-      edge.disconnect();
-      delete edges[id];
-    }
-  }
-
-  this.moving = true;
-  this._updateValueRange(edges);
-  if (this.constants.hierarchicalLayout.enabled == true && this.initializing == false) {
-    this._resetLevels();
-    this._setupHierarchicalLayout();
-  }
-  this._updateCalculationNodes();
-};
-
-/**
- * Reconnect all edges
- * @private
- */
-Graph.prototype._reconnectEdges = function() {
-  var id,
-      nodes = this.nodes,
-      edges = this.edges;
-  for (id in nodes) {
-    if (nodes.hasOwnProperty(id)) {
-      nodes[id].edges = [];
-    }
-  }
-
-  for (id in edges) {
-    if (edges.hasOwnProperty(id)) {
-      var edge = edges[id];
-      edge.from = null;
-      edge.to = null;
-      edge.connect();
-    }
-  }
-};
-
-/**
- * Update the values of all object in the given array according to the current
- * value range of the objects in the array.
- * @param {Object} obj    An object containing a set of Edges or Nodes
- *                        The objects must have a method getValue() and
- *                        setValueRange(min, max).
- * @private
- */
-Graph.prototype._updateValueRange = function(obj) {
-  var id;
-
-  // determine the range of the objects
-  var valueMin = undefined;
-  var valueMax = undefined;
-  for (id in obj) {
-    if (obj.hasOwnProperty(id)) {
-      var value = obj[id].getValue();
-      if (value !== undefined) {
-        valueMin = (valueMin === undefined) ? value : Math.min(value, valueMin);
-        valueMax = (valueMax === undefined) ? value : Math.max(value, valueMax);
-      }
-    }
-  }
-
-  // adjust the range of all objects
-  if (valueMin !== undefined && valueMax !== undefined) {
-    for (id in obj) {
-      if (obj.hasOwnProperty(id)) {
-        obj[id].setValueRange(valueMin, valueMax);
-      }
-    }
-  }
-};
-
-/**
- * Redraw the graph with the current data
- * chart will be resized too.
- */
-Graph.prototype.redraw = function() {
-  this.setSize(this.width, this.height);
-  this._redraw();
-};
-
-/**
- * Redraw the graph with the current data
- * @private
- */
-Graph.prototype._redraw = function() {
-  var ctx = this.frame.canvas.getContext('2d');
-  // clear the canvas
-  var w = this.frame.canvas.width;
-  var h = this.frame.canvas.height;
-  ctx.clearRect(0, 0, w, h);
-
-  // set scaling and translation
-  ctx.save();
-  ctx.translate(this.translation.x, this.translation.y);
-  ctx.scale(this.scale, this.scale);
-
-  this.canvasTopLeft = {
-    "x": this._XconvertDOMtoCanvas(0),
-    "y": this._YconvertDOMtoCanvas(0)
-  };
-  this.canvasBottomRight = {
-    "x": this._XconvertDOMtoCanvas(this.frame.canvas.clientWidth),
-    "y": this._YconvertDOMtoCanvas(this.frame.canvas.clientHeight)
-  };
-
-  this._doInAllSectors("_drawAllSectorNodes",ctx);
-  this._doInAllSectors("_drawEdges",ctx);
-  this._doInAllSectors("_drawNodes",ctx,false);
-  this._doInAllSectors("_drawControlNodes",ctx);
-
-//  this._doInSupportSector("_drawNodes",ctx,true);
-//  this._drawTree(ctx,"#F00F0F");
-
-  // restore original scaling and translation
-  ctx.restore();
-};
-
-/**
- * Set the translation of the graph
- * @param {Number} offsetX    Horizontal offset
- * @param {Number} offsetY    Vertical offset
- * @private
- */
-Graph.prototype._setTranslation = function(offsetX, offsetY) {
-  if (this.translation === undefined) {
-    this.translation = {
-      x: 0,
-      y: 0
-    };
-  }
-
-  if (offsetX !== undefined) {
-    this.translation.x = offsetX;
-  }
-  if (offsetY !== undefined) {
-    this.translation.y = offsetY;
-  }
-
-  this.emit('viewChanged');
-};
-
-/**
- * Get the translation of the graph
- * @return {Object} translation    An object with parameters x and y, both a number
- * @private
- */
-Graph.prototype._getTranslation = function() {
-  return {
-    x: this.translation.x,
-    y: this.translation.y
-  };
-};
-
-/**
- * Scale the graph
- * @param {Number} scale   Scaling factor 1.0 is unscaled
- * @private
- */
-Graph.prototype._setScale = function(scale) {
-  this.scale = scale;
-};
-
-/**
- * Get the current scale of  the graph
- * @return {Number} scale   Scaling factor 1.0 is unscaled
- * @private
- */
-Graph.prototype._getScale = function() {
-  return this.scale;
-};
-
-/**
- * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
- * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
- * @param {number} x
- * @returns {number}
- * @private
- */
-Graph.prototype._XconvertDOMtoCanvas = function(x) {
-  return (x - this.translation.x) / this.scale;
-};
-
-/**
- * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
- * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
- * @param {number} x
- * @returns {number}
- * @private
- */
-Graph.prototype._XconvertCanvasToDOM = function(x) {
-  return x * this.scale + this.translation.x;
-};
-
-/**
- * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
- * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
- * @param {number} y
- * @returns {number}
- * @private
- */
-Graph.prototype._YconvertDOMtoCanvas = function(y) {
-  return (y - this.translation.y) / this.scale;
-};
-
-/**
- * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
- * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
- * @param {number} y
- * @returns {number}
- * @private
- */
-Graph.prototype._YconvertCanvasToDOM = function(y) {
-  return y * this.scale + this.translation.y ;
-};
-
-
-/**
- *
- * @param {object} pos   = {x: number, y: number}
- * @returns {{x: number, y: number}}
- * @constructor
- */
-Graph.prototype.canvasToDOM = function(pos) {
-  return {x:this._XconvertCanvasToDOM(pos.x),y:this._YconvertCanvasToDOM(pos.y)};
-}
-
-/**
- *
- * @param {object} pos   = {x: number, y: number}
- * @returns {{x: number, y: number}}
- * @constructor
- */
-Graph.prototype.DOMtoCanvas = function(pos) {
-  return {x:this._XconvertDOMtoCanvas(pos.x),y:this._YconvertDOMtoCanvas(pos.y)};
-}
-
-/**
- * Redraw all nodes
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
- * @param {CanvasRenderingContext2D}   ctx
- * @param {Boolean} [alwaysShow]
- * @private
- */
-Graph.prototype._drawNodes = function(ctx,alwaysShow) {
-  if (alwaysShow === undefined) {
-    alwaysShow = false;
-  }
-
-  // first draw the unselected nodes
-  var nodes = this.nodes;
-  var selected = [];
-
-  for (var id in nodes) {
-    if (nodes.hasOwnProperty(id)) {
-      nodes[id].setScaleAndPos(this.scale,this.canvasTopLeft,this.canvasBottomRight);
-      if (nodes[id].isSelected()) {
-        selected.push(id);
-      }
-      else {
-        if (nodes[id].inArea() || alwaysShow) {
-          nodes[id].draw(ctx);
-        }
-      }
-    }
-  }
-
-  // draw the selected nodes on top
-  for (var s = 0, sMax = selected.length; s < sMax; s++) {
-    if (nodes[selected[s]].inArea() || alwaysShow) {
-      nodes[selected[s]].draw(ctx);
-    }
-  }
-};
-
-/**
- * Redraw all edges
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
- * @param {CanvasRenderingContext2D}   ctx
- * @private
- */
-Graph.prototype._drawEdges = function(ctx) {
-  var edges = this.edges;
-  for (var id in edges) {
-    if (edges.hasOwnProperty(id)) {
-      var edge = edges[id];
-      edge.setScale(this.scale);
-      if (edge.connected) {
-        edges[id].draw(ctx);
-      }
-    }
-  }
-};
-
-/**
- * Redraw all edges
- * The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');
- * @param {CanvasRenderingContext2D}   ctx
- * @private
- */
-Graph.prototype._drawControlNodes = function(ctx) {
-  var edges = this.edges;
-  for (var id in edges) {
-    if (edges.hasOwnProperty(id)) {
-      edges[id]._drawControlNodes(ctx);
-    }
-  }
-};
-
-/**
- * Find a stable position for all nodes
- * @private
- */
-Graph.prototype._stabilize = function() {
-  if (this.constants.freezeForStabilization == true) {
-    this._freezeDefinedNodes();
-  }
-
-  // find stable position
-  var count = 0;
-  while (this.moving && count < this.constants.stabilizationIterations) {
-    this._physicsTick();
-    count++;
-  }
-  this.zoomExtent(false,true);
-  if (this.constants.freezeForStabilization == true) {
-    this._restoreFrozenNodes();
-  }
-  this.emit("stabilized",{iterations:count});
-};
-
-/**
- * When initializing and stabilizing, we can freeze nodes with a predefined position. This greatly speeds up stabilization
- * because only the supportnodes for the smoothCurves have to settle.
- *
- * @private
- */
-Graph.prototype._freezeDefinedNodes = function() {
-  var nodes = this.nodes;
-  for (var id in nodes) {
-    if (nodes.hasOwnProperty(id)) {
-      if (nodes[id].x != null && nodes[id].y != null) {
-        nodes[id].fixedData.x = nodes[id].xFixed;
-        nodes[id].fixedData.y = nodes[id].yFixed;
-        nodes[id].xFixed = true;
-        nodes[id].yFixed = true;
-      }
-    }
-  }
-};
-
-/**
- * Unfreezes the nodes that have been frozen by _freezeDefinedNodes.
- *
- * @private
- */
-Graph.prototype._restoreFrozenNodes = function() {
-  var nodes = this.nodes;
-  for (var id in nodes) {
-    if (nodes.hasOwnProperty(id)) {
-      if (nodes[id].fixedData.x != null) {
-        nodes[id].xFixed = nodes[id].fixedData.x;
-        nodes[id].yFixed = nodes[id].fixedData.y;
-      }
-    }
-  }
-};
-
-
-/**
- * Check if any of the nodes is still moving
- * @param {number} vmin   the minimum velocity considered as 'moving'
- * @return {boolean}      true if moving, false if non of the nodes is moving
- * @private
- */
-Graph.prototype._isMoving = function(vmin) {
-  var nodes = this.nodes;
-  for (var id in nodes) {
-    if (nodes.hasOwnProperty(id) && nodes[id].isMoving(vmin)) {
-      return true;
-    }
-  }
-  return false;
-};
-
-
-/**
- * /**
- * Perform one discrete step for all nodes
- *
- * @private
- */
-Graph.prototype._discreteStepNodes = function() {
-  var interval = this.physicsDiscreteStepsize;
-  var nodes = this.nodes;
-  var nodeId;
-  var nodesPresent = false;
-
-  if (this.constants.maxVelocity > 0) {
-    for (nodeId in nodes) {
-      if (nodes.hasOwnProperty(nodeId)) {
-        nodes[nodeId].discreteStepLimited(interval, this.constants.maxVelocity);
-        nodesPresent = true;
-      }
-    }
-  }
-  else {
-    for (nodeId in nodes) {
-      if (nodes.hasOwnProperty(nodeId)) {
-        nodes[nodeId].discreteStep(interval);
-        nodesPresent = true;
-      }
-    }
-  }
-
-  if (nodesPresent == true) {
-    var vminCorrected = this.constants.minVelocity / Math.max(this.scale,0.05);
-    if (vminCorrected > 0.5*this.constants.maxVelocity) {
-      this.moving = true;
-    }
-    else {
-      this.moving = this._isMoving(vminCorrected);
-    }
-  }
-};
-
-/**
- * A single simulation step (or "tick") in the physics simulation
- *
- * @private
- */
-Graph.prototype._physicsTick = function() {
-  if (!this.freezeSimulation) {
-    if (this.moving) {
-      this._doInAllActiveSectors("_initializeForceCalculation");
-      this._doInAllActiveSectors("_discreteStepNodes");
-      if (this.constants.smoothCurves) {
-        this._doInSupportSector("_discreteStepNodes");
-      }
-      this._findCenter(this._getRange())
-    }
-  }
-};
-
-
-/**
- * This function runs one step of the animation. It calls an x amount of physics ticks and one render tick.
- * It reschedules itself at the beginning of the function
- *
- * @private
- */
-Graph.prototype._animationStep = function() {
-  // reset the timer so a new scheduled animation step can be set
-  this.timer = undefined;
-  // handle the keyboad movement
-  this._handleNavigation();
-
-  // this schedules a new animation step
-  this.start();
-
-  // start the physics simulation
-  var calculationTime = Date.now();
-  var maxSteps = 1;
-  this._physicsTick();
-  var timeRequired = Date.now() - calculationTime;
-  while (timeRequired < (this.renderTimestep - this.renderTime) && maxSteps < this.maxPhysicsTicksPerRender) {
-    this._physicsTick();
-    timeRequired = Date.now() - calculationTime;
-    maxSteps++;
-
-  }
-
-  // start the rendering process
-  var renderTime = Date.now();
-  this._redraw();
-  this.renderTime = Date.now() - renderTime;
-};
-
-if (typeof window !== 'undefined') {
-  window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
-                                 window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
-}
-
-/**
- * Schedule a animation step with the refreshrate interval.
- */
-Graph.prototype.start = function() {
-  if (this.moving || this.xIncrement != 0 || this.yIncrement != 0 || this.zoomIncrement != 0) {
-    if (!this.timer) {
-      var ua = navigator.userAgent.toLowerCase();
-
-      var requiresTimeout = false;
-      if (ua.indexOf('msie 9.0') != -1) { // IE 9
-        requiresTimeout = true;
-      }
-      else if (ua.indexOf('safari') != -1) {  // safari
-        if (ua.indexOf('chrome') <= -1) {
-          requiresTimeout = true;
-        }
-      }
-
-      if (requiresTimeout == true) {
-        this.timer = window.setTimeout(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function
-      }
-      else{
-        this.timer = window.requestAnimationFrame(this._animationStep.bind(this), this.renderTimestep); // wait this.renderTimeStep milliseconds and perform the animation step function
-      }
-    }
-  }
-  else {
-    this._redraw();
-  }
-};
-
-
-/**
- * Move the graph according to the keyboard presses.
- *
- * @private
- */
-Graph.prototype._handleNavigation = function() {
-  if (this.xIncrement != 0 || this.yIncrement != 0) {
-    var translation = this._getTranslation();
-    this._setTranslation(translation.x+this.xIncrement, translation.y+this.yIncrement);
-  }
-  if (this.zoomIncrement != 0) {
-    var center = {
-      x: this.frame.canvas.clientWidth / 2,
-      y: this.frame.canvas.clientHeight / 2
-    };
-    this._zoom(this.scale*(1 + this.zoomIncrement), center);
-  }
-};
-
-
-/**
- *  Freeze the _animationStep
- */
-Graph.prototype.toggleFreeze = function() {
-  if (this.freezeSimulation == false) {
-    this.freezeSimulation = true;
-  }
-  else {
-    this.freezeSimulation = false;
-    this.start();
-  }
-};
-
-
-/**
- * This function cleans the support nodes if they are not needed and adds them when they are.
- *
- * @param {boolean} [disableStart]
- * @private
- */
-Graph.prototype._configureSmoothCurves = function(disableStart) {
-  if (disableStart === undefined) {
-    disableStart = true;
-  }
-
-  if (this.constants.smoothCurves == true) {
-    this._createBezierNodes();
-  }
-  else {
-    // delete the support nodes
-    this.sectors['support']['nodes'] = {};
-    for (var edgeId in this.edges) {
-      if (this.edges.hasOwnProperty(edgeId)) {
-        this.edges[edgeId].smooth = false;
-        this.edges[edgeId].via = null;
-      }
-    }
-  }
-  this._updateCalculationNodes();
-  if (!disableStart) {
-    this.moving = true;
-    this.start();
-  }
-};
-
-
-/**
- * Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but
- * are used for the force calculation.
- *
- * @private
- */
-Graph.prototype._createBezierNodes = function() {
-  if (this.constants.smoothCurves == true) {
-    for (var edgeId in this.edges) {
-      if (this.edges.hasOwnProperty(edgeId)) {
-        var edge = this.edges[edgeId];
-        if (edge.via == null) {
-          edge.smooth = true;
-          var nodeId = "edgeId:".concat(edge.id);
-          this.sectors['support']['nodes'][nodeId] = new Node(
-                  {id:nodeId,
-                    mass:1,
-                    shape:'circle',
-                    image:"",
-                    internalMultiplier:1
-                  },{},{},this.constants);
-          edge.via = this.sectors['support']['nodes'][nodeId];
-          edge.via.parentEdgeId = edge.id;
-          edge.positionBezierNode();
-        }
-      }
-    }
-  }
-};
-
-/**
- * load the functions that load the mixins into the prototype.
- *
- * @private
- */
-Graph.prototype._initializeMixinLoaders = function () {
-  for (var mixinFunction in graphMixinLoaders) {
-    if (graphMixinLoaders.hasOwnProperty(mixinFunction)) {
-      Graph.prototype[mixinFunction] = graphMixinLoaders[mixinFunction];
-    }
-  }
-};
-
-/**
- * Load the XY positions of the nodes into the dataset.
- */
-Graph.prototype.storePosition = function() {
-  var dataArray = [];
-  for (var nodeId in this.nodes) {
-    if (this.nodes.hasOwnProperty(nodeId)) {
-      var node = this.nodes[nodeId];
-      var allowedToMoveX = !this.nodes.xFixed;
-      var allowedToMoveY = !this.nodes.yFixed;
-      if (this.nodesData.data[nodeId].x != Math.round(node.x) || this.nodesData.data[nodeId].y != Math.round(node.y)) {
-        dataArray.push({id:nodeId,x:Math.round(node.x),y:Math.round(node.y),allowedToMoveX:allowedToMoveX,allowedToMoveY:allowedToMoveY});
-      }
-    }
-  }
-  this.nodesData.update(dataArray);
-};
-
-
-/**
- * Center a node in view.
- *
- * @param {Number} nodeId
- * @param {Number} [zoomLevel]
- */
-Graph.prototype.focusOnNode = function (nodeId, zoomLevel) {
-  if (this.nodes.hasOwnProperty(nodeId)) {
-    if (zoomLevel === undefined) {
-      zoomLevel = this._getScale();
-    }
-    var nodePosition= {x: this.nodes[nodeId].x, y: this.nodes[nodeId].y};
-
-    var requiredScale = zoomLevel;
-    this._setScale(requiredScale);
-
-    var canvasCenter = this.DOMtoCanvas({x:0.5 * this.frame.canvas.width,y:0.5 * this.frame.canvas.height});
-    var translation = this._getTranslation();
-
-    var distanceFromCenter = {x:canvasCenter.x - nodePosition.x,
-                              y:canvasCenter.y - nodePosition.y};
-
-    this._setTranslation(translation.x + requiredScale * distanceFromCenter.x,
-                         translation.y + requiredScale * distanceFromCenter.y);
-    this.redraw();
-  }
-  else {
-    console.log("This nodeId cannot be found.")
-  }
-};
-
-
-
-
-
-
-
-
-
-
-/**
- * @constructor Graph3d
- * The Graph is a visualization Graphs on a time line
- *
- * Graph is developed in javascript as a Google Visualization Chart.
- *
- * @param {Element} container   The DOM element in which the Graph will
- *                              be created. Normally a div element.
- * @param {DataSet | DataView | Array} [data]
- * @param {Object} [options]
- */
-function Graph3d(container, data, options) {
-  // create variables and set default values
-  this.containerElement = container;
-  this.width = '400px';
-  this.height = '400px';
-  this.margin = 10; // px
-  this.defaultXCenter = '55%';
-  this.defaultYCenter = '50%';
-
-  this.xLabel = 'x';
-  this.yLabel = 'y';
-  this.zLabel = 'z';
-  this.filterLabel = 'time';
-  this.legendLabel = 'value';
-
-  this.style = Graph3d.STYLE.DOT;
-  this.showPerspective = true;
-  this.showGrid = true;
-  this.keepAspectRatio = true;
-  this.showShadow = false;
-  this.showGrayBottom = false; // TODO: this does not work correctly
-  this.showTooltip = false;
-  this.verticalRatio = 0.5; // 0.1 to 1.0, where 1.0 results in a 'cube'
-
-  this.animationInterval = 1000; // milliseconds
-  this.animationPreload = false;
-
-  this.camera = new Graph3d.Camera();
-  this.eye = new Point3d(0, 0, -1);  // TODO: set eye.z about 3/4 of the width of the window?
-
-  this.dataTable = null;  // The original data table
-  this.dataPoints = null; // The table with point objects
-
-  // the column indexes
-  this.colX = undefined;
-  this.colY = undefined;
-  this.colZ = undefined;
-  this.colValue = undefined;
-  this.colFilter = undefined;
-
-  this.xMin = 0;
-  this.xStep = undefined; // auto by default
-  this.xMax = 1;
-  this.yMin = 0;
-  this.yStep = undefined; // auto by default
-  this.yMax = 1;
-  this.zMin = 0;
-  this.zStep = undefined; // auto by default
-  this.zMax = 1;
-  this.valueMin = 0;
-  this.valueMax = 1;
-  this.xBarWidth = 1;
-  this.yBarWidth = 1;
-  // TODO: customize axis range
-
-  // constants
-  this.colorAxis = '#4D4D4D';
-  this.colorGrid = '#D3D3D3';
-  this.colorDot = '#7DC1FF';
-  this.colorDotBorder = '#3267D2';
-
-  // create a frame and canvas
-  this.create();
-
-  // apply options (also when undefined)
-  this.setOptions(options);
-
-  // apply data
-  if (data) {
-    this.setData(data);
-  }
-}
-
-// Extend Graph with an Emitter mixin
-Emitter(Graph3d.prototype);
-
-/**
- * @class Camera
- * The camera is mounted on a (virtual) camera arm. The camera arm can rotate
- * The camera is always looking in the direction of the origin of the arm.
- * This way, the camera always rotates around one fixed point, the location
- * of the camera arm.
- *
- * Documentation:
- *   http://en.wikipedia.org/wiki/3D_projection
- */
-Graph3d.Camera = function () {
-  this.armLocation = new Point3d();
-  this.armRotation = {};
-  this.armRotation.horizontal = 0;
-  this.armRotation.vertical = 0;
-  this.armLength = 1.7;
-
-  this.cameraLocation = new Point3d();
-  this.cameraRotation =  new Point3d(0.5*Math.PI, 0, 0);
-
-  this.calculateCameraOrientation();
-};
-
-/**
- * Set the location (origin) of the arm
- * @param {Number} x  Normalized value of x
- * @param {Number} y  Normalized value of y
- * @param {Number} z  Normalized value of z
- */
-Graph3d.Camera.prototype.setArmLocation = function(x, y, z) {
-  this.armLocation.x = x;
-  this.armLocation.y = y;
-  this.armLocation.z = z;
-
-  this.calculateCameraOrientation();
-};
-
-/**
- * Set the rotation of the camera arm
- * @param {Number} horizontal   The horizontal rotation, between 0 and 2*PI.
- *                Optional, can be left undefined.
- * @param {Number} vertical   The vertical rotation, between 0 and 0.5*PI
- *                if vertical=0.5*PI, the graph is shown from the
- *                top. Optional, can be left undefined.
- */
-Graph3d.Camera.prototype.setArmRotation = function(horizontal, vertical) {
-  if (horizontal !== undefined) {
-    this.armRotation.horizontal = horizontal;
-  }
-
-  if (vertical !== undefined) {
-    this.armRotation.vertical = vertical;
-    if (this.armRotation.vertical < 0) this.armRotation.vertical = 0;
-    if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI;
-  }
-
-  if (horizontal !== undefined || vertical !== undefined) {
-    this.calculateCameraOrientation();
-  }
-};
-
-/**
- * Retrieve the current arm rotation
- * @return {object}   An object with parameters horizontal and vertical
- */
-Graph3d.Camera.prototype.getArmRotation = function() {
-  var rot = {};
-  rot.horizontal = this.armRotation.horizontal;
-  rot.vertical = this.armRotation.vertical;
-
-  return rot;
-};
-
-/**
- * Set the (normalized) length of the camera arm.
- * @param {Number} length A length between 0.71 and 5.0
- */
-Graph3d.Camera.prototype.setArmLength = function(length) {
-  if (length === undefined)
-    return;
-
-  this.armLength = length;
-
-  // Radius must be larger than the corner of the graph,
-  // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the
-  // graph
-  if (this.armLength < 0.71) this.armLength = 0.71;
-  if (this.armLength > 5.0) this.armLength = 5.0;
-
-  this.calculateCameraOrientation();
-};
-
-/**
- * Retrieve the arm length
- * @return {Number} length
- */
-Graph3d.Camera.prototype.getArmLength = function() {
-  return this.armLength;
-};
-
-/**
- * Retrieve the camera location
- * @return {Point3d} cameraLocation
- */
-Graph3d.Camera.prototype.getCameraLocation = function() {
-  return this.cameraLocation;
-};
-
-/**
- * Retrieve the camera rotation
- * @return {Point3d} cameraRotation
- */
-Graph3d.Camera.prototype.getCameraRotation = function() {
-  return this.cameraRotation;
-};
-
-/**
- * Calculate the location and rotation of the camera based on the
- * position and orientation of the camera arm
- */
-Graph3d.Camera.prototype.calculateCameraOrientation = function() {
-  // calculate location of the camera
-  this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
-  this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
-  this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical);
-
-  // calculate rotation of the camera
-  this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical;
-  this.cameraRotation.y = 0;
-  this.cameraRotation.z = -this.armRotation.horizontal;
-};
-
-/**
- * Calculate the scaling values, dependent on the range in x, y, and z direction
- */
-Graph3d.prototype._setScale = function() {
-  this.scale = new Point3d(1 / (this.xMax - this.xMin),
-    1 / (this.yMax - this.yMin),
-    1 / (this.zMax - this.zMin));
-
-  // keep aspect ration between x and y scale if desired
-  if (this.keepAspectRatio) {
-    if (this.scale.x < this.scale.y) {
-      //noinspection JSSuspiciousNameCombination
-      this.scale.y = this.scale.x;
-    }
-    else {
-      //noinspection JSSuspiciousNameCombination
-      this.scale.x = this.scale.y;
-    }
-  }
-
-  // scale the vertical axis
-  this.scale.z *= this.verticalRatio;
-  // TODO: can this be automated? verticalRatio?
-
-  // determine scale for (optional) value
-  this.scale.value = 1 / (this.valueMax - this.valueMin);
-
-  // position the camera arm
-  var xCenter = (this.xMax + this.xMin) / 2 * this.scale.x;
-  var yCenter = (this.yMax + this.yMin) / 2 * this.scale.y;
-  var zCenter = (this.zMax + this.zMin) / 2 * this.scale.z;
-  this.camera.setArmLocation(xCenter, yCenter, zCenter);
-};
-
-
-/**
- * Convert a 3D location to a 2D location on screen
- * http://en.wikipedia.org/wiki/3D_projection
- * @param {Point3d} point3d   A 3D point with parameters x, y, z
- * @return {Point2d} point2d  A 2D point with parameters x, y
- */
-Graph3d.prototype._convert3Dto2D = function(point3d) {
-  var translation = this._convertPointToTranslation(point3d);
-  return this._convertTranslationToScreen(translation);
-};
-
-/**
- * Convert a 3D location its translation seen from the camera
- * http://en.wikipedia.org/wiki/3D_projection
- * @param {Point3d} point3d    A 3D point with parameters x, y, z
- * @return {Point3d} translation A 3D point with parameters x, y, z This is
- *                   the translation of the point, seen from the
- *                   camera
- */
-Graph3d.prototype._convertPointToTranslation = function(point3d) {
-  var ax = point3d.x * this.scale.x,
-    ay = point3d.y * this.scale.y,
-    az = point3d.z * this.scale.z,
-
-    cx = this.camera.getCameraLocation().x,
-    cy = this.camera.getCameraLocation().y,
-    cz = this.camera.getCameraLocation().z,
-
-  // calculate angles
-    sinTx = Math.sin(this.camera.getCameraRotation().x),
-    cosTx = Math.cos(this.camera.getCameraRotation().x),
-    sinTy = Math.sin(this.camera.getCameraRotation().y),
-    cosTy = Math.cos(this.camera.getCameraRotation().y),
-    sinTz = Math.sin(this.camera.getCameraRotation().z),
-    cosTz = Math.cos(this.camera.getCameraRotation().z),
-
-  // calculate translation
-    dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz),
-    dy = sinTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) + cosTx * (cosTz * (ay - cy) - sinTz * (ax-cx)),
-    dz = cosTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) - sinTx * (cosTz * (ay - cy) - sinTz * (ax-cx));
-
-  return new Point3d(dx, dy, dz);
-};
-
-/**
- * Convert a translation point to a point on the screen
- * @param {Point3d} translation   A 3D point with parameters x, y, z This is
- *                    the translation of the point, seen from the
- *                    camera
- * @return {Point2d} point2d    A 2D point with parameters x, y
- */
-Graph3d.prototype._convertTranslationToScreen = function(translation) {
-  var ex = this.eye.x,
-    ey = this.eye.y,
-    ez = this.eye.z,
-    dx = translation.x,
-    dy = translation.y,
-    dz = translation.z;
-
-  // calculate position on screen from translation
-  var bx;
-  var by;
-  if (this.showPerspective) {
-    bx = (dx - ex) * (ez / dz);
-    by = (dy - ey) * (ez / dz);
-  }
-  else {
-    bx = dx * -(ez / this.camera.getArmLength());
-    by = dy * -(ez / this.camera.getArmLength());
-  }
-
-  // shift and scale the point to the center of the screen
-  // use the width of the graph to scale both horizontally and vertically.
-  return new Point2d(
-    this.xcenter + bx * this.frame.canvas.clientWidth,
-    this.ycenter - by * this.frame.canvas.clientWidth);
-};
-
-/**
- * Set the background styling for the graph
- * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor
- */
-Graph3d.prototype._setBackgroundColor = function(backgroundColor) {
-  var fill = 'white';
-  var stroke = 'gray';
-  var strokeWidth = 1;
-
-  if (typeof(backgroundColor) === 'string') {
-    fill = backgroundColor;
-    stroke = 'none';
-    strokeWidth = 0;
-  }
-  else if (typeof(backgroundColor) === 'object') {
-    if (backgroundColor.fill !== undefined)    fill = backgroundColor.fill;
-    if (backgroundColor.stroke !== undefined)    stroke = backgroundColor.stroke;
-    if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth;
-  }
-  else if  (backgroundColor === undefined) {
-    // use use defaults
-  }
-  else {
-    throw 'Unsupported type of backgroundColor';
-  }
-
-  this.frame.style.backgroundColor = fill;
-  this.frame.style.borderColor = stroke;
-  this.frame.style.borderWidth = strokeWidth + 'px';
-  this.frame.style.borderStyle = 'solid';
-};
-
-
-/// enumerate the available styles
-Graph3d.STYLE = {
-  BAR: 0,
-  BARCOLOR: 1,
-  BARSIZE: 2,
-  DOT : 3,
-  DOTLINE : 4,
-  DOTCOLOR: 5,
-  DOTSIZE: 6,
-  GRID : 7,
-  LINE: 8,
-  SURFACE : 9
-};
-
-/**
- * Retrieve the style index from given styleName
- * @param {string} styleName  Style name such as 'dot', 'grid', 'dot-line'
- * @return {Number} styleNumber Enumeration value representing the style, or -1
- *                when not found
- */
-Graph3d.prototype._getStyleNumber = function(styleName) {
-  switch (styleName) {
-    case 'dot':     return Graph3d.STYLE.DOT;
-    case 'dot-line':  return Graph3d.STYLE.DOTLINE;
-    case 'dot-color':   return Graph3d.STYLE.DOTCOLOR;
-    case 'dot-size':  return Graph3d.STYLE.DOTSIZE;
-    case 'line':    return Graph3d.STYLE.LINE;
-    case 'grid':    return Graph3d.STYLE.GRID;
-    case 'surface':   return Graph3d.STYLE.SURFACE;
-    case 'bar':     return Graph3d.STYLE.BAR;
-    case 'bar-color':   return Graph3d.STYLE.BARCOLOR;
-    case 'bar-size':  return Graph3d.STYLE.BARSIZE;
-  }
-
-  return -1;
-};
-
-/**
- * Determine the indexes of the data columns, based on the given style and data
- * @param {DataSet} data
- * @param {Number}  style
- */
-Graph3d.prototype._determineColumnIndexes = function(data, style) {
-  if (this.style === Graph3d.STYLE.DOT ||
-    this.style === Graph3d.STYLE.DOTLINE ||
-    this.style === Graph3d.STYLE.LINE ||
-    this.style === Graph3d.STYLE.GRID ||
-    this.style === Graph3d.STYLE.SURFACE ||
-    this.style === Graph3d.STYLE.BAR) {
-    // 3 columns expected, and optionally a 4th with filter values
-    this.colX = 0;
-    this.colY = 1;
-    this.colZ = 2;
-    this.colValue = undefined;
-
-    if (data.getNumberOfColumns() > 3) {
-      this.colFilter = 3;
-    }
-  }
-  else if (this.style === Graph3d.STYLE.DOTCOLOR ||
-    this.style === Graph3d.STYLE.DOTSIZE ||
-    this.style === Graph3d.STYLE.BARCOLOR ||
-    this.style === Graph3d.STYLE.BARSIZE) {
-    // 4 columns expected, and optionally a 5th with filter values
-    this.colX = 0;
-    this.colY = 1;
-    this.colZ = 2;
-    this.colValue = 3;
-
-    if (data.getNumberOfColumns() > 4) {
-      this.colFilter = 4;
-    }
-  }
-  else {
-    throw 'Unknown style "' + this.style + '"';
-  }
-};
-
-Graph3d.prototype.getNumberOfRows = function(data) {
-  return data.length;
-}
-
-
-Graph3d.prototype.getNumberOfColumns = function(data) {
-  var counter = 0;
-  for (var column in data[0]) {
-    if (data[0].hasOwnProperty(column)) {
-      counter++;
-    }
-  }
-  return counter;
-}
-
-
-Graph3d.prototype.getDistinctValues = function(data, column) {
-  var distinctValues = [];
-  for (var i = 0; i < data.length; i++) {
-    if (distinctValues.indexOf(data[i][column]) == -1) {
-      distinctValues.push(data[i][column]);
-    }
-  }
-  return distinctValues;
-}
-
-
-Graph3d.prototype.getColumnRange = function(data,column) {
-  var minMax = {min:data[0][column],max:data[0][column]};
-  for (var i = 0; i < data.length; i++) {
-    if (minMax.min > data[i][column]) { minMax.min = data[i][column]; }
-    if (minMax.max < data[i][column]) { minMax.max = data[i][column]; }
-  }
-  return minMax;
-};
-
-/**
- * Initialize the data from the data table. Calculate minimum and maximum values
- * and column index values
- * @param {Array | DataSet | DataView} rawData   The data containing the items for the Graph.
- * @param {Number}     style   Style Number
- */
-Graph3d.prototype._dataInitialize = function (rawData, style) {
-  var me = this;
-
-  // unsubscribe from the dataTable
-  if (this.dataSet) {
-    this.dataSet.off('*', this._onChange);
-  }
-
-  if (rawData === undefined)
-    return;
-
-  if (Array.isArray(rawData)) {
-    rawData = new DataSet(rawData);
-  }
-
-  var data;
-  if (rawData instanceof DataSet || rawData instanceof DataView) {
-    data = rawData.get();
-  }
-  else {
-    throw new Error('Array, DataSet, or DataView expected');
-  }
-
-  if (data.length == 0)
-    return;
-
-  this.dataSet = rawData;
-  this.dataTable = data;
-
-  // subscribe to changes in the dataset
-  this._onChange = function () {
-    me.setData(me.dataSet);
-  };
-  this.dataSet.on('*', this._onChange);
-
-  // _determineColumnIndexes
-  // getNumberOfRows (points)
-  // getNumberOfColumns (x,y,z,v,t,t1,t2...)
-  // getDistinctValues (unique values?)
-  // getColumnRange
-
-  // determine the location of x,y,z,value,filter columns
-  this.colX = 'x';
-  this.colY = 'y';
-  this.colZ = 'z';
-  this.colValue = 'style';
-  this.colFilter = 'filter';
-
-
-
-  // check if a filter column is provided
-  if (data[0].hasOwnProperty('filter')) {
-    if (this.dataFilter === undefined) {
-      this.dataFilter = new Filter(rawData, this.colFilter, this);
-      this.dataFilter.setOnLoadCallback(function() {me.redraw();});
-    }
-  }
-
-
-  var withBars = this.style == Graph3d.STYLE.BAR ||
-    this.style == Graph3d.STYLE.BARCOLOR ||
-    this.style == Graph3d.STYLE.BARSIZE;
-
-  // determine barWidth from data
-  if (withBars) {
-    if (this.defaultXBarWidth !== undefined) {
-      this.xBarWidth = this.defaultXBarWidth;
-    }
-    else {
-      var dataX = this.getDistinctValues(data,this.colX);
-      this.xBarWidth = (dataX[1] - dataX[0]) || 1;
-    }
-
-    if (this.defaultYBarWidth !== undefined) {
-      this.yBarWidth = this.defaultYBarWidth;
-    }
-    else {
-      var dataY = this.getDistinctValues(data,this.colY);
-      this.yBarWidth = (dataY[1] - dataY[0]) || 1;
-    }
-  }
-
-  // calculate minimums and maximums
-  var xRange = this.getColumnRange(data,this.colX);
-  if (withBars) {
-    xRange.min -= this.xBarWidth / 2;
-    xRange.max += this.xBarWidth / 2;
-  }
-  this.xMin = (this.defaultXMin !== undefined) ? this.defaultXMin : xRange.min;
-  this.xMax = (this.defaultXMax !== undefined) ? this.defaultXMax : xRange.max;
-  if (this.xMax <= this.xMin) this.xMax = this.xMin + 1;
-  this.xStep = (this.defaultXStep !== undefined) ? this.defaultXStep : (this.xMax-this.xMin)/5;
-
-  var yRange = this.getColumnRange(data,this.colY);
-  if (withBars) {
-    yRange.min -= this.yBarWidth / 2;
-    yRange.max += this.yBarWidth / 2;
-  }
-  this.yMin = (this.defaultYMin !== undefined) ? this.defaultYMin : yRange.min;
-  this.yMax = (this.defaultYMax !== undefined) ? this.defaultYMax : yRange.max;
-  if (this.yMax <= this.yMin) this.yMax = this.yMin + 1;
-  this.yStep = (this.defaultYStep !== undefined) ? this.defaultYStep : (this.yMax-this.yMin)/5;
-
-  var zRange = this.getColumnRange(data,this.colZ);
-  this.zMin = (this.defaultZMin !== undefined) ? this.defaultZMin : zRange.min;
-  this.zMax = (this.defaultZMax !== undefined) ? this.defaultZMax : zRange.max;
-  if (this.zMax <= this.zMin) this.zMax = this.zMin + 1;
-  this.zStep = (this.defaultZStep !== undefined) ? this.defaultZStep : (this.zMax-this.zMin)/5;
-
-  if (this.colValue !== undefined) {
-    var valueRange = this.getColumnRange(data,this.colValue);
-    this.valueMin = (this.defaultValueMin !== undefined) ? this.defaultValueMin : valueRange.min;
-    this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max;
-    if (this.valueMax <= this.valueMin) this.valueMax = this.valueMin + 1;
-  }
-
-  // set the scale dependent on the ranges.
-  this._setScale();
-};
-
-
-
-/**
- * Filter the data based on the current filter
- * @param {Array} data
- * @return {Array} dataPoints   Array with point objects which can be drawn on screen
- */
-Graph3d.prototype._getDataPoints = function (data) {
-  // TODO: store the created matrix dataPoints in the filters instead of reloading each time
-  var x, y, i, z, obj, point;
-
-  var dataPoints = [];
-
-  if (this.style === Graph3d.STYLE.GRID ||
-    this.style === Graph3d.STYLE.SURFACE) {
-    // copy all values from the google data table to a matrix
-    // the provided values are supposed to form a grid of (x,y) positions
-
-    // create two lists with all present x and y values
-    var dataX = [];
-    var dataY = [];
-    for (i = 0; i < this.getNumberOfRows(data); i++) {
-      x = data[i][this.colX] || 0;
-      y = data[i][this.colY] || 0;
-
-      if (dataX.indexOf(x) === -1) {
-        dataX.push(x);
-      }
-      if (dataY.indexOf(y) === -1) {
-        dataY.push(y);
-      }
-    }
-
-    function sortNumber(a, b) {
-      return a - b;
-    }
-    dataX.sort(sortNumber);
-    dataY.sort(sortNumber);
-
-    // create a grid, a 2d matrix, with all values.
-    var dataMatrix = [];   // temporary data matrix
-    for (i = 0; i < data.length; i++) {
-      x = data[i][this.colX] || 0;
-      y = data[i][this.colY] || 0;
-      z = data[i][this.colZ] || 0;
-
-      var xIndex = dataX.indexOf(x);  // TODO: implement Array().indexOf() for Internet Explorer
-      var yIndex = dataY.indexOf(y);
-
-      if (dataMatrix[xIndex] === undefined) {
-        dataMatrix[xIndex] = [];
-      }
-
-      var point3d = new Point3d();
-      point3d.x = x;
-      point3d.y = y;
-      point3d.z = z;
-
-      obj = {};
-      obj.point = point3d;
-      obj.trans = undefined;
-      obj.screen = undefined;
-      obj.bottom = new Point3d(x, y, this.zMin);
-
-      dataMatrix[xIndex][yIndex] = obj;
-
-      dataPoints.push(obj);
-    }
-
-    // fill in the pointers to the neighbors.
-    for (x = 0; x < dataMatrix.length; x++) {
-      for (y = 0; y < dataMatrix[x].length; y++) {
-        if (dataMatrix[x][y]) {
-          dataMatrix[x][y].pointRight = (x < dataMatrix.length-1) ? dataMatrix[x+1][y] : undefined;
-          dataMatrix[x][y].pointTop   = (y < dataMatrix[x].length-1) ? dataMatrix[x][y+1] : undefined;
-          dataMatrix[x][y].pointCross =
-            (x < dataMatrix.length-1 && y < dataMatrix[x].length-1) ?
-              dataMatrix[x+1][y+1] :
-              undefined;
-        }
-      }
-    }
-  }
-  else {  // 'dot', 'dot-line', etc.
-    // copy all values from the google data table to a list with Point3d objects
-    for (i = 0; i < data.length; i++) {
-      point = new Point3d();
-      point.x = data[i][this.colX] || 0;
-      point.y = data[i][this.colY] || 0;
-      point.z = data[i][this.colZ] || 0;
-
-      if (this.colValue !== undefined) {
-        point.value = data[i][this.colValue] || 0;
-      }
-
-      obj = {};
-      obj.point = point;
-      obj.bottom = new Point3d(point.x, point.y, this.zMin);
-      obj.trans = undefined;
-      obj.screen = undefined;
-
-      dataPoints.push(obj);
-    }
-  }
-
-  return dataPoints;
-};
-
-
-
-
-/**
- * Append suffix 'px' to provided value x
- * @param {int}   x  An integer value
- * @return {string} the string value of x, followed by the suffix 'px'
- */
-Graph3d.px = function(x) {
-  return x + 'px';
-};
-
-
-/**
- * Create the main frame for the Graph3d.
- * This function is executed once when a Graph3d object is created. The frame
- * contains a canvas, and this canvas contains all objects like the axis and
- * nodes.
- */
-Graph3d.prototype.create = function () {
-  // remove all elements from the container element.
-  while (this.containerElement.hasChildNodes()) {
-    this.containerElement.removeChild(this.containerElement.firstChild);
-  }
-
-  this.frame = document.createElement('div');
-  this.frame.style.position = 'relative';
-  this.frame.style.overflow = 'hidden';
-
-  // create the graph canvas (HTML canvas element)
-  this.frame.canvas = document.createElement( 'canvas' );
-  this.frame.canvas.style.position = 'relative';
-  this.frame.appendChild(this.frame.canvas);
-  //if (!this.frame.canvas.getContext) {
-  {
-    var noCanvas = document.createElement( 'DIV' );
-    noCanvas.style.color = 'red';
-    noCanvas.style.fontWeight =  'bold' ;
-    noCanvas.style.padding =  '10px';
-    noCanvas.innerHTML =  'Error: your browser does not support HTML canvas';
-    this.frame.canvas.appendChild(noCanvas);
-  }
-
-  this.frame.filter = document.createElement( 'div' );
-  this.frame.filter.style.position = 'absolute';
-  this.frame.filter.style.bottom = '0px';
-  this.frame.filter.style.left = '0px';
-  this.frame.filter.style.width = '100%';
-  this.frame.appendChild(this.frame.filter);
-
-  // add event listeners to handle moving and zooming the contents
-  var me = this;
-  var onmousedown = function (event) {me._onMouseDown(event);};
-  var ontouchstart = function (event) {me._onTouchStart(event);};
-  var onmousewheel = function (event) {me._onWheel(event);};
-  var ontooltip = function (event) {me._onTooltip(event);};
-  // TODO: these events are never cleaned up... can give a 'memory leakage'
-
-  G3DaddEventListener(this.frame.canvas, 'keydown', onkeydown);
-  G3DaddEventListener(this.frame.canvas, 'mousedown', onmousedown);
-  G3DaddEventListener(this.frame.canvas, 'touchstart', ontouchstart);
-  G3DaddEventListener(this.frame.canvas, 'mousewheel', onmousewheel);
-  G3DaddEventListener(this.frame.canvas, 'mousemove', ontooltip);
-
-  // add the new graph to the container element
-  this.containerElement.appendChild(this.frame);
-};
-
-
-/**
- * Set a new size for the graph
- * @param {string} width   Width in pixels or percentage (for example '800px'
- *             or '50%')
- * @param {string} height  Height in pixels or percentage  (for example '400px'
- *             or '30%')
- */
-Graph3d.prototype.setSize = function(width, height) {
-  this.frame.style.width = width;
-  this.frame.style.height = height;
-
-  this._resizeCanvas();
-};
-
-/**
- * Resize the canvas to the current size of the frame
- */
-Graph3d.prototype._resizeCanvas = function() {
-  this.frame.canvas.style.width = '100%';
-  this.frame.canvas.style.height = '100%';
-
-  this.frame.canvas.width = this.frame.canvas.clientWidth;
-  this.frame.canvas.height = this.frame.canvas.clientHeight;
-
-  // adjust with for margin
-  this.frame.filter.style.width = (this.frame.canvas.clientWidth - 2 * 10) + 'px';
-};
-
-/**
- * Start animation
- */
-Graph3d.prototype.animationStart = function() {
-  if (!this.frame.filter || !this.frame.filter.slider)
-    throw 'No animation available';
-
-  this.frame.filter.slider.play();
-};
-
-
-/**
- * Stop animation
- */
-Graph3d.prototype.animationStop = function() {
-  if (!this.frame.filter || !this.frame.filter.slider) return;
-
-  this.frame.filter.slider.stop();
-};
-
-
-/**
- * Resize the center position based on the current values in this.defaultXCenter
- * and this.defaultYCenter (which are strings with a percentage or a value
- * in pixels). The center positions are the variables this.xCenter
- * and this.yCenter
- */
-Graph3d.prototype._resizeCenter = function() {
-  // calculate the horizontal center position
-  if (this.defaultXCenter.charAt(this.defaultXCenter.length-1) === '%') {
-    this.xcenter =
-      parseFloat(this.defaultXCenter) / 100 *
-        this.frame.canvas.clientWidth;
-  }
-  else {
-    this.xcenter = parseFloat(this.defaultXCenter); // supposed to be in px
-  }
-
-  // calculate the vertical center position
-  if (this.defaultYCenter.charAt(this.defaultYCenter.length-1) === '%') {
-    this.ycenter =
-      parseFloat(this.defaultYCenter) / 100 *
-        (this.frame.canvas.clientHeight - this.frame.filter.clientHeight);
-  }
-  else {
-    this.ycenter = parseFloat(this.defaultYCenter); // supposed to be in px
-  }
-};
-
-/**
- * Set the rotation and distance of the camera
- * @param {Object} pos   An object with the camera position. The object
- *             contains three parameters:
- *             - horizontal {Number}
- *             The horizontal rotation, between 0 and 2*PI.
- *             Optional, can be left undefined.
- *             - vertical {Number}
- *             The vertical rotation, between 0 and 0.5*PI
- *             if vertical=0.5*PI, the graph is shown from the
- *             top. Optional, can be left undefined.
- *             - distance {Number}
- *             The (normalized) distance of the camera to the
- *             center of the graph, a value between 0.71 and 5.0.
- *             Optional, can be left undefined.
- */
-Graph3d.prototype.setCameraPosition = function(pos) {
-  if (pos === undefined) {
-    return;
-  }
-
-  if (pos.horizontal !== undefined && pos.vertical !== undefined) {
-    this.camera.setArmRotation(pos.horizontal, pos.vertical);
-  }
-
-  if (pos.distance !== undefined) {
-    this.camera.setArmLength(pos.distance);
-  }
-
-  this.redraw();
-};
-
-
-/**
- * Retrieve the current camera rotation
- * @return {object}   An object with parameters horizontal, vertical, and
- *          distance
- */
-Graph3d.prototype.getCameraPosition = function() {
-  var pos = this.camera.getArmRotation();
-  pos.distance = this.camera.getArmLength();
-  return pos;
-};
-
-/**
- * Load data into the 3D Graph
- */
-Graph3d.prototype._readData = function(data) {
-  // read the data
-  this._dataInitialize(data, this.style);
-
-
-  if (this.dataFilter) {
-    // apply filtering
-    this.dataPoints = this.dataFilter._getDataPoints();
-  }
-  else {
-    // no filtering. load all data
-    this.dataPoints = this._getDataPoints(this.dataTable);
-  }
-
-  // draw the filter
-  this._redrawFilter();
-};
-
-/**
- * Replace the dataset of the Graph3d
- * @param {Array | DataSet | DataView} data
- */
-Graph3d.prototype.setData = function (data) {
-  this._readData(data);
-  this.redraw();
-
-  // start animation when option is true
-  if (this.animationAutoStart && this.dataFilter) {
-    this.animationStart();
-  }
-};
-
-/**
- * Update the options. Options will be merged with current options
- * @param {Object} options
- */
-Graph3d.prototype.setOptions = function (options) {
-  var cameraPosition = undefined;
-
-  this.animationStop();
-
-  if (options !== undefined) {
-    // retrieve parameter values
-    if (options.width !== undefined)       this.width = options.width;
-    if (options.height !== undefined)      this.height = options.height;
-
-    if (options.xCenter !== undefined)     this.defaultXCenter = options.xCenter;
-    if (options.yCenter !== undefined)     this.defaultYCenter = options.yCenter;
-
-    if (options.filterLabel !== undefined)     this.filterLabel = options.filterLabel;
-    if (options.legendLabel !== undefined)     this.legendLabel = options.legendLabel;
-    if (options.xLabel !== undefined)     this.xLabel = options.xLabel;
-    if (options.yLabel !== undefined)     this.yLabel = options.yLabel;
-    if (options.zLabel !== undefined)     this.zLabel = options.zLabel;
-
-    if (options.style !== undefined) {
-      var styleNumber = this._getStyleNumber(options.style);
-      if (styleNumber !== -1) {
-        this.style = styleNumber;
-      }
-    }
-    if (options.showGrid !== undefined)      this.showGrid = options.showGrid;
-    if (options.showPerspective !== undefined)   this.showPerspective = options.showPerspective;
-    if (options.showShadow !== undefined)    this.showShadow = options.showShadow;
-    if (options.tooltip !== undefined)       this.showTooltip = options.tooltip;
-    if (options.showAnimationControls !== undefined) this.showAnimationControls = options.showAnimationControls;
-    if (options.keepAspectRatio !== undefined)   this.keepAspectRatio = options.keepAspectRatio;
-    if (options.verticalRatio !== undefined)   this.verticalRatio = options.verticalRatio;
-
-    if (options.animationInterval !== undefined) this.animationInterval = options.animationInterval;
-    if (options.animationPreload !== undefined)  this.animationPreload = options.animationPreload;
-    if (options.animationAutoStart !== undefined)this.animationAutoStart = options.animationAutoStart;
-
-    if (options.xBarWidth !== undefined) this.defaultXBarWidth = options.xBarWidth;
-    if (options.yBarWidth !== undefined) this.defaultYBarWidth = options.yBarWidth;
-
-    if (options.xMin !== undefined) this.defaultXMin = options.xMin;
-    if (options.xStep !== undefined) this.defaultXStep = options.xStep;
-    if (options.xMax !== undefined) this.defaultXMax = options.xMax;
-    if (options.yMin !== undefined) this.defaultYMin = options.yMin;
-    if (options.yStep !== undefined) this.defaultYStep = options.yStep;
-    if (options.yMax !== undefined) this.defaultYMax = options.yMax;
-    if (options.zMin !== undefined) this.defaultZMin = options.zMin;
-    if (options.zStep !== undefined) this.defaultZStep = options.zStep;
-    if (options.zMax !== undefined) this.defaultZMax = options.zMax;
-    if (options.valueMin !== undefined) this.defaultValueMin = options.valueMin;
-    if (options.valueMax !== undefined) this.defaultValueMax = options.valueMax;
-
-    if (options.cameraPosition !== undefined) cameraPosition = options.cameraPosition;
-
-    if (cameraPosition !== undefined) {
-      this.camera.setArmRotation(cameraPosition.horizontal, cameraPosition.vertical);
-      this.camera.setArmLength(cameraPosition.distance);
-    }
-    else {
-      this.camera.setArmRotation(1.0, 0.5);
-      this.camera.setArmLength(1.7);
-    }
-  }
-
-  this._setBackgroundColor(options && options.backgroundColor);
-
-  this.setSize(this.width, this.height);
-
-  // re-load the data
-  if (this.dataTable) {
-    this.setData(this.dataTable);
-  }
-
-  // start animation when option is true
-  if (this.animationAutoStart && this.dataFilter) {
-    this.animationStart();
-  }
-};
-
-/**
- * Redraw the Graph.
- */
-Graph3d.prototype.redraw = function() {
-  if (this.dataPoints === undefined) {
-    throw 'Error: graph data not initialized';
-  }
-
-  this._resizeCanvas();
-  this._resizeCenter();
-  this._redrawSlider();
-  this._redrawClear();
-  this._redrawAxis();
-
-  if (this.style === Graph3d.STYLE.GRID ||
-    this.style === Graph3d.STYLE.SURFACE) {
-    this._redrawDataGrid();
-  }
-  else if (this.style === Graph3d.STYLE.LINE) {
-    this._redrawDataLine();
-  }
-  else if (this.style === Graph3d.STYLE.BAR ||
-    this.style === Graph3d.STYLE.BARCOLOR ||
-    this.style === Graph3d.STYLE.BARSIZE) {
-    this._redrawDataBar();
-  }
-  else {
-    // style is DOT, DOTLINE, DOTCOLOR, DOTSIZE
-    this._redrawDataDot();
-  }
-
-  this._redrawInfo();
-  this._redrawLegend();
-};
-
-/**
- * Clear the canvas before redrawing
- */
-Graph3d.prototype._redrawClear = function() {
-  var canvas = this.frame.canvas;
-  var ctx = canvas.getContext('2d');
-
-  ctx.clearRect(0, 0, canvas.width, canvas.height);
-};
-
-
-/**
- * Redraw the legend showing the colors
- */
-Graph3d.prototype._redrawLegend = function() {
-  var y;
-
-  if (this.style === Graph3d.STYLE.DOTCOLOR ||
-    this.style === Graph3d.STYLE.DOTSIZE) {
-
-    var dotSize = this.frame.clientWidth * 0.02;
-
-    var widthMin, widthMax;
-    if (this.style === Graph3d.STYLE.DOTSIZE) {
-      widthMin = dotSize / 2; // px
-      widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function
-    }
-    else {
-      widthMin = 20; // px
-      widthMax = 20; // px
-    }
-
-    var height = Math.max(this.frame.clientHeight * 0.25, 100);
-    var top = this.margin;
-    var right = this.frame.clientWidth - this.margin;
-    var left = right - widthMax;
-    var bottom = top + height;
-  }
-
-  var canvas = this.frame.canvas;
-  var ctx = canvas.getContext('2d');
-  ctx.lineWidth = 1;
-  ctx.font = '14px arial'; // TODO: put in options
-
-  if (this.style === Graph3d.STYLE.DOTCOLOR) {
-    // draw the color bar
-    var ymin = 0;
-    var ymax = height; // Todo: make height customizable
-    for (y = ymin; y < ymax; y++) {
-      var f = (y - ymin) / (ymax - ymin);
-
-      //var width = (dotSize / 2 + (1-f) * dotSize * 2); // Todo: put this in one function
-      var hue = f * 240;
-      var color = this._hsv2rgb(hue, 1, 1);
-
-      ctx.strokeStyle = color;
-      ctx.beginPath();
-      ctx.moveTo(left, top + y);
-      ctx.lineTo(right, top + y);
-      ctx.stroke();
-    }
-
-    ctx.strokeStyle =  this.colorAxis;
-    ctx.strokeRect(left, top, widthMax, height);
-  }
-
-  if (this.style === Graph3d.STYLE.DOTSIZE) {
-    // draw border around color bar
-    ctx.strokeStyle =  this.colorAxis;
-    ctx.fillStyle =  this.colorDot;
-    ctx.beginPath();
-    ctx.moveTo(left, top);
-    ctx.lineTo(right, top);
-    ctx.lineTo(right - widthMax + widthMin, bottom);
-    ctx.lineTo(left, bottom);
-    ctx.closePath();
-    ctx.fill();
-    ctx.stroke();
-  }
-
-  if (this.style === Graph3d.STYLE.DOTCOLOR ||
-    this.style === Graph3d.STYLE.DOTSIZE) {
-    // print values along the color bar
-    var gridLineLen = 5; // px
-    var step = new StepNumber(this.valueMin, this.valueMax, (this.valueMax-this.valueMin)/5, true);
-    step.start();
-    if (step.getCurrent() < this.valueMin) {
-      step.next();
-    }
-    while (!step.end()) {
-      y = bottom - (step.getCurrent() - this.valueMin) / (this.valueMax - this.valueMin) * height;
-
-      ctx.beginPath();
-      ctx.moveTo(left - gridLineLen, y);
-      ctx.lineTo(left, y);
-      ctx.stroke();
-
-      ctx.textAlign = 'right';
-      ctx.textBaseline = 'middle';
-      ctx.fillStyle = this.colorAxis;
-      ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y);
-
-      step.next();
-    }
-
-    ctx.textAlign = 'right';
-    ctx.textBaseline = 'top';
-    var label = this.legendLabel;
-    ctx.fillText(label, right, bottom + this.margin);
-  }
-};
-
-/**
- * Redraw the filter
- */
-Graph3d.prototype._redrawFilter = function() {
-  this.frame.filter.innerHTML = '';
-
-  if (this.dataFilter) {
-    var options = {
-      'visible': this.showAnimationControls
-    };
-    var slider = new Slider(this.frame.filter, options);
-    this.frame.filter.slider = slider;
-
-    // TODO: css here is not nice here...
-    this.frame.filter.style.padding = '10px';
-    //this.frame.filter.style.backgroundColor = '#EFEFEF';
-
-    slider.setValues(this.dataFilter.values);
-    slider.setPlayInterval(this.animationInterval);
-
-    // create an event handler
-    var me = this;
-    var onchange = function () {
-      var index = slider.getIndex();
-
-      me.dataFilter.selectValue(index);
-      me.dataPoints = me.dataFilter._getDataPoints();
-
-      me.redraw();
-    };
-    slider.setOnChangeCallback(onchange);
-  }
-  else {
-    this.frame.filter.slider = undefined;
-  }
-};
-
-/**
- * Redraw the slider
- */
-Graph3d.prototype._redrawSlider = function() {
-  if ( this.frame.filter.slider !== undefined) {
-    this.frame.filter.slider.redraw();
-  }
-};
-
-
-/**
- * Redraw common information
- */
-Graph3d.prototype._redrawInfo = function() {
-  if (this.dataFilter) {
-    var canvas = this.frame.canvas;
-    var ctx = canvas.getContext('2d');
-
-    ctx.font = '14px arial'; // TODO: put in options
-    ctx.lineStyle = 'gray';
-    ctx.fillStyle = 'gray';
-    ctx.textAlign = 'left';
-    ctx.textBaseline = 'top';
-
-    var x = this.margin;
-    var y = this.margin;
-    ctx.fillText(this.dataFilter.getLabel() + ': ' + this.dataFilter.getSelectedValue(), x, y);
-  }
-};
-
-
-/**
- * Redraw the axis
- */
-Graph3d.prototype._redrawAxis = function() {
-  var canvas = this.frame.canvas,
-    ctx = canvas.getContext('2d'),
-    from, to, step, prettyStep,
-    text, xText, yText, zText,
-    offset, xOffset, yOffset,
-    xMin2d, xMax2d;
-
-  // TODO: get the actual rendered style of the containerElement
-  //ctx.font = this.containerElement.style.font;
-  ctx.font = 24 / this.camera.getArmLength() + 'px arial';
-
-  // calculate the length for the short grid lines
-  var gridLenX = 0.025 / this.scale.x;
-  var gridLenY = 0.025 / this.scale.y;
-  var textMargin = 5 / this.camera.getArmLength(); // px
-  var armAngle = this.camera.getArmRotation().horizontal;
-
-  // draw x-grid lines
-  ctx.lineWidth = 1;
-  prettyStep = (this.defaultXStep === undefined);
-  step = new StepNumber(this.xMin, this.xMax, this.xStep, prettyStep);
-  step.start();
-  if (step.getCurrent() < this.xMin) {
-    step.next();
-  }
-  while (!step.end()) {
-    var x = step.getCurrent();
-
-    if (this.showGrid) {
-      from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin));
-      to = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin));
-      ctx.strokeStyle = this.colorGrid;
-      ctx.beginPath();
-      ctx.moveTo(from.x, from.y);
-      ctx.lineTo(to.x, to.y);
-      ctx.stroke();
-    }
-    else {
-      from = this._convert3Dto2D(new Point3d(x, this.yMin, this.zMin));
-      to = this._convert3Dto2D(new Point3d(x, this.yMin+gridLenX, this.zMin));
-      ctx.strokeStyle = this.colorAxis;
-      ctx.beginPath();
-      ctx.moveTo(from.x, from.y);
-      ctx.lineTo(to.x, to.y);
-      ctx.stroke();
-
-      from = this._convert3Dto2D(new Point3d(x, this.yMax, this.zMin));
-      to = this._convert3Dto2D(new Point3d(x, this.yMax-gridLenX, this.zMin));
-      ctx.strokeStyle = this.colorAxis;
-      ctx.beginPath();
-      ctx.moveTo(from.x, from.y);
-      ctx.lineTo(to.x, to.y);
-      ctx.stroke();
-    }
-
-    yText = (Math.cos(armAngle) > 0) ? this.yMin : this.yMax;
-    text = this._convert3Dto2D(new Point3d(x, yText, this.zMin));
-    if (Math.cos(armAngle * 2) > 0) {
-      ctx.textAlign = 'center';
-      ctx.textBaseline = 'top';
-      text.y += textMargin;
-    }
-    else if (Math.sin(armAngle * 2) < 0){
-      ctx.textAlign = 'right';
-      ctx.textBaseline = 'middle';
-    }
-    else {
-      ctx.textAlign = 'left';
-      ctx.textBaseline = 'middle';
-    }
-    ctx.fillStyle = this.colorAxis;
-    ctx.fillText('  ' + step.getCurrent() + '  ', text.x, text.y);
-
-    step.next();
-  }
-
-  // draw y-grid lines
-  ctx.lineWidth = 1;
-  prettyStep = (this.defaultYStep === undefined);
-  step = new StepNumber(this.yMin, this.yMax, this.yStep, prettyStep);
-  step.start();
-  if (step.getCurrent() < this.yMin) {
-    step.next();
-  }
-  while (!step.end()) {
-    if (this.showGrid) {
-      from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin));
-      to = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin));
-      ctx.strokeStyle = this.colorGrid;
-      ctx.beginPath();
-      ctx.moveTo(from.x, from.y);
-      ctx.lineTo(to.x, to.y);
-      ctx.stroke();
-    }
-    else {
-      from = this._convert3Dto2D(new Point3d(this.xMin, step.getCurrent(), this.zMin));
-      to = this._convert3Dto2D(new Point3d(this.xMin+gridLenY, step.getCurrent(), this.zMin));
-      ctx.strokeStyle = this.colorAxis;
-      ctx.beginPath();
-      ctx.moveTo(from.x, from.y);
-      ctx.lineTo(to.x, to.y);
-      ctx.stroke();
-
-      from = this._convert3Dto2D(new Point3d(this.xMax, step.getCurrent(), this.zMin));
-      to = this._convert3Dto2D(new Point3d(this.xMax-gridLenY, step.getCurrent(), this.zMin));
-      ctx.strokeStyle = this.colorAxis;
-      ctx.beginPath();
-      ctx.moveTo(from.x, from.y);
-      ctx.lineTo(to.x, to.y);
-      ctx.stroke();
-    }
-
-    xText = (Math.sin(armAngle ) > 0) ? this.xMin : this.xMax;
-    text = this._convert3Dto2D(new Point3d(xText, step.getCurrent(), this.zMin));
-    if (Math.cos(armAngle * 2) < 0) {
-      ctx.textAlign = 'center';
-      ctx.textBaseline = 'top';
-      text.y += textMargin;
-    }
-    else if (Math.sin(armAngle * 2) > 0){
-      ctx.textAlign = 'right';
-      ctx.textBaseline = 'middle';
-    }
-    else {
-      ctx.textAlign = 'left';
-      ctx.textBaseline = 'middle';
-    }
-    ctx.fillStyle = this.colorAxis;
-    ctx.fillText('  ' + step.getCurrent() + '  ', text.x, text.y);
-
-    step.next();
-  }
-
-  // draw z-grid lines and axis
-  ctx.lineWidth = 1;
-  prettyStep = (this.defaultZStep === undefined);
-  step = new StepNumber(this.zMin, this.zMax, this.zStep, prettyStep);
-  step.start();
-  if (step.getCurrent() < this.zMin) {
-    step.next();
-  }
-  xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax;
-  yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax;
-  while (!step.end()) {
-    // TODO: make z-grid lines really 3d?
-    from = this._convert3Dto2D(new Point3d(xText, yText, step.getCurrent()));
-    ctx.strokeStyle = this.colorAxis;
-    ctx.beginPath();
-    ctx.moveTo(from.x, from.y);
-    ctx.lineTo(from.x - textMargin, from.y);
-    ctx.stroke();
-
-    ctx.textAlign = 'right';
-    ctx.textBaseline = 'middle';
-    ctx.fillStyle = this.colorAxis;
-    ctx.fillText(step.getCurrent() + ' ', from.x - 5, from.y);
-
-    step.next();
-  }
-  ctx.lineWidth = 1;
-  from = this._convert3Dto2D(new Point3d(xText, yText, this.zMin));
-  to = this._convert3Dto2D(new Point3d(xText, yText, this.zMax));
-  ctx.strokeStyle = this.colorAxis;
-  ctx.beginPath();
-  ctx.moveTo(from.x, from.y);
-  ctx.lineTo(to.x, to.y);
-  ctx.stroke();
-
-  // draw x-axis
-  ctx.lineWidth = 1;
-  // line at yMin
-  xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin));
-  xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin));
-  ctx.strokeStyle = this.colorAxis;
-  ctx.beginPath();
-  ctx.moveTo(xMin2d.x, xMin2d.y);
-  ctx.lineTo(xMax2d.x, xMax2d.y);
-  ctx.stroke();
-  // line at ymax
-  xMin2d = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin));
-  xMax2d = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin));
-  ctx.strokeStyle = this.colorAxis;
-  ctx.beginPath();
-  ctx.moveTo(xMin2d.x, xMin2d.y);
-  ctx.lineTo(xMax2d.x, xMax2d.y);
-  ctx.stroke();
-
-  // draw y-axis
-  ctx.lineWidth = 1;
-  // line at xMin
-  from = this._convert3Dto2D(new Point3d(this.xMin, this.yMin, this.zMin));
-  to = this._convert3Dto2D(new Point3d(this.xMin, this.yMax, this.zMin));
-  ctx.strokeStyle = this.colorAxis;
-  ctx.beginPath();
-  ctx.moveTo(from.x, from.y);
-  ctx.lineTo(to.x, to.y);
-  ctx.stroke();
-  // line at xMax
-  from = this._convert3Dto2D(new Point3d(this.xMax, this.yMin, this.zMin));
-  to = this._convert3Dto2D(new Point3d(this.xMax, this.yMax, this.zMin));
-  ctx.strokeStyle = this.colorAxis;
-  ctx.beginPath();
-  ctx.moveTo(from.x, from.y);
-  ctx.lineTo(to.x, to.y);
-  ctx.stroke();
-
-  // draw x-label
-  var xLabel = this.xLabel;
-  if (xLabel.length > 0) {
-    yOffset = 0.1 / this.scale.y;
-    xText = (this.xMin + this.xMax) / 2;
-    yText = (Math.cos(armAngle) > 0) ? this.yMin - yOffset: this.yMax + yOffset;
-    text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin));
-    if (Math.cos(armAngle * 2) > 0) {
-      ctx.textAlign = 'center';
-      ctx.textBaseline = 'top';
-    }
-    else if (Math.sin(armAngle * 2) < 0){
-      ctx.textAlign = 'right';
-      ctx.textBaseline = 'middle';
-    }
-    else {
-      ctx.textAlign = 'left';
-      ctx.textBaseline = 'middle';
-    }
-    ctx.fillStyle = this.colorAxis;
-    ctx.fillText(xLabel, text.x, text.y);
-  }
-
-  // draw y-label
-  var yLabel = this.yLabel;
-  if (yLabel.length > 0) {
-    xOffset = 0.1 / this.scale.x;
-    xText = (Math.sin(armAngle ) > 0) ? this.xMin - xOffset : this.xMax + xOffset;
-    yText = (this.yMin + this.yMax) / 2;
-    text = this._convert3Dto2D(new Point3d(xText, yText, this.zMin));
-    if (Math.cos(armAngle * 2) < 0) {
-      ctx.textAlign = 'center';
-      ctx.textBaseline = 'top';
-    }
-    else if (Math.sin(armAngle * 2) > 0){
-      ctx.textAlign = 'right';
-      ctx.textBaseline = 'middle';
-    }
-    else {
-      ctx.textAlign = 'left';
-      ctx.textBaseline = 'middle';
-    }
-    ctx.fillStyle = this.colorAxis;
-    ctx.fillText(yLabel, text.x, text.y);
-  }
-
-  // draw z-label
-  var zLabel = this.zLabel;
-  if (zLabel.length > 0) {
-    offset = 30;  // pixels.  // TODO: relate to the max width of the values on the z axis?
-    xText = (Math.cos(armAngle ) > 0) ? this.xMin : this.xMax;
-    yText = (Math.sin(armAngle ) < 0) ? this.yMin : this.yMax;
-    zText = (this.zMin + this.zMax) / 2;
-    text = this._convert3Dto2D(new Point3d(xText, yText, zText));
-    ctx.textAlign = 'right';
-    ctx.textBaseline = 'middle';
-    ctx.fillStyle = this.colorAxis;
-    ctx.fillText(zLabel, text.x - offset, text.y);
-  }
-};
-
-/**
- * Calculate the color based on the given value.
- * @param {Number} H   Hue, a value be between 0 and 360
- * @param {Number} S   Saturation, a value between 0 and 1
- * @param {Number} V   Value, a value between 0 and 1
- */
-Graph3d.prototype._hsv2rgb = function(H, S, V) {
-  var R, G, B, C, Hi, X;
-
-  C = V * S;
-  Hi = Math.floor(H/60);  // hi = 0,1,2,3,4,5
-  X = C * (1 - Math.abs(((H/60) % 2) - 1));
-
-  switch (Hi) {
-    case 0: R = C; G = X; B = 0; break;
-    case 1: R = X; G = C; B = 0; break;
-    case 2: R = 0; G = C; B = X; break;
-    case 3: R = 0; G = X; B = C; break;
-    case 4: R = X; G = 0; B = C; break;
-    case 5: R = C; G = 0; B = X; break;
-
-    default: R = 0; G = 0; B = 0; break;
-  }
-
-  return 'RGB(' + parseInt(R*255) + ',' + parseInt(G*255) + ',' + parseInt(B*255) + ')';
-};
-
-
-/**
- * Draw all datapoints as a grid
- * This function can be used when the style is 'grid'
- */
-Graph3d.prototype._redrawDataGrid = function() {
-  var canvas = this.frame.canvas,
-    ctx = canvas.getContext('2d'),
-    point, right, top, cross,
-    i,
-    topSideVisible, fillStyle, strokeStyle, lineWidth,
-    h, s, v, zAvg;
-
-
-  if (this.dataPoints === undefined || this.dataPoints.length <= 0)
-    return; // TODO: throw exception?
-
-  // calculate the translations and screen position of all points
-  for (i = 0; i < this.dataPoints.length; i++) {
-    var trans = this._convertPointToTranslation(this.dataPoints[i].point);
-    var screen = this._convertTranslationToScreen(trans);
-
-    this.dataPoints[i].trans = trans;
-    this.dataPoints[i].screen = screen;
-
-    // calculate the translation of the point at the bottom (needed for sorting)
-    var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom);
-    this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z;
-  }
-
-  // sort the points on depth of their (x,y) position (not on z)
-  var sortDepth = function (a, b) {
-    return b.dist - a.dist;
-  };
-  this.dataPoints.sort(sortDepth);
-
-  if (this.style === Graph3d.STYLE.SURFACE) {
-    for (i = 0; i < this.dataPoints.length; i++) {
-      point = this.dataPoints[i];
-      right = this.dataPoints[i].pointRight;
-      top   = this.dataPoints[i].pointTop;
-      cross = this.dataPoints[i].pointCross;
-
-      if (point !== undefined && right !== undefined && top !== undefined && cross !== undefined) {
-
-        if (this.showGrayBottom || this.showShadow) {
-          // calculate the cross product of the two vectors from center
-          // to left and right, in order to know whether we are looking at the
-          // bottom or at the top side. We can also use the cross product
-          // for calculating light intensity
-          var aDiff = Point3d.subtract(cross.trans, point.trans);
-          var bDiff = Point3d.subtract(top.trans, right.trans);
-          var crossproduct = Point3d.crossProduct(aDiff, bDiff);
-          var len = crossproduct.length();
-          // FIXME: there is a bug with determining the surface side (shadow or colored)
-
-          topSideVisible = (crossproduct.z > 0);
-        }
-        else {
-          topSideVisible = true;
-        }
-
-        if (topSideVisible) {
-          // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
-          zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4;
-          h = (1 - (zAvg - this.zMin) * this.scale.z  / this.verticalRatio) * 240;
-          s = 1; // saturation
-
-          if (this.showShadow) {
-            v = Math.min(1 + (crossproduct.x / len) / 2, 1);  // value. TODO: scale
-            fillStyle = this._hsv2rgb(h, s, v);
-            strokeStyle = fillStyle;
-          }
-          else  {
-            v = 1;
-            fillStyle = this._hsv2rgb(h, s, v);
-            strokeStyle = this.colorAxis;
-          }
-        }
-        else {
-          fillStyle = 'gray';
-          strokeStyle = this.colorAxis;
-        }
-        lineWidth = 0.5;
-
-        ctx.lineWidth = lineWidth;
-        ctx.fillStyle = fillStyle;
-        ctx.strokeStyle = strokeStyle;
-        ctx.beginPath();
-        ctx.moveTo(point.screen.x, point.screen.y);
-        ctx.lineTo(right.screen.x, right.screen.y);
-        ctx.lineTo(cross.screen.x, cross.screen.y);
-        ctx.lineTo(top.screen.x, top.screen.y);
-        ctx.closePath();
-        ctx.fill();
-        ctx.stroke();
-      }
-    }
-  }
-  else { // grid style
-    for (i = 0; i < this.dataPoints.length; i++) {
-      point = this.dataPoints[i];
-      right = this.dataPoints[i].pointRight;
-      top   = this.dataPoints[i].pointTop;
-
-      if (point !== undefined) {
-        if (this.showPerspective) {
-          lineWidth = 2 / -point.trans.z;
-        }
-        else {
-          lineWidth = 2 * -(this.eye.z / this.camera.getArmLength());
-        }
-      }
-
-      if (point !== undefined && right !== undefined) {
-        // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
-        zAvg = (point.point.z + right.point.z) / 2;
-        h = (1 - (zAvg - this.zMin) * this.scale.z  / this.verticalRatio) * 240;
-
-        ctx.lineWidth = lineWidth;
-        ctx.strokeStyle = this._hsv2rgb(h, 1, 1);
-        ctx.beginPath();
-        ctx.moveTo(point.screen.x, point.screen.y);
-        ctx.lineTo(right.screen.x, right.screen.y);
-        ctx.stroke();
-      }
-
-      if (point !== undefined && top !== undefined) {
-        // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
-        zAvg = (point.point.z + top.point.z) / 2;
-        h = (1 - (zAvg - this.zMin) * this.scale.z  / this.verticalRatio) * 240;
-
-        ctx.lineWidth = lineWidth;
-        ctx.strokeStyle = this._hsv2rgb(h, 1, 1);
-        ctx.beginPath();
-        ctx.moveTo(point.screen.x, point.screen.y);
-        ctx.lineTo(top.screen.x, top.screen.y);
-        ctx.stroke();
-      }
-    }
-  }
-};
-
-
-/**
- * Draw all datapoints as dots.
- * This function can be used when the style is 'dot' or 'dot-line'
- */
-Graph3d.prototype._redrawDataDot = function() {
-  var canvas = this.frame.canvas;
-  var ctx = canvas.getContext('2d');
-  var i;
-
-  if (this.dataPoints === undefined || this.dataPoints.length <= 0)
-    return;  // TODO: throw exception?
-
-  // calculate the translations of all points
-  for (i = 0; i < this.dataPoints.length; i++) {
-    var trans = this._convertPointToTranslation(this.dataPoints[i].point);
-    var screen = this._convertTranslationToScreen(trans);
-    this.dataPoints[i].trans = trans;
-    this.dataPoints[i].screen = screen;
-
-    // calculate the distance from the point at the bottom to the camera
-    var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom);
-    this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z;
-  }
-
-  // order the translated points by depth
-  var sortDepth = function (a, b) {
-    return b.dist - a.dist;
-  };
-  this.dataPoints.sort(sortDepth);
-
-  // draw the datapoints as colored circles
-  var dotSize = this.frame.clientWidth * 0.02;  // px
-  for (i = 0; i < this.dataPoints.length; i++) {
-    var point = this.dataPoints[i];
-
-    if (this.style === Graph3d.STYLE.DOTLINE) {
-      // draw a vertical line from the bottom to the graph value
-      //var from = this._convert3Dto2D(new Point3d(point.point.x, point.point.y, this.zMin));
-      var from = this._convert3Dto2D(point.bottom);
-      ctx.lineWidth = 1;
-      ctx.strokeStyle = this.colorGrid;
-      ctx.beginPath();
-      ctx.moveTo(from.x, from.y);
-      ctx.lineTo(point.screen.x, point.screen.y);
-      ctx.stroke();
-    }
-
-    // calculate radius for the circle
-    var size;
-    if (this.style === Graph3d.STYLE.DOTSIZE) {
-      size = dotSize/2 + 2*dotSize * (point.point.value - this.valueMin) / (this.valueMax - this.valueMin);
-    }
-    else {
-      size = dotSize;
-    }
-
-    var radius;
-    if (this.showPerspective) {
-      radius = size / -point.trans.z;
-    }
-    else {
-      radius = size * -(this.eye.z / this.camera.getArmLength());
-    }
-    if (radius < 0) {
-      radius = 0;
-    }
-
-    var hue, color, borderColor;
-    if (this.style === Graph3d.STYLE.DOTCOLOR ) {
-      // calculate the color based on the value
-      hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240;
-      color = this._hsv2rgb(hue, 1, 1);
-      borderColor = this._hsv2rgb(hue, 1, 0.8);
-    }
-    else if (this.style === Graph3d.STYLE.DOTSIZE) {
-      color = this.colorDot;
-      borderColor = this.colorDotBorder;
-    }
-    else {
-      // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
-      hue = (1 - (point.point.z - this.zMin) * this.scale.z  / this.verticalRatio) * 240;
-      color = this._hsv2rgb(hue, 1, 1);
-      borderColor = this._hsv2rgb(hue, 1, 0.8);
-    }
-
-    // draw the circle
-    ctx.lineWidth = 1.0;
-    ctx.strokeStyle = borderColor;
-    ctx.fillStyle = color;
-    ctx.beginPath();
-    ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI*2, true);
-    ctx.fill();
-    ctx.stroke();
-  }
-};
-
-/**
- * Draw all datapoints as bars.
- * This function can be used when the style is 'bar', 'bar-color', or 'bar-size'
- */
-Graph3d.prototype._redrawDataBar = function() {
-  var canvas = this.frame.canvas;
-  var ctx = canvas.getContext('2d');
-  var i, j, surface, corners;
-
-  if (this.dataPoints === undefined || this.dataPoints.length <= 0)
-    return;  // TODO: throw exception?
-
-  // calculate the translations of all points
-  for (i = 0; i < this.dataPoints.length; i++) {
-    var trans = this._convertPointToTranslation(this.dataPoints[i].point);
-    var screen = this._convertTranslationToScreen(trans);
-    this.dataPoints[i].trans = trans;
-    this.dataPoints[i].screen = screen;
-
-    // calculate the distance from the point at the bottom to the camera
-    var transBottom = this._convertPointToTranslation(this.dataPoints[i].bottom);
-    this.dataPoints[i].dist = this.showPerspective ? transBottom.length() : -transBottom.z;
-  }
-
-  // order the translated points by depth
-  var sortDepth = function (a, b) {
-    return b.dist - a.dist;
-  };
-  this.dataPoints.sort(sortDepth);
-
-  // draw the datapoints as bars
-  var xWidth = this.xBarWidth / 2;
-  var yWidth = this.yBarWidth / 2;
-  for (i = 0; i < this.dataPoints.length; i++) {
-    var point = this.dataPoints[i];
-
-    // determine color
-    var hue, color, borderColor;
-    if (this.style === Graph3d.STYLE.BARCOLOR ) {
-      // calculate the color based on the value
-      hue = (1 - (point.point.value - this.valueMin) * this.scale.value) * 240;
-      color = this._hsv2rgb(hue, 1, 1);
-      borderColor = this._hsv2rgb(hue, 1, 0.8);
-    }
-    else if (this.style === Graph3d.STYLE.BARSIZE) {
-      color = this.colorDot;
-      borderColor = this.colorDotBorder;
-    }
-    else {
-      // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
-      hue = (1 - (point.point.z - this.zMin) * this.scale.z  / this.verticalRatio) * 240;
-      color = this._hsv2rgb(hue, 1, 1);
-      borderColor = this._hsv2rgb(hue, 1, 0.8);
-    }
-
-    // calculate size for the bar
-    if (this.style === Graph3d.STYLE.BARSIZE) {
-      xWidth = (this.xBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2);
-      yWidth = (this.yBarWidth / 2) * ((point.point.value - this.valueMin) / (this.valueMax - this.valueMin) * 0.8 + 0.2);
-    }
-
-    // calculate all corner points
-    var me = this;
-    var point3d = point.point;
-    var top = [
-      {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z)},
-      {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z)},
-      {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z)},
-      {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z)}
-    ];
-    var bottom = [
-      {point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, this.zMin)},
-      {point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, this.zMin)},
-      {point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, this.zMin)},
-      {point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, this.zMin)}
-    ];
-
-    // calculate screen location of the points
-    top.forEach(function (obj) {
-      obj.screen = me._convert3Dto2D(obj.point);
-    });
-    bottom.forEach(function (obj) {
-      obj.screen = me._convert3Dto2D(obj.point);
-    });
-
-    // create five sides, calculate both corner points and center points
-    var surfaces = [
-      {corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point)},
-      {corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point)},
-      {corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point)},
-      {corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point)},
-      {corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point)}
-    ];
-    point.surfaces = surfaces;
-
-    // calculate the distance of each of the surface centers to the camera
-    for (j = 0; j < surfaces.length; j++) {
-      surface = surfaces[j];
-      var transCenter = this._convertPointToTranslation(surface.center);
-      surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z;
-      // TODO: this dept calculation doesn't work 100% of the cases due to perspective,
-      //     but the current solution is fast/simple and works in 99.9% of all cases
-      //     the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9})
-    }
-
-    // order the surfaces by their (translated) depth
-    surfaces.sort(function (a, b) {
-      var diff = b.dist - a.dist;
-      if (diff) return diff;
-
-      // if equal depth, sort the top surface last
-      if (a.corners === top) return 1;
-      if (b.corners === top) return -1;
-
-      // both are equal
-      return 0;
-    });
-
-    // draw the ordered surfaces
-    ctx.lineWidth = 1;
-    ctx.strokeStyle = borderColor;
-    ctx.fillStyle = color;
-    // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside
-    for (j = 2; j < surfaces.length; j++) {
-      surface = surfaces[j];
-      corners = surface.corners;
-      ctx.beginPath();
-      ctx.moveTo(corners[3].screen.x, corners[3].screen.y);
-      ctx.lineTo(corners[0].screen.x, corners[0].screen.y);
-      ctx.lineTo(corners[1].screen.x, corners[1].screen.y);
-      ctx.lineTo(corners[2].screen.x, corners[2].screen.y);
-      ctx.lineTo(corners[3].screen.x, corners[3].screen.y);
-      ctx.fill();
-      ctx.stroke();
-    }
-  }
-};
-
-
-/**
- * Draw a line through all datapoints.
- * This function can be used when the style is 'line'
- */
-Graph3d.prototype._redrawDataLine = function() {
-  var canvas = this.frame.canvas,
-    ctx = canvas.getContext('2d'),
-    point, i;
-
-  if (this.dataPoints === undefined || this.dataPoints.length <= 0)
-    return;  // TODO: throw exception?
-
-  // calculate the translations of all points
-  for (i = 0; i < this.dataPoints.length; i++) {
-    var trans = this._convertPointToTranslation(this.dataPoints[i].point);
-    var screen = this._convertTranslationToScreen(trans);
-
-    this.dataPoints[i].trans = trans;
-    this.dataPoints[i].screen = screen;
-  }
-
-  // start the line
-  if (this.dataPoints.length > 0) {
-    point = this.dataPoints[0];
-
-    ctx.lineWidth = 1;    // TODO: make customizable
-    ctx.strokeStyle = 'blue'; // TODO: make customizable
-    ctx.beginPath();
-    ctx.moveTo(point.screen.x, point.screen.y);
-  }
-
-  // draw the datapoints as colored circles
-  for (i = 1; i < this.dataPoints.length; i++) {
-    point = this.dataPoints[i];
-    ctx.lineTo(point.screen.x, point.screen.y);
-  }
-
-  // finish the line
-  if (this.dataPoints.length > 0) {
-    ctx.stroke();
-  }
-};
-
-/**
- * Start a moving operation inside the provided parent element
- * @param {Event}     event     The event that occurred (required for
- *                  retrieving the  mouse position)
- */
-Graph3d.prototype._onMouseDown = function(event) {
-  event = event || window.event;
-
-  // check if mouse is still down (may be up when focus is lost for example
-  // in an iframe)
-  if (this.leftButtonDown) {
-    this._onMouseUp(event);
-  }
-
-  // only react on left mouse button down
-  this.leftButtonDown = event.which ? (event.which === 1) : (event.button === 1);
-  if (!this.leftButtonDown && !this.touchDown) return;
-
-  // get mouse position (different code for IE and all other browsers)
-  this.startMouseX = getMouseX(event);
-  this.startMouseY = getMouseY(event);
-
-  this.startStart = new Date(this.start);
-  this.startEnd = new Date(this.end);
-  this.startArmRotation = this.camera.getArmRotation();
-
-  this.frame.style.cursor = 'move';
-
-  // add event listeners to handle moving the contents
-  // we store the function onmousemove and onmouseup in the graph, so we can
-  // remove the eventlisteners lateron in the function mouseUp()
-  var me = this;
-  this.onmousemove = function (event) {me._onMouseMove(event);};
-  this.onmouseup   = function (event) {me._onMouseUp(event);};
-  G3DaddEventListener(document, 'mousemove', me.onmousemove);
-  G3DaddEventListener(document, 'mouseup', me.onmouseup);
-  G3DpreventDefault(event);
-};
-
-
-/**
- * Perform moving operating.
- * This function activated from within the funcion Graph.mouseDown().
- * @param {Event}   event  Well, eehh, the event
- */
-Graph3d.prototype._onMouseMove = function (event) {
-  event = event || window.event;
-
-  // calculate change in mouse position
-  var diffX = parseFloat(getMouseX(event)) - this.startMouseX;
-  var diffY = parseFloat(getMouseY(event)) - this.startMouseY;
-
-  var horizontalNew = this.startArmRotation.horizontal + diffX / 200;
-  var verticalNew = this.startArmRotation.vertical + diffY / 200;
-
-  var snapAngle = 4; // degrees
-  var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI);
-
-  // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc...
-  // the -0.001 is to take care that the vertical axis is always drawn at the left front corner
-  if (Math.abs(Math.sin(horizontalNew)) < snapValue) {
-    horizontalNew = Math.round((horizontalNew / Math.PI)) * Math.PI - 0.001;
-  }
-  if (Math.abs(Math.cos(horizontalNew)) < snapValue) {
-    horizontalNew = (Math.round((horizontalNew/ Math.PI - 0.5)) + 0.5) * Math.PI - 0.001;
-  }
-
-  // snap vertically to nice angles
-  if (Math.abs(Math.sin(verticalNew)) < snapValue) {
-    verticalNew = Math.round((verticalNew / Math.PI)) * Math.PI;
-  }
-  if (Math.abs(Math.cos(verticalNew)) < snapValue) {
-    verticalNew = (Math.round((verticalNew/ Math.PI - 0.5)) + 0.5) * Math.PI;
-  }
-
-  this.camera.setArmRotation(horizontalNew, verticalNew);
-  this.redraw();
-
-  // fire a cameraPositionChange event
-  var parameters = this.getCameraPosition();
-  this.emit('cameraPositionChange', parameters);
-
-  G3DpreventDefault(event);
-};
-
-
-/**
- * Stop moving operating.
- * This function activated from within the funcion Graph.mouseDown().
- * @param {event}  event   The event
- */
-Graph3d.prototype._onMouseUp = function (event) {
-  this.frame.style.cursor = 'auto';
-  this.leftButtonDown = false;
-
-  // remove event listeners here
-  G3DremoveEventListener(document, 'mousemove', this.onmousemove);
-  G3DremoveEventListener(document, 'mouseup',   this.onmouseup);
-  G3DpreventDefault(event);
-};
-
-/**
- * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point
- * @param {Event}  event   A mouse move event
- */
-Graph3d.prototype._onTooltip = function (event) {
-  var delay = 300; // ms
-  var mouseX = getMouseX(event) - getAbsoluteLeft(this.frame);
-  var mouseY = getMouseY(event) - getAbsoluteTop(this.frame);
-
-  if (!this.showTooltip) {
-    return;
-  }
-
-  if (this.tooltipTimeout) {
-    clearTimeout(this.tooltipTimeout);
-  }
-
-  // (delayed) display of a tooltip only if no mouse button is down
-  if (this.leftButtonDown) {
-    this._hideTooltip();
-    return;
-  }
-
-  if (this.tooltip && this.tooltip.dataPoint) {
-    // tooltip is currently visible
-    var dataPoint = this._dataPointFromXY(mouseX, mouseY);
-    if (dataPoint !== this.tooltip.dataPoint) {
-      // datapoint changed
-      if (dataPoint) {
-        this._showTooltip(dataPoint);
-      }
-      else {
-        this._hideTooltip();
-      }
-    }
-  }
-  else {
-    // tooltip is currently not visible
-    var me = this;
-    this.tooltipTimeout = setTimeout(function () {
-      me.tooltipTimeout = null;
-
-      // show a tooltip if we have a data point
-      var dataPoint = me._dataPointFromXY(mouseX, mouseY);
-      if (dataPoint) {
-        me._showTooltip(dataPoint);
-      }
-    }, delay);
-  }
-};
-
-/**
- * Event handler for touchstart event on mobile devices
- */
-Graph3d.prototype._onTouchStart = function(event) {
-  this.touchDown = true;
-
-  var me = this;
-  this.ontouchmove = function (event) {me._onTouchMove(event);};
-  this.ontouchend  = function (event) {me._onTouchEnd(event);};
-  G3DaddEventListener(document, 'touchmove', me.ontouchmove);
-  G3DaddEventListener(document, 'touchend', me.ontouchend);
-
-  this._onMouseDown(event);
-};
-
-/**
- * Event handler for touchmove event on mobile devices
- */
-Graph3d.prototype._onTouchMove = function(event) {
-  this._onMouseMove(event);
-};
-
-/**
- * Event handler for touchend event on mobile devices
- */
-Graph3d.prototype._onTouchEnd = function(event) {
-  this.touchDown = false;
-
-  G3DremoveEventListener(document, 'touchmove', this.ontouchmove);
-  G3DremoveEventListener(document, 'touchend',   this.ontouchend);
-
-  this._onMouseUp(event);
-};
-
-
-/**
- * Event handler for mouse wheel event, used to zoom the graph
- * Code from http://adomas.org/javascript-mouse-wheel/
- * @param {event}  event   The event
- */
-Graph3d.prototype._onWheel = function(event) {
-  if (!event) /* For IE. */
-    event = window.event;
-
-  // retrieve delta
-  var delta = 0;
-  if (event.wheelDelta) { /* IE/Opera. */
-    delta = event.wheelDelta/120;
-  } else if (event.detail) { /* Mozilla case. */
-    // In Mozilla, sign of delta is different than in IE.
-    // Also, delta is multiple of 3.
-    delta = -event.detail/3;
-  }
-
-  // If delta is nonzero, handle it.
-  // Basically, delta is now positive if wheel was scrolled up,
-  // and negative, if wheel was scrolled down.
-  if (delta) {
-    var oldLength = this.camera.getArmLength();
-    var newLength = oldLength * (1 - delta / 10);
-
-    this.camera.setArmLength(newLength);
-    this.redraw();
-
-    this._hideTooltip();
-  }
-
-  // fire a cameraPositionChange event
-  var parameters = this.getCameraPosition();
-  this.emit('cameraPositionChange', parameters);
-
-  // Prevent default actions caused by mouse wheel.
-  // That might be ugly, but we handle scrolls somehow
-  // anyway, so don't bother here..
-  G3DpreventDefault(event);
-};
-
-/**
- * Test whether a point lies inside given 2D triangle
- * @param {Point2d} point
- * @param {Point2d[]} triangle
- * @return {boolean} Returns true if given point lies inside or on the edge of the triangle
- * @private
- */
-Graph3d.prototype._insideTriangle = function (point, triangle) {
-  var a = triangle[0],
-    b = triangle[1],
-    c = triangle[2];
-
-  function sign (x) {
-    return x > 0 ? 1 : x < 0 ? -1 : 0;
-  }
-
-  var as = sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x));
-  var bs = sign((c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x));
-  var cs = sign((a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x));
-
-  // each of the three signs must be either equal to each other or zero
-  return (as == 0 || bs == 0 || as == bs) &&
-    (bs == 0 || cs == 0 || bs == cs) &&
-    (as == 0 || cs == 0 || as == cs);
-};
-
-/**
- * Find a data point close to given screen position (x, y)
- * @param {Number} x
- * @param {Number} y
- * @return {Object | null} The closest data point or null if not close to any data point
- * @private
- */
-Graph3d.prototype._dataPointFromXY = function (x, y) {
-  var i,
-    distMax = 100, // px
-    dataPoint = null,
-    closestDataPoint = null,
-    closestDist = null,
-    center = new Point2d(x, y);
-
-  if (this.style === Graph3d.STYLE.BAR ||
-    this.style === Graph3d.STYLE.BARCOLOR ||
-    this.style === Graph3d.STYLE.BARSIZE) {
-    // the data points are ordered from far away to closest
-    for (i = this.dataPoints.length - 1; i >= 0; i--) {
-      dataPoint = this.dataPoints[i];
-      var surfaces  = dataPoint.surfaces;
-      if (surfaces) {
-        for (var s = surfaces.length - 1; s >= 0; s--) {
-          // split each surface in two triangles, and see if the center point is inside one of these
-          var surface = surfaces[s];
-          var corners = surface.corners;
-          var triangle1 = [corners[0].screen, corners[1].screen, corners[2].screen];
-          var triangle2 = [corners[2].screen, corners[3].screen, corners[0].screen];
-          if (this._insideTriangle(center, triangle1) ||
-            this._insideTriangle(center, triangle2)) {
-            // return immediately at the first hit
-            return dataPoint;
-          }
-        }
-      }
-    }
-  }
-  else {
-    // find the closest data point, using distance to the center of the point on 2d screen
-    for (i = 0; i < this.dataPoints.length; i++) {
-      dataPoint = this.dataPoints[i];
-      var point = dataPoint.screen;
-      if (point) {
-        var distX = Math.abs(x - point.x);
-        var distY = Math.abs(y - point.y);
-        var dist  = Math.sqrt(distX * distX + distY * distY);
-
-        if ((closestDist === null || dist < closestDist) && dist < distMax) {
-          closestDist = dist;
-          closestDataPoint = dataPoint;
-        }
-      }
-    }
-  }
-
-
-  return closestDataPoint;
-};
-
-/**
- * Display a tooltip for given data point
- * @param {Object} dataPoint
- * @private
- */
-Graph3d.prototype._showTooltip = function (dataPoint) {
-  var content, line, dot;
-
-  if (!this.tooltip) {
-    content = document.createElement('div');
-    content.style.position = 'absolute';
-    content.style.padding = '10px';
-    content.style.border = '1px solid #4d4d4d';
-    content.style.color = '#1a1a1a';
-    content.style.background = 'rgba(255,255,255,0.7)';
-    content.style.borderRadius = '2px';
-    content.style.boxShadow = '5px 5px 10px rgba(128,128,128,0.5)';
-
-    line = document.createElement('div');
-    line.style.position = 'absolute';
-    line.style.height = '40px';
-    line.style.width = '0';
-    line.style.borderLeft = '1px solid #4d4d4d';
-
-    dot = document.createElement('div');
-    dot.style.position = 'absolute';
-    dot.style.height = '0';
-    dot.style.width = '0';
-    dot.style.border = '5px solid #4d4d4d';
-    dot.style.borderRadius = '5px';
-
-    this.tooltip = {
-      dataPoint: null,
-      dom: {
-        content: content,
-        line: line,
-        dot: dot
-      }
-    };
-  }
-  else {
-    content = this.tooltip.dom.content;
-    line  = this.tooltip.dom.line;
-    dot   = this.tooltip.dom.dot;
-  }
-
-  this._hideTooltip();
-
-  this.tooltip.dataPoint = dataPoint;
-  if (typeof this.showTooltip === 'function') {
-    content.innerHTML = this.showTooltip(dataPoint.point);
-  }
-  else {
-    content.innerHTML = '<table>' +
-      '<tr><td>x:</td><td>' + dataPoint.point.x + '</td></tr>' +
-      '<tr><td>y:</td><td>' + dataPoint.point.y + '</td></tr>' +
-      '<tr><td>z:</td><td>' + dataPoint.point.z + '</td></tr>' +
-      '</table>';
-  }
-
-  content.style.left  = '0';
-  content.style.top   = '0';
-  this.frame.appendChild(content);
-  this.frame.appendChild(line);
-  this.frame.appendChild(dot);
-
-  // calculate sizes
-  var contentWidth  = content.offsetWidth;
-  var contentHeight   = content.offsetHeight;
-  var lineHeight    = line.offsetHeight;
-  var dotWidth    = dot.offsetWidth;
-  var dotHeight     = dot.offsetHeight;
-
-  var left = dataPoint.screen.x - contentWidth / 2;
-  left = Math.min(Math.max(left, 10), this.frame.clientWidth - 10 - contentWidth);
-
-  line.style.left   = dataPoint.screen.x + 'px';
-  line.style.top    = (dataPoint.screen.y - lineHeight) + 'px';
-  content.style.left  = left + 'px';
-  content.style.top   = (dataPoint.screen.y - lineHeight - contentHeight) + 'px';
-  dot.style.left    = (dataPoint.screen.x - dotWidth / 2) + 'px';
-  dot.style.top     = (dataPoint.screen.y - dotHeight / 2) + 'px';
-};
-
-/**
- * Hide the tooltip when displayed
- * @private
- */
-Graph3d.prototype._hideTooltip = function () {
-  if (this.tooltip) {
-    this.tooltip.dataPoint = null;
-
-    for (var prop in this.tooltip.dom) {
-      if (this.tooltip.dom.hasOwnProperty(prop)) {
-        var elem = this.tooltip.dom[prop];
-        if (elem && elem.parentNode) {
-          elem.parentNode.removeChild(elem);
-        }
-      }
-    }
-  }
-};
-
-
-/**
- * Add and event listener. Works for all browsers
- * @param {Element}   element  An html element
- * @param {string}    action   The action, for example 'click',
- *                 without the prefix 'on'
- * @param {function}  listener   The callback function to be executed
- * @param {boolean}   useCapture
- */
-G3DaddEventListener = function(element, action, listener, useCapture) {
-  if (element.addEventListener) {
-    if (useCapture === undefined)
-      useCapture = false;
-
-    if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) {
-      action = 'DOMMouseScroll';  // For Firefox
-    }
-
-    element.addEventListener(action, listener, useCapture);
-  } else {
-    element.attachEvent('on' + action, listener);  // IE browsers
-  }
-};
-
-/**
- * Remove an event listener from an element
- * @param {Element}    element   An html dom element
- * @param {string}     action  The name of the event, for example 'mousedown'
- * @param {function}   listener  The listener function
- * @param {boolean}    useCapture
- */
-G3DremoveEventListener = function(element, action, listener, useCapture) {
-  if (element.removeEventListener) {
-    // non-IE browsers
-    if (useCapture === undefined)
-      useCapture = false;
-
-    if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) {
-      action = 'DOMMouseScroll';  // For Firefox
-    }
-
-    element.removeEventListener(action, listener, useCapture);
-  } else {
-    // IE browsers
-    element.detachEvent('on' + action, listener);
-  }
-};
-
-/**
- * Stop event propagation
- */
-G3DstopPropagation = function(event) {
-  if (!event)
-    event = window.event;
-
-  if (event.stopPropagation) {
-    event.stopPropagation();  // non-IE browsers
-  }
-  else {
-    event.cancelBubble = true;  // IE browsers
-  }
-};
-
-
-/**
- * Cancels the event if it is cancelable, without stopping further propagation of the event.
- */
-G3DpreventDefault = function (event) {
-  if (!event)
-    event = window.event;
-
-  if (event.preventDefault) {
-    event.preventDefault();  // non-IE browsers
-  }
-  else {
-    event.returnValue = false;  // IE browsers
-  }
-};
-
-
-
-/**
- * @prototype Point3d
- * @param {Number} x
- * @param {Number} y
- * @param {Number} z
- */
-function Point3d(x, y, z) {
-  this.x = x !== undefined ? x : 0;
-  this.y = y !== undefined ? y : 0;
-  this.z = z !== undefined ? z : 0;
-};
-
-/**
- * Subtract the two provided points, returns a-b
- * @param {Point3d} a
- * @param {Point3d} b
- * @return {Point3d} a-b
- */
-Point3d.subtract = function(a, b) {
-  var sub = new Point3d();
-  sub.x = a.x - b.x;
-  sub.y = a.y - b.y;
-  sub.z = a.z - b.z;
-  return sub;
-};
-
-/**
- * Add the two provided points, returns a+b
- * @param {Point3d} a
- * @param {Point3d} b
- * @return {Point3d} a+b
- */
-Point3d.add = function(a, b) {
-  var sum = new Point3d();
-  sum.x = a.x + b.x;
-  sum.y = a.y + b.y;
-  sum.z = a.z + b.z;
-  return sum;
-};
-
-/**
- * Calculate the average of two 3d points
- * @param {Point3d} a
- * @param {Point3d} b
- * @return {Point3d} The average, (a+b)/2
- */
-Point3d.avg = function(a, b) {
-  return new Point3d(
-      (a.x + b.x) / 2,
-      (a.y + b.y) / 2,
-      (a.z + b.z) / 2
-  );
-};
-
-/**
- * Calculate the cross product of the two provided points, returns axb
- * Documentation: http://en.wikipedia.org/wiki/Cross_product
- * @param {Point3d} a
- * @param {Point3d} b
- * @return {Point3d} cross product axb
- */
-Point3d.crossProduct = function(a, b) {
-  var crossproduct = new Point3d();
-
-  crossproduct.x = a.y * b.z - a.z * b.y;
-  crossproduct.y = a.z * b.x - a.x * b.z;
-  crossproduct.z = a.x * b.y - a.y * b.x;
-
-  return crossproduct;
-};
-
-
-/**
- * Rtrieve the length of the vector (or the distance from this point to the origin
- * @return {Number}  length
- */
-Point3d.prototype.length = function() {
-  return Math.sqrt(
-      this.x * this.x +
-      this.y * this.y +
-      this.z * this.z
-  );
-};
-
-/**
- * @prototype Point2d
- */
-Point2d = function (x, y) {
-  this.x = x !== undefined ? x : 0;
-  this.y = y !== undefined ? y : 0;
-};
-
-
-/**
- * @class Filter
- *
- * @param {DataSet} data The google data table
- * @param {Number}  column             The index of the column to be filtered
- * @param {Graph} graph           The graph
- */
-function Filter (data, column, graph) {
-  this.data = data;
-  this.column = column;
-  this.graph = graph; // the parent graph
-
-  this.index = undefined;
-  this.value = undefined;
-
-  // read all distinct values and select the first one
-  this.values = graph.getDistinctValues(data.get(), this.column);
-
-  // sort both numeric and string values correctly
-  this.values.sort(function (a, b) {
-    return a > b ? 1 : a < b ? -1 : 0;
-  });
-
-  if (this.values.length > 0) {
-    this.selectValue(0);
-  }
-
-  // create an array with the filtered datapoints. this will be loaded afterwards
-  this.dataPoints = [];
-
-  this.loaded = false;
-  this.onLoadCallback = undefined;
-
-  if (graph.animationPreload) {
-    this.loaded = false;
-    this.loadInBackground();
-  }
-  else {
-    this.loaded = true;
-  }
-};
-
-
-/**
- * Return the label
- * @return {string} label
- */
-Filter.prototype.isLoaded = function() {
-  return this.loaded;
-};
-
-
-/**
- * Return the loaded progress
- * @return {Number} percentage between 0 and 100
- */
-Filter.prototype.getLoadedProgress = function() {
-  var len = this.values.length;
-
-  var i = 0;
-  while (this.dataPoints[i]) {
-    i++;
-  }
-
-  return Math.round(i / len * 100);
-};
-
-
-/**
- * Return the label
- * @return {string} label
- */
-Filter.prototype.getLabel = function() {
-  return this.graph.filterLabel;
-};
-
-
-/**
- * Return the columnIndex of the filter
- * @return {Number} columnIndex
- */
-Filter.prototype.getColumn = function() {
-  return this.column;
-};
-
-/**
- * Return the currently selected value. Returns undefined if there is no selection
- * @return {*} value
- */
-Filter.prototype.getSelectedValue = function() {
-  if (this.index === undefined)
-    return undefined;
-
-  return this.values[this.index];
-};
-
-/**
- * Retrieve all values of the filter
- * @return {Array} values
- */
-Filter.prototype.getValues = function() {
-  return this.values;
-};
-
-/**
- * Retrieve one value of the filter
- * @param {Number}  index
- * @return {*} value
- */
-Filter.prototype.getValue = function(index) {
-  if (index >= this.values.length)
-    throw 'Error: index out of range';
-
-  return this.values[index];
-};
-
-
-/**
- * Retrieve the (filtered) dataPoints for the currently selected filter index
- * @param {Number} [index] (optional)
- * @return {Array} dataPoints
- */
-Filter.prototype._getDataPoints = function(index) {
-  if (index === undefined)
-    index = this.index;
-
-  if (index === undefined)
-    return [];
-
-  var dataPoints;
-  if (this.dataPoints[index]) {
-    dataPoints = this.dataPoints[index];
-  }
-  else {
-    var f = {};
-    f.column = this.column;
-    f.value = this.values[index];
-
-    var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get();
-    dataPoints = this.graph._getDataPoints(dataView);
-
-    this.dataPoints[index] = dataPoints;
-  }
-
-  return dataPoints;
-};
-
-
-
-/**
- * Set a callback function when the filter is fully loaded.
- */
-Filter.prototype.setOnLoadCallback = function(callback) {
-  this.onLoadCallback = callback;
-};
-
-
-/**
- * Add a value to the list with available values for this filter
- * No double entries will be created.
- * @param {Number} index
- */
-Filter.prototype.selectValue = function(index) {
-  if (index >= this.values.length)
-    throw 'Error: index out of range';
-
-  this.index = index;
-  this.value = this.values[index];
-};
-
-/**
- * Load all filtered rows in the background one by one
- * Start this method without providing an index!
- */
-Filter.prototype.loadInBackground = function(index) {
-  if (index === undefined)
-    index = 0;
-
-  var frame = this.graph.frame;
-
-  if (index < this.values.length) {
-    var dataPointsTemp = this._getDataPoints(index);
-    //this.graph.redrawInfo(); // TODO: not neat
-
-    // create a progress box
-    if (frame.progress === undefined) {
-      frame.progress = document.createElement('DIV');
-      frame.progress.style.position = 'absolute';
-      frame.progress.style.color = 'gray';
-      frame.appendChild(frame.progress);
-    }
-    var progress = this.getLoadedProgress();
-    frame.progress.innerHTML = 'Loading animation... ' + progress + '%';
-    // TODO: this is no nice solution...
-    frame.progress.style.bottom = Graph3d.px(60); // TODO: use height of slider
-    frame.progress.style.left = Graph3d.px(10);
-
-    var me = this;
-    setTimeout(function() {me.loadInBackground(index+1);}, 10);
-    this.loaded = false;
-  }
-  else {
-    this.loaded = true;
-
-    // remove the progress box
-    if (frame.progress !== undefined) {
-      frame.removeChild(frame.progress);
-      frame.progress = undefined;
-    }
-
-    if (this.onLoadCallback)
-      this.onLoadCallback();
-  }
-};
-
-
-
-/**
- * @prototype StepNumber
- * The class StepNumber is an iterator for Numbers. You provide a start and end
- * value, and a best step size. StepNumber itself rounds to fixed values and
- * a finds the step that best fits the provided step.
- *
- * If prettyStep is true, the step size is chosen as close as possible to the
- * provided step, but being a round value like 1, 2, 5, 10, 20, 50, ....
- *
- * Example usage:
- *   var step = new StepNumber(0, 10, 2.5, true);
- *   step.start();
- *   while (!step.end()) {
- *   alert(step.getCurrent());
- *   step.next();
- *   }
- *
- * Version: 1.0
- *
- * @param {Number} start     The start value
- * @param {Number} end     The end value
- * @param {Number} step    Optional. Step size. Must be a positive value.
- * @param {boolean} prettyStep Optional. If true, the step size is rounded
- *               To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
- */
-StepNumber = function (start, end, step, prettyStep) {
-  // set default values
-  this._start = 0;
-  this._end = 0;
-  this._step = 1;
-  this.prettyStep = true;
-  this.precision = 5;
-
-  this._current = 0;
-  this.setRange(start, end, step, prettyStep);
-};
-
-/**
- * Set a new range: start, end and step.
- *
- * @param {Number} start     The start value
- * @param {Number} end     The end value
- * @param {Number} step    Optional. Step size. Must be a positive value.
- * @param {boolean} prettyStep Optional. If true, the step size is rounded
- *               To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
- */
-StepNumber.prototype.setRange = function(start, end, step, prettyStep) {
-  this._start = start ? start : 0;
-  this._end = end ? end : 0;
-
-  this.setStep(step, prettyStep);
-};
-
-/**
- * Set a new step size
- * @param {Number} step    New step size. Must be a positive value
- * @param {boolean} prettyStep Optional. If true, the provided step is rounded
- *               to a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
- */
-StepNumber.prototype.setStep = function(step, prettyStep) {
-  if (step === undefined || step <= 0)
-    return;
-
-  if (prettyStep !== undefined)
-    this.prettyStep = prettyStep;
-
-  if (this.prettyStep === true)
-    this._step = StepNumber.calculatePrettyStep(step);
-  else
-    this._step = step;
-};
-
-/**
- * Calculate a nice step size, closest to the desired step size.
- * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an
- * integer Number. For example 1, 2, 5, 10, 20, 50, etc...
- * @param {Number}  step  Desired step size
- * @return {Number}     Nice step size
- */
-StepNumber.calculatePrettyStep = function (step) {
-  var log10 = function (x) {return Math.log(x) / Math.LN10;};
-
-  // try three steps (multiple of 1, 2, or 5
-  var step1 = Math.pow(10, Math.round(log10(step))),
-    step2 = 2 * Math.pow(10, Math.round(log10(step / 2))),
-    step5 = 5 * Math.pow(10, Math.round(log10(step / 5)));
-
-  // choose the best step (closest to minimum step)
-  var prettyStep = step1;
-  if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2;
-  if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5;
-
-  // for safety
-  if (prettyStep <= 0) {
-    prettyStep = 1;
-  }
-
-  return prettyStep;
-};
-
-/**
- * returns the current value of the step
- * @return {Number} current value
- */
-StepNumber.prototype.getCurrent = function () {
-  return parseFloat(this._current.toPrecision(this.precision));
-};
-
-/**
- * returns the current step size
- * @return {Number} current step size
- */
-StepNumber.prototype.getStep = function () {
-  return this._step;
-};
-
-/**
- * Set the current value to the largest value smaller than start, which
- * is a multiple of the step size
- */
-StepNumber.prototype.start = function() {
-  this._current = this._start - this._start % this._step;
-};
-
-/**
- * Do a step, add the step size to the current value
- */
-StepNumber.prototype.next = function () {
-  this._current += this._step;
-};
-
-/**
- * Returns true whether the end is reached
- * @return {boolean}  True if the current value has passed the end value.
- */
-StepNumber.prototype.end = function () {
-  return (this._current > this._end);
-};
-
-
-/**
- * @constructor Slider
- *
- * An html slider control with start/stop/prev/next buttons
- * @param {Element} container  The element where the slider will be created
- * @param {Object} options   Available options:
- *                 {boolean} visible   If true (default) the
- *                           slider is visible.
- */
-function Slider(container, options) {
-  if (container === undefined) {
-    throw 'Error: No container element defined';
-  }
-  this.container = container;
-  this.visible = (options && options.visible != undefined) ? options.visible : true;
-
-  if (this.visible) {
-    this.frame = document.createElement('DIV');
-    //this.frame.style.backgroundColor = '#E5E5E5';
-    this.frame.style.width = '100%';
-    this.frame.style.position = 'relative';
-    this.container.appendChild(this.frame);
-
-    this.frame.prev = document.createElement('INPUT');
-    this.frame.prev.type = 'BUTTON';
-    this.frame.prev.value = 'Prev';
-    this.frame.appendChild(this.frame.prev);
-
-    this.frame.play = document.createElement('INPUT');
-    this.frame.play.type = 'BUTTON';
-    this.frame.play.value = 'Play';
-    this.frame.appendChild(this.frame.play);
-
-    this.frame.next = document.createElement('INPUT');
-    this.frame.next.type = 'BUTTON';
-    this.frame.next.value = 'Next';
-    this.frame.appendChild(this.frame.next);
-
-    this.frame.bar = document.createElement('INPUT');
-    this.frame.bar.type = 'BUTTON';
-    this.frame.bar.style.position = 'absolute';
-    this.frame.bar.style.border = '1px solid red';
-    this.frame.bar.style.width = '100px';
-    this.frame.bar.style.height = '6px';
-    this.frame.bar.style.borderRadius = '2px';
-    this.frame.bar.style.MozBorderRadius = '2px';
-    this.frame.bar.style.border = '1px solid #7F7F7F';
-    this.frame.bar.style.backgroundColor = '#E5E5E5';
-    this.frame.appendChild(this.frame.bar);
-
-    this.frame.slide = document.createElement('INPUT');
-    this.frame.slide.type = 'BUTTON';
-    this.frame.slide.style.margin = '0px';
-    this.frame.slide.value = ' ';
-    this.frame.slide.style.position = 'relative';
-    this.frame.slide.style.left = '-100px';
-    this.frame.appendChild(this.frame.slide);
-
-    // create events
-    var me = this;
-    this.frame.slide.onmousedown = function (event) {me._onMouseDown(event);};
-    this.frame.prev.onclick = function (event) {me.prev(event);};
-    this.frame.play.onclick = function (event) {me.togglePlay(event);};
-    this.frame.next.onclick = function (event) {me.next(event);};
-  }
-
-  this.onChangeCallback = undefined;
-
-  this.values = [];
-  this.index = undefined;
-
-  this.playTimeout = undefined;
-  this.playInterval = 1000; // milliseconds
-  this.playLoop = true;
-};
-
-/**
- * Select the previous index
- */
-Slider.prototype.prev = function() {
-  var index = this.getIndex();
-  if (index > 0) {
-    index--;
-    this.setIndex(index);
-  }
-};
-
-/**
- * Select the next index
- */
-Slider.prototype.next = function() {
-  var index = this.getIndex();
-  if (index < this.values.length - 1) {
-    index++;
-    this.setIndex(index);
-  }
-};
-
-/**
- * Select the next index
- */
-Slider.prototype.playNext = function() {
-  var start = new Date();
-
-  var index = this.getIndex();
-  if (index < this.values.length - 1) {
-    index++;
-    this.setIndex(index);
-  }
-  else if (this.playLoop) {
-    // jump to the start
-    index = 0;
-    this.setIndex(index);
-  }
-
-  var end = new Date();
-  var diff = (end - start);
-
-  // calculate how much time it to to set the index and to execute the callback
-  // function.
-  var interval = Math.max(this.playInterval - diff, 0);
-  // document.title = diff // TODO: cleanup
-
-  var me = this;
-  this.playTimeout = setTimeout(function() {me.playNext();}, interval);
-};
-
-/**
- * Toggle start or stop playing
- */
-Slider.prototype.togglePlay = function() {
-  if (this.playTimeout === undefined) {
-    this.play();
-  } else {
-    this.stop();
-  }
-};
-
-/**
- * Start playing
- */
-Slider.prototype.play = function() {
-  // Test whether already playing
-  if (this.playTimeout) return;
-
-  this.playNext();
-
-  if (this.frame) {
-    this.frame.play.value = 'Stop';
-  }
-};
-
-/**
- * Stop playing
- */
-Slider.prototype.stop = function() {
-  clearInterval(this.playTimeout);
-  this.playTimeout = undefined;
-
-  if (this.frame) {
-    this.frame.play.value = 'Play';
-  }
-};
-
-/**
- * Set a callback function which will be triggered when the value of the
- * slider bar has changed.
- */
-Slider.prototype.setOnChangeCallback = function(callback) {
-  this.onChangeCallback = callback;
-};
-
-/**
- * Set the interval for playing the list
- * @param {Number} interval   The interval in milliseconds
- */
-Slider.prototype.setPlayInterval = function(interval) {
-  this.playInterval = interval;
-};
-
-/**
- * Retrieve the current play interval
- * @return {Number} interval   The interval in milliseconds
- */
-Slider.prototype.getPlayInterval = function(interval) {
-  return this.playInterval;
-};
-
-/**
- * Set looping on or off
- * @pararm {boolean} doLoop  If true, the slider will jump to the start when
- *               the end is passed, and will jump to the end
- *               when the start is passed.
- */
-Slider.prototype.setPlayLoop = function(doLoop) {
-  this.playLoop = doLoop;
-};
-
-
-/**
- * Execute the onchange callback function
- */
-Slider.prototype.onChange = function() {
-  if (this.onChangeCallback !== undefined) {
-    this.onChangeCallback();
-  }
-};
-
-/**
- * redraw the slider on the correct place
- */
-Slider.prototype.redraw = function() {
-  if (this.frame) {
-    // resize the bar
-    this.frame.bar.style.top = (this.frame.clientHeight/2 -
-      this.frame.bar.offsetHeight/2) + 'px';
-    this.frame.bar.style.width = (this.frame.clientWidth -
-      this.frame.prev.clientWidth -
-      this.frame.play.clientWidth -
-      this.frame.next.clientWidth - 30)  + 'px';
-
-    // position the slider button
-    var left = this.indexToLeft(this.index);
-    this.frame.slide.style.left = (left) + 'px';
-  }
-};
-
-
-/**
- * Set the list with values for the slider
- * @param {Array} values   A javascript array with values (any type)
- */
-Slider.prototype.setValues = function(values) {
-  this.values = values;
-
-  if (this.values.length > 0)
-    this.setIndex(0);
-  else
-    this.index = undefined;
-};
-
-/**
- * Select a value by its index
- * @param {Number} index
- */
-Slider.prototype.setIndex = function(index) {
-  if (index < this.values.length) {
-    this.index = index;
-
-    this.redraw();
-    this.onChange();
-  }
-  else {
-    throw 'Error: index out of range';
-  }
-};
-
-/**
- * retrieve the index of the currently selected vaue
- * @return {Number} index
- */
-Slider.prototype.getIndex = function() {
-  return this.index;
-};
-
-
-/**
- * retrieve the currently selected value
- * @return {*} value
- */
-Slider.prototype.get = function() {
-  return this.values[this.index];
-};
-
-
-Slider.prototype._onMouseDown = function(event) {
-  // only react on left mouse button down
-  var leftButtonDown = event.which ? (event.which === 1) : (event.button === 1);
-  if (!leftButtonDown) return;
-
-  this.startClientX = event.clientX;
-  this.startSlideX = parseFloat(this.frame.slide.style.left);
-
-  this.frame.style.cursor = 'move';
-
-  // add event listeners to handle moving the contents
-  // we store the function onmousemove and onmouseup in the graph, so we can
-  // remove the eventlisteners lateron in the function mouseUp()
-  var me = this;
-  this.onmousemove = function (event) {me._onMouseMove(event);};
-  this.onmouseup   = function (event) {me._onMouseUp(event);};
-  G3DaddEventListener(document, 'mousemove', this.onmousemove);
-  G3DaddEventListener(document, 'mouseup',   this.onmouseup);
-  G3DpreventDefault(event);
-};
-
-
-Slider.prototype.leftToIndex = function (left) {
-  var width = parseFloat(this.frame.bar.style.width) -
-    this.frame.slide.clientWidth - 10;
-  var x = left - 3;
-
-  var index = Math.round(x / width * (this.values.length-1));
-  if (index < 0) index = 0;
-  if (index > this.values.length-1) index = this.values.length-1;
-
-  return index;
-};
-
-Slider.prototype.indexToLeft = function (index) {
-  var width = parseFloat(this.frame.bar.style.width) -
-    this.frame.slide.clientWidth - 10;
-
-  var x = index / (this.values.length-1) * width;
-  var left = x + 3;
-
-  return left;
-};
-
-
-
-Slider.prototype._onMouseMove = function (event) {
-  var diff = event.clientX - this.startClientX;
-  var x = this.startSlideX + diff;
-
-  var index = this.leftToIndex(x);
-
-  this.setIndex(index);
-
-  G3DpreventDefault();
-};
-
-
-Slider.prototype._onMouseUp = function (event) {
-  this.frame.style.cursor = 'auto';
-
-  // remove event listeners
-  G3DremoveEventListener(document, 'mousemove', this.onmousemove);
-  G3DremoveEventListener(document, 'mouseup', this.onmouseup);
-
-  G3DpreventDefault();
-};
-
-
-
-/**--------------------------------------------------------------------------**/
-
-
-
-/**
- * Retrieve the absolute left value of a DOM element
- * @param {Element} elem  A dom element, for example a div
- * @return {Number} left    The absolute left position of this element
- *                in the browser page.
- */
-getAbsoluteLeft = function(elem) {
-  var left = 0;
-  while( elem !== null ) {
-    left += elem.offsetLeft;
-    left -= elem.scrollLeft;
-    elem = elem.offsetParent;
-  }
-  return left;
-};
-
-/**
- * Retrieve the absolute top value of a DOM element
- * @param {Element} elem  A dom element, for example a div
- * @return {Number} top     The absolute top position of this element
- *                in the browser page.
- */
-getAbsoluteTop = function(elem) {
-  var top = 0;
-  while( elem !== null ) {
-    top += elem.offsetTop;
-    top -= elem.scrollTop;
-    elem = elem.offsetParent;
-  }
-  return top;
-};
-
-/**
- * Get the horizontal mouse position from a mouse event
- * @param {Event} event
- * @return {Number} mouse x
- */
-getMouseX = function(event) {
-  if ('clientX' in event) return event.clientX;
-  return event.targetTouches[0] && event.targetTouches[0].clientX || 0;
-};
-
-/**
- * Get the vertical mouse position from a mouse event
- * @param {Event} event
- * @return {Number} mouse y
- */
-getMouseY = function(event) {
-  if ('clientY' in event) return event.clientY;
-  return event.targetTouches[0] && event.targetTouches[0].clientY || 0;
-};
-
-
-/**
- * vis.js module exports
- */
-var vis = {
-  util: util,
-  moment: moment,
-
-  DataSet: DataSet,
-  DataView: DataView,
-  Range: Range,
-  stack: stack,
-  TimeStep: TimeStep,
-
-  components: {
-    items: {
-      Item: Item,
-      ItemBox: ItemBox,
-      ItemPoint: ItemPoint,
-      ItemRange: ItemRange
-    },
-
-    Component: Component,
-    ItemSet: ItemSet,
-    TimeAxis: TimeAxis
-  },
-
-  graph: {
-    Node: Node,
-    Edge: Edge,
-    Popup: Popup,
-    Groups: Groups,
-    Images: Images
-  },
-
-  Timeline: Timeline,
-  Graph: Graph,
-  Graph3d: Graph3d
-};
-
-/**
- * CommonJS module exports
- */
-if (typeof exports !== 'undefined') {
-  exports = vis;
-}
-if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
-  module.exports = vis;
-}
-
-/**
- * AMD module exports
- */
-if (typeof(define) === 'function') {
-  define(function () {
-    return vis;
-  });
-}
-
-/**
- * Window exports
- */
-if (typeof window !== 'undefined') {
-  // attach the module to the window, load as a regular javascript file
-  window['vis'] = vis;
-}
-
-
-},{"emitter-component":2,"hammerjs":3,"moment":4,"mousetrap":5}],2:[function(require,module,exports){
-
-/**
- * Expose `Emitter`.
- */
-
-module.exports = Emitter;
-
-/**
- * Initialize a new `Emitter`.
- *
- * @api public
- */
-
-function Emitter(obj) {
-  if (obj) return mixin(obj);
-};
-
-/**
- * Mixin the emitter properties.
- *
- * @param {Object} obj
- * @return {Object}
- * @api private
- */
-
-function mixin(obj) {
-  for (var key in Emitter.prototype) {
-    obj[key] = Emitter.prototype[key];
-  }
-  return obj;
-}
-
-/**
- * Listen on the given `event` with `fn`.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- * @api public
- */
-
-Emitter.prototype.on =
-Emitter.prototype.addEventListener = function(event, fn){
-  this._callbacks = this._callbacks || {};
-  (this._callbacks[event] = this._callbacks[event] || [])
-    .push(fn);
-  return this;
-};
-
-/**
- * Adds an `event` listener that will be invoked a single
- * time then automatically removed.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- * @api public
- */
-
-Emitter.prototype.once = function(event, fn){
-  var self = this;
-  this._callbacks = this._callbacks || {};
-
-  function on() {
-    self.off(event, on);
-    fn.apply(this, arguments);
-  }
-
-  on.fn = fn;
-  this.on(event, on);
-  return this;
-};
-
-/**
- * Remove the given callback for `event` or all
- * registered callbacks.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- * @api public
- */
-
-Emitter.prototype.off =
-Emitter.prototype.removeListener =
-Emitter.prototype.removeAllListeners =
-Emitter.prototype.removeEventListener = function(event, fn){
-  this._callbacks = this._callbacks || {};
-
-  // all
-  if (0 == arguments.length) {
-    this._callbacks = {};
-    return this;
-  }
-
-  // specific event
-  var callbacks = this._callbacks[event];
-  if (!callbacks) return this;
-
-  // remove all handlers
-  if (1 == arguments.length) {
-    delete this._callbacks[event];
-    return this;
-  }
-
-  // remove specific handler
-  var cb;
-  for (var i = 0; i < callbacks.length; i++) {
-    cb = callbacks[i];
-    if (cb === fn || cb.fn === fn) {
-      callbacks.splice(i, 1);
-      break;
-    }
-  }
-  return this;
-};
-
-/**
- * Emit `event` with the given args.
- *
- * @param {String} event
- * @param {Mixed} ...
- * @return {Emitter}
- */
-
-Emitter.prototype.emit = function(event){
-  this._callbacks = this._callbacks || {};
-  var args = [].slice.call(arguments, 1)
-    , callbacks = this._callbacks[event];
-
-  if (callbacks) {
-    callbacks = callbacks.slice(0);
-    for (var i = 0, len = callbacks.length; i < len; ++i) {
-      callbacks[i].apply(this, args);
-    }
-  }
-
-  return this;
-};
-
-/**
- * Return array of callbacks for `event`.
- *
- * @param {String} event
- * @return {Array}
- * @api public
- */
-
-Emitter.prototype.listeners = function(event){
-  this._callbacks = this._callbacks || {};
-  return this._callbacks[event] || [];
-};
-
-/**
- * Check if this emitter has `event` handlers.
- *
- * @param {String} event
- * @return {Boolean}
- * @api public
- */
-
-Emitter.prototype.hasListeners = function(event){
-  return !! this.listeners(event).length;
-};
-
-},{}],3:[function(require,module,exports){
-/*! Hammer.JS - v1.0.5 - 2013-04-07
- * http://eightmedia.github.com/hammer.js
- *
- * Copyright (c) 2013 Jorik Tangelder <j.tangelder@gmail.com>;
- * Licensed under the MIT license */
-
-(function(window, undefined) {
-    'use strict';
-
-/**
- * Hammer
- * use this to create instances
- * @param   {HTMLElement}   element
- * @param   {Object}        options
- * @returns {Hammer.Instance}
- * @constructor
- */
-var Hammer = function(element, options) {
-    return new Hammer.Instance(element, options || {});
-};
-
-// default settings
-Hammer.defaults = {
-    // add styles and attributes to the element to prevent the browser from doing
-    // its native behavior. this doesnt prevent the scrolling, but cancels
-    // the contextmenu, tap highlighting etc
-    // set to false to disable this
-    stop_browser_behavior: {
-               // this also triggers onselectstart=false for IE
-        userSelect: 'none',
-               // this makes the element blocking in IE10 >, you could experiment with the value
-               // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241
-        touchAction: 'none',
-               touchCallout: 'none',
-        contentZooming: 'none',
-        userDrag: 'none',
-        tapHighlightColor: 'rgba(0,0,0,0)'
-    }
-
-    // more settings are defined per gesture at gestures.js
-};
-
-// detect touchevents
-Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled;
-Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window);
-
-// dont use mouseevents on mobile devices
-Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
-Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX);
-
-// eventtypes per touchevent (start, move, end)
-// are filled by Hammer.event.determineEventTypes on setup
-Hammer.EVENT_TYPES = {};
-
-// direction defines
-Hammer.DIRECTION_DOWN = 'down';
-Hammer.DIRECTION_LEFT = 'left';
-Hammer.DIRECTION_UP = 'up';
-Hammer.DIRECTION_RIGHT = 'right';
-
-// pointer type
-Hammer.POINTER_MOUSE = 'mouse';
-Hammer.POINTER_TOUCH = 'touch';
-Hammer.POINTER_PEN = 'pen';
-
-// touch event defines
-Hammer.EVENT_START = 'start';
-Hammer.EVENT_MOVE = 'move';
-Hammer.EVENT_END = 'end';
-
-// hammer document where the base events are added at
-Hammer.DOCUMENT = document;
-
-// plugins namespace
-Hammer.plugins = {};
-
-// if the window events are set...
-Hammer.READY = false;
-
-/**
- * setup events to detect gestures on the document
- */
-function setup() {
-    if(Hammer.READY) {
-        return;
-    }
-
-    // find what eventtypes we add listeners to
-    Hammer.event.determineEventTypes();
-
-    // Register all gestures inside Hammer.gestures
-    for(var name in Hammer.gestures) {
-        if(Hammer.gestures.hasOwnProperty(name)) {
-            Hammer.detection.register(Hammer.gestures[name]);
-        }
-    }
-
-    // Add touch events on the document
-    Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect);
-    Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect);
-
-    // Hammer is ready...!
-    Hammer.READY = true;
-}
-
-/**
- * create new hammer instance
- * all methods should return the instance itself, so it is chainable.
- * @param   {HTMLElement}       element
- * @param   {Object}            [options={}]
- * @returns {Hammer.Instance}
- * @constructor
- */
-Hammer.Instance = function(element, options) {
-    var self = this;
-
-    // setup HammerJS window events and register all gestures
-    // this also sets up the default options
-    setup();
-
-    this.element = element;
-
-    // start/stop detection option
-    this.enabled = true;
-
-    // merge options
-    this.options = Hammer.utils.extend(
-        Hammer.utils.extend({}, Hammer.defaults),
-        options || {});
-
-    // add some css to the element to prevent the browser from doing its native behavoir
-    if(this.options.stop_browser_behavior) {
-        Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior);
-    }
-
-    // start detection on touchstart
-    Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) {
-        if(self.enabled) {
-            Hammer.detection.startDetect(self, ev);
-        }
-    });
-
-    // return instance
-    return this;
-};
-
-
-Hammer.Instance.prototype = {
-    /**
-     * bind events to the instance
-     * @param   {String}      gesture
-     * @param   {Function}    handler
-     * @returns {Hammer.Instance}
-     */
-    on: function onEvent(gesture, handler){
-        var gestures = gesture.split(' ');
-        for(var t=0; t<gestures.length; t++) {
-            this.element.addEventListener(gestures[t], handler, false);
-        }
-        return this;
-    },
-
-
-    /**
-     * unbind events to the instance
-     * @param   {String}      gesture
-     * @param   {Function}    handler
-     * @returns {Hammer.Instance}
-     */
-    off: function offEvent(gesture, handler){
-        var gestures = gesture.split(' ');
-        for(var t=0; t<gestures.length; t++) {
-            this.element.removeEventListener(gestures[t], handler, false);
-        }
-        return this;
-    },
-
-
-    /**
-     * trigger gesture event
-     * @param   {String}      gesture
-     * @param   {Object}      eventData
-     * @returns {Hammer.Instance}
-     */
-    trigger: function triggerEvent(gesture, eventData){
-        // create DOM event
-        var event = Hammer.DOCUMENT.createEvent('Event');
-               event.initEvent(gesture, true, true);
-               event.gesture = eventData;
-
-        // trigger on the target if it is in the instance element,
-        // this is for event delegation tricks
-        var element = this.element;
-        if(Hammer.utils.hasParent(eventData.target, element)) {
-            element = eventData.target;
-        }
-
-        element.dispatchEvent(event);
-        return this;
-    },
-
-
-    /**
-     * enable of disable hammer.js detection
-     * @param   {Boolean}   state
-     * @returns {Hammer.Instance}
-     */
-    enable: function enable(state) {
-        this.enabled = state;
-        return this;
-    }
-};
-
-/**
- * this holds the last move event,
- * used to fix empty touchend issue
- * see the onTouch event for an explanation
- * @type {Object}
- */
-var last_move_event = null;
-
-
-/**
- * when the mouse is hold down, this is true
- * @type {Boolean}
- */
-var enable_detect = false;
-
-
-/**
- * when touch events have been fired, this is true
- * @type {Boolean}
- */
-var touch_triggered = false;
-
-
-Hammer.event = {
-    /**
-     * simple addEventListener
-     * @param   {HTMLElement}   element
-     * @param   {String}        type
-     * @param   {Function}      handler
-     */
-    bindDom: function(element, type, handler) {
-        var types = type.split(' ');
-        for(var t=0; t<types.length; t++) {
-            element.addEventListener(types[t], handler, false);
-        }
-    },
-
-
-    /**
-     * touch events with mouse fallback
-     * @param   {HTMLElement}   element
-     * @param   {String}        eventType        like Hammer.EVENT_MOVE
-     * @param   {Function}      handler
-     */
-    onTouch: function onTouch(element, eventType, handler) {
-               var self = this;
-
-        this.bindDom(element, Hammer.EVENT_TYPES[eventType], function bindDomOnTouch(ev) {
-            var sourceEventType = ev.type.toLowerCase();
-
-            // onmouseup, but when touchend has been fired we do nothing.
-            // this is for touchdevices which also fire a mouseup on touchend
-            if(sourceEventType.match(/mouse/) && touch_triggered) {
-                return;
-            }
-
-            // mousebutton must be down or a touch event
-            else if( sourceEventType.match(/touch/) ||   // touch events are always on screen
-                sourceEventType.match(/pointerdown/) || // pointerevents touch
-                (sourceEventType.match(/mouse/) && ev.which === 1)   // mouse is pressed
-            ){
-                enable_detect = true;
-            }
-
-            // we are in a touch event, set the touch triggered bool to true,
-            // this for the conflicts that may occur on ios and android
-            if(sourceEventType.match(/touch|pointer/)) {
-                touch_triggered = true;
-            }
-
-            // count the total touches on the screen
-            var count_touches = 0;
-
-            // when touch has been triggered in this detection session
-            // and we are now handling a mouse event, we stop that to prevent conflicts
-            if(enable_detect) {
-                // update pointerevent
-                if(Hammer.HAS_POINTEREVENTS && eventType != Hammer.EVENT_END) {
-                    count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
-                }
-                // touch
-                else if(sourceEventType.match(/touch/)) {
-                    count_touches = ev.touches.length;
-                }
-                // mouse
-                else if(!touch_triggered) {
-                    count_touches = sourceEventType.match(/up/) ? 0 : 1;
-                }
-
-                // if we are in a end event, but when we remove one touch and
-                // we still have enough, set eventType to move
-                if(count_touches > 0 && eventType == Hammer.EVENT_END) {
-                    eventType = Hammer.EVENT_MOVE;
-                }
-                // no touches, force the end event
-                else if(!count_touches) {
-                    eventType = Hammer.EVENT_END;
-                }
-
-                // because touchend has no touches, and we often want to use these in our gestures,
-                // we send the last move event as our eventData in touchend
-                if(!count_touches && last_move_event !== null) {
-                    ev = last_move_event;
-                }
-                // store the last move event
-                else {
-                    last_move_event = ev;
-                }
-
-                // trigger the handler
-                handler.call(Hammer.detection, self.collectEventData(element, eventType, ev));
-
-                // remove pointerevent from list
-                if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) {
-                    count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
-                }
-            }
-
-            //debug(sourceEventType +" "+ eventType);
-
-            // on the end we reset everything
-            if(!count_touches) {
-                last_move_event = null;
-                enable_detect = false;
-                touch_triggered = false;
-                Hammer.PointerEvent.reset();
-            }
-        });
-    },
-
-
-    /**
-     * we have different events for each device/browser
-     * determine what we need and set them in the Hammer.EVENT_TYPES constant
-     */
-    determineEventTypes: function determineEventTypes() {
-        // determine the eventtype we want to set
-        var types;
-
-        // pointerEvents magic
-        if(Hammer.HAS_POINTEREVENTS) {
-            types = Hammer.PointerEvent.getEvents();
-        }
-        // on Android, iOS, blackberry, windows mobile we dont want any mouseevents
-        else if(Hammer.NO_MOUSEEVENTS) {
-            types = [
-                'touchstart',
-                'touchmove',
-                'touchend touchcancel'];
-        }
-        // for non pointer events browsers and mixed browsers,
-        // like chrome on windows8 touch laptop
-        else {
-            types = [
-                'touchstart mousedown',
-                'touchmove mousemove',
-                'touchend touchcancel mouseup'];
-        }
-
-        Hammer.EVENT_TYPES[Hammer.EVENT_START]  = types[0];
-        Hammer.EVENT_TYPES[Hammer.EVENT_MOVE]   = types[1];
-        Hammer.EVENT_TYPES[Hammer.EVENT_END]    = types[2];
-    },
-
-
-    /**
-     * create touchlist depending on the event
-     * @param   {Object}    ev
-     * @param   {String}    eventType   used by the fakemultitouch plugin
-     */
-    getTouchList: function getTouchList(ev/*, eventType*/) {
-        // get the fake pointerEvent touchlist
-        if(Hammer.HAS_POINTEREVENTS) {
-            return Hammer.PointerEvent.getTouchList();
-        }
-        // get the touchlist
-        else if(ev.touches) {
-            return ev.touches;
-        }
-        // make fake touchlist from mouse position
-        else {
-            return [{
-                identifier: 1,
-                pageX: ev.pageX,
-                pageY: ev.pageY,
-                target: ev.target
-            }];
-        }
-    },
-
-
-    /**
-     * collect event data for Hammer js
-     * @param   {HTMLElement}   element
-     * @param   {String}        eventType        like Hammer.EVENT_MOVE
-     * @param   {Object}        eventData
-     */
-    collectEventData: function collectEventData(element, eventType, ev) {
-        var touches = this.getTouchList(ev, eventType);
-
-        // find out pointerType
-        var pointerType = Hammer.POINTER_TOUCH;
-        if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) {
-            pointerType = Hammer.POINTER_MOUSE;
-        }
-
-        return {
-            center      : Hammer.utils.getCenter(touches),
-            timeStamp   : new Date().getTime(),
-            target      : ev.target,
-            touches     : touches,
-            eventType   : eventType,
-            pointerType : pointerType,
-            srcEvent    : ev,
-
-            /**
-             * prevent the browser default actions
-             * mostly used to disable scrolling of the browser
-             */
-            preventDefault: function() {
-                if(this.srcEvent.preventManipulation) {
-                    this.srcEvent.preventManipulation();
-                }
-
-                if(this.srcEvent.preventDefault) {
-                    this.srcEvent.preventDefault();
-                }
-            },
-
-            /**
-             * stop bubbling the event up to its parents
-             */
-            stopPropagation: function() {
-                this.srcEvent.stopPropagation();
-            },
-
-            /**
-             * immediately stop gesture detection
-             * might be useful after a swipe was detected
-             * @return {*}
-             */
-            stopDetect: function() {
-                return Hammer.detection.stopDetect();
-            }
-        };
-    }
-};
-
-Hammer.PointerEvent = {
-    /**
-     * holds all pointers
-     * @type {Object}
-     */
-    pointers: {},
-
-    /**
-     * get a list of pointers
-     * @returns {Array}     touchlist
-     */
-    getTouchList: function() {
-        var self = this;
-        var touchlist = [];
-
-        // we can use forEach since pointerEvents only is in IE10
-        Object.keys(self.pointers).sort().forEach(function(id) {
-            touchlist.push(self.pointers[id]);
-        });
-        return touchlist;
-    },
-
-    /**
-     * update the position of a pointer
-     * @param   {String}   type             Hammer.EVENT_END
-     * @param   {Object}   pointerEvent
-     */
-    updatePointer: function(type, pointerEvent) {
-        if(type == Hammer.EVENT_END) {
-            this.pointers = {};
-        }
-        else {
-            pointerEvent.identifier = pointerEvent.pointerId;
-            this.pointers[pointerEvent.pointerId] = pointerEvent;
-        }
-
-        return Object.keys(this.pointers).length;
-    },
-
-    /**
-     * check if ev matches pointertype
-     * @param   {String}        pointerType     Hammer.POINTER_MOUSE
-     * @param   {PointerEvent}  ev
-     */
-    matchType: function(pointerType, ev) {
-        if(!ev.pointerType) {
-            return false;
-        }
-
-        var types = {};
-        types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE);
-        types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH);
-        types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN);
-        return types[pointerType];
-    },
-
-
-    /**
-     * get events
-     */
-    getEvents: function() {
-        return [
-            'pointerdown MSPointerDown',
-            'pointermove MSPointerMove',
-            'pointerup pointercancel MSPointerUp MSPointerCancel'
-        ];
-    },
-
-    /**
-     * reset the list
-     */
-    reset: function() {
-        this.pointers = {};
-    }
-};
-
-
-Hammer.utils = {
-    /**
-     * extend method,
-     * also used for cloning when dest is an empty object
-     * @param   {Object}    dest
-     * @param   {Object}    src
-        * @parm        {Boolean}       merge           do a merge
-     * @returns {Object}    dest
-     */
-    extend: function extend(dest, src, merge) {
-        for (var key in src) {
-                       if(dest[key] !== undefined && merge) {
-                               continue;
-                       }
-            dest[key] = src[key];
-        }
-        return dest;
-    },
-
-
-    /**
-     * find if a node is in the given parent
-     * used for event delegation tricks
-     * @param   {HTMLElement}   node
-     * @param   {HTMLElement}   parent
-     * @returns {boolean}       has_parent
-     */
-    hasParent: function(node, parent) {
-        while(node){
-            if(node == parent) {
-                return true;
-            }
-            node = node.parentNode;
-        }
-        return false;
-    },
-
-
-    /**
-     * get the center of all the touches
-     * @param   {Array}     touches
-     * @returns {Object}    center
-     */
-    getCenter: function getCenter(touches) {
-        var valuesX = [], valuesY = [];
-
-        for(var t= 0,len=touches.length; t<len; t++) {
-            valuesX.push(touches[t].pageX);
-            valuesY.push(touches[t].pageY);
-        }
-
-        return {
-            pageX: ((Math.min.apply(Math, valuesX) + Math.max.apply(Math, valuesX)) / 2),
-            pageY: ((Math.min.apply(Math, valuesY) + Math.max.apply(Math, valuesY)) / 2)
-        };
-    },
-
-
-    /**
-     * calculate the velocity between two points
-     * @param   {Number}    delta_time
-     * @param   {Number}    delta_x
-     * @param   {Number}    delta_y
-     * @returns {Object}    velocity
-     */
-    getVelocity: function getVelocity(delta_time, delta_x, delta_y) {
-        return {
-            x: Math.abs(delta_x / delta_time) || 0,
-            y: Math.abs(delta_y / delta_time) || 0
-        };
-    },
-
-
-    /**
-     * calculate the angle between two coordinates
-     * @param   {Touch}     touch1
-     * @param   {Touch}     touch2
-     * @returns {Number}    angle
-     */
-    getAngle: function getAngle(touch1, touch2) {
-        var y = touch2.pageY - touch1.pageY,
-            x = touch2.pageX - touch1.pageX;
-        return Math.atan2(y, x) * 180 / Math.PI;
-    },
-
-
-    /**
-     * angle to direction define
-     * @param   {Touch}     touch1
-     * @param   {Touch}     touch2
-     * @returns {String}    direction constant, like Hammer.DIRECTION_LEFT
-     */
-    getDirection: function getDirection(touch1, touch2) {
-        var x = Math.abs(touch1.pageX - touch2.pageX),
-            y = Math.abs(touch1.pageY - touch2.pageY);
-
-        if(x >= y) {
-            return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;
-        }
-        else {
-            return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;
-        }
-    },
-
-
-    /**
-     * calculate the distance between two touches
-     * @param   {Touch}     touch1
-     * @param   {Touch}     touch2
-     * @returns {Number}    distance
-     */
-    getDistance: function getDistance(touch1, touch2) {
-        var x = touch2.pageX - touch1.pageX,
-            y = touch2.pageY - touch1.pageY;
-        return Math.sqrt((x*x) + (y*y));
-    },
-
-
-    /**
-     * calculate the scale factor between two touchLists (fingers)
-     * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
-     * @param   {Array}     start
-     * @param   {Array}     end
-     * @returns {Number}    scale
-     */
-    getScale: function getScale(start, end) {
-        // need two fingers...
-        if(start.length >= 2 && end.length >= 2) {
-            return this.getDistance(end[0], end[1]) /
-                this.getDistance(start[0], start[1]);
-        }
-        return 1;
-    },
-
-
-    /**
-     * calculate the rotation degrees between two touchLists (fingers)
-     * @param   {Array}     start
-     * @param   {Array}     end
-     * @returns {Number}    rotation
-     */
-    getRotation: function getRotation(start, end) {
-        // need two fingers
-        if(start.length >= 2 && end.length >= 2) {
-            return this.getAngle(end[1], end[0]) -
-                this.getAngle(start[1], start[0]);
-        }
-        return 0;
-    },
-
-
-    /**
-     * boolean if the direction is vertical
-     * @param    {String}    direction
-     * @returns  {Boolean}   is_vertical
-     */
-    isVertical: function isVertical(direction) {
-        return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN);
-    },
-
-
-    /**
-     * stop browser default behavior with css props
-     * @param   {HtmlElement}   element
-     * @param   {Object}        css_props
-     */
-    stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) {
-        var prop,
-            vendors = ['webkit','khtml','moz','ms','o',''];
-
-        if(!css_props || !element.style) {
-            return;
-        }
-
-        // with css properties for modern browsers
-        for(var i = 0; i < vendors.length; i++) {
-            for(var p in css_props) {
-                if(css_props.hasOwnProperty(p)) {
-                    prop = p;
-
-                    // vender prefix at the property
-                    if(vendors[i]) {
-                        prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1);
-                    }
-
-                    // set the style
-                    element.style[prop] = css_props[p];
-                }
-            }
-        }
-
-        // also the disable onselectstart
-        if(css_props.userSelect == 'none') {
-            element.onselectstart = function() {
-                return false;
-            };
-        }
-    }
-};
-
-Hammer.detection = {
-    // contains all registred Hammer.gestures in the correct order
-    gestures: [],
-
-    // data of the current Hammer.gesture detection session
-    current: null,
-
-    // the previous Hammer.gesture session data
-    // is a full clone of the previous gesture.current object
-    previous: null,
-
-    // when this becomes true, no gestures are fired
-    stopped: false,
-
-
-    /**
-     * start Hammer.gesture detection
-     * @param   {Hammer.Instance}   inst
-     * @param   {Object}            eventData
-     */
-    startDetect: function startDetect(inst, eventData) {
-        // already busy with a Hammer.gesture detection on an element
-        if(this.current) {
-            return;
-        }
-
-        this.stopped = false;
-
-        this.current = {
-            inst        : inst, // reference to HammerInstance we're working for
-            startEvent  : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc
-            lastEvent   : false, // last eventData
-            name        : '' // current gesture we're in/detected, can be 'tap', 'hold' etc
-        };
-
-        this.detect(eventData);
-    },
-
-
-    /**
-     * Hammer.gesture detection
-     * @param   {Object}    eventData
-     * @param   {Object}    eventData
-     */
-    detect: function detect(eventData) {
-        if(!this.current || this.stopped) {
-            return;
-        }
-
-        // extend event data with calculations about scale, distance etc
-        eventData = this.extendEventData(eventData);
-
-        // instance options
-        var inst_options = this.current.inst.options;
-
-        // call Hammer.gesture handlers
-        for(var g=0,len=this.gestures.length; g<len; g++) {
-            var gesture = this.gestures[g];
-
-            // only when the instance options have enabled this gesture
-            if(!this.stopped && inst_options[gesture.name] !== false) {
-                // if a handler returns false, we stop with the detection
-                if(gesture.handler.call(gesture, eventData, this.current.inst) === false) {
-                    this.stopDetect();
-                    break;
-                }
-            }
-        }
-
-        // store as previous event event
-        if(this.current) {
-            this.current.lastEvent = eventData;
-        }
-
-        // endevent, but not the last touch, so dont stop
-        if(eventData.eventType == Hammer.EVENT_END && !eventData.touches.length-1) {
-            this.stopDetect();
-        }
-
-        return eventData;
-    },
-
-
-    /**
-     * clear the Hammer.gesture vars
-     * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected
-     * to stop other Hammer.gestures from being fired
-     */
-    stopDetect: function stopDetect() {
-        // clone current data to the store as the previous gesture
-        // used for the double tap gesture, since this is an other gesture detect session
-        this.previous = Hammer.utils.extend({}, this.current);
-
-        // reset the current
-        this.current = null;
-
-        // stopped!
-        this.stopped = true;
-    },
-
-
-    /**
-     * extend eventData for Hammer.gestures
-     * @param   {Object}   ev
-     * @returns {Object}   ev
-     */
-    extendEventData: function extendEventData(ev) {
-        var startEv = this.current.startEvent;
-
-        // if the touches change, set the new touches over the startEvent touches
-        // this because touchevents don't have all the touches on touchstart, or the
-        // user must place his fingers at the EXACT same time on the screen, which is not realistic
-        // but, sometimes it happens that both fingers are touching at the EXACT same time
-        if(startEv && (ev.touches.length != startEv.touches.length || ev.touches === startEv.touches)) {
-            // extend 1 level deep to get the touchlist with the touch objects
-            startEv.touches = [];
-            for(var i=0,len=ev.touches.length; i<len; i++) {
-                startEv.touches.push(Hammer.utils.extend({}, ev.touches[i]));
-            }
-        }
-
-        var delta_time = ev.timeStamp - startEv.timeStamp,
-            delta_x = ev.center.pageX - startEv.center.pageX,
-            delta_y = ev.center.pageY - startEv.center.pageY,
-            velocity = Hammer.utils.getVelocity(delta_time, delta_x, delta_y);
-
-        Hammer.utils.extend(ev, {
-            deltaTime   : delta_time,
-
-            deltaX      : delta_x,
-            deltaY      : delta_y,
-
-            velocityX   : velocity.x,
-            velocityY   : velocity.y,
-
-            distance    : Hammer.utils.getDistance(startEv.center, ev.center),
-            angle       : Hammer.utils.getAngle(startEv.center, ev.center),
-            direction   : Hammer.utils.getDirection(startEv.center, ev.center),
-
-            scale       : Hammer.utils.getScale(startEv.touches, ev.touches),
-            rotation    : Hammer.utils.getRotation(startEv.touches, ev.touches),
-
-            startEvent  : startEv
-        });
-
-        return ev;
-    },
-
-
-    /**
-     * register new gesture
-     * @param   {Object}    gesture object, see gestures.js for documentation
-     * @returns {Array}     gestures
-     */
-    register: function register(gesture) {
-        // add an enable gesture options if there is no given
-        var options = gesture.defaults || {};
-        if(options[gesture.name] === undefined) {
-            options[gesture.name] = true;
-        }
-
-        // extend Hammer default options with the Hammer.gesture options
-        Hammer.utils.extend(Hammer.defaults, options, true);
-
-        // set its index
-        gesture.index = gesture.index || 1000;
-
-        // add Hammer.gesture to the list
-        this.gestures.push(gesture);
-
-        // sort the list by index
-        this.gestures.sort(function(a, b) {
-            if (a.index < b.index) {
-                return -1;
-            }
-            if (a.index > b.index) {
-                return 1;
-            }
-            return 0;
-        });
-
-        return this.gestures;
-    }
-};
-
-
-Hammer.gestures = Hammer.gestures || {};
-
-/**
- * Custom gestures
- * ==============================
- *
- * Gesture object
- * --------------------
- * The object structure of a gesture:
- *
- * { name: 'mygesture',
- *   index: 1337,
- *   defaults: {
- *     mygesture_option: true
- *   }
- *   handler: function(type, ev, inst) {
- *     // trigger gesture event
- *     inst.trigger(this.name, ev);
- *   }
- * }
-
- * @param   {String}    name
- * this should be the name of the gesture, lowercase
- * it is also being used to disable/enable the gesture per instance config.
- *
- * @param   {Number}    [index=1000]
- * the index of the gesture, where it is going to be in the stack of gestures detection
- * like when you build an gesture that depends on the drag gesture, it is a good
- * idea to place it after the index of the drag gesture.
- *
- * @param   {Object}    [defaults={}]
- * the default settings of the gesture. these are added to the instance settings,
- * and can be overruled per instance. you can also add the name of the gesture,
- * but this is also added by default (and set to true).
- *
- * @param   {Function}  handler
- * this handles the gesture detection of your custom gesture and receives the
- * following arguments:
- *
- *      @param  {Object}    eventData
- *      event data containing the following properties:
- *          timeStamp   {Number}        time the event occurred
- *          target      {HTMLElement}   target element
- *          touches     {Array}         touches (fingers, pointers, mouse) on the screen
- *          pointerType {String}        kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH
- *          center      {Object}        center position of the touches. contains pageX and pageY
- *          deltaTime   {Number}        the total time of the touches in the screen
- *          deltaX      {Number}        the delta on x axis we haved moved
- *          deltaY      {Number}        the delta on y axis we haved moved
- *          velocityX   {Number}        the velocity on the x
- *          velocityY   {Number}        the velocity on y
- *          angle       {Number}        the angle we are moving
- *          direction   {String}        the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT
- *          distance    {Number}        the distance we haved moved
- *          scale       {Number}        scaling of the touches, needs 2 touches
- *          rotation    {Number}        rotation of the touches, needs 2 touches *
- *          eventType   {String}        matches Hammer.EVENT_START|MOVE|END
- *          srcEvent    {Object}        the source event, like TouchStart or MouseDown *
- *          startEvent  {Object}        contains the same properties as above,
- *                                      but from the first touch. this is used to calculate
- *                                      distances, deltaTime, scaling etc
- *
- *      @param  {Hammer.Instance}    inst
- *      the instance we are doing the detection for. you can get the options from
- *      the inst.options object and trigger the gesture event by calling inst.trigger
- *
- *
- * Handle gestures
- * --------------------
- * inside the handler you can get/set Hammer.detection.current. This is the current
- * detection session. It has the following properties
- *      @param  {String}    name
- *      contains the name of the gesture we have detected. it has not a real function,
- *      only to check in other gestures if something is detected.
- *      like in the drag gesture we set it to 'drag' and in the swipe gesture we can
- *      check if the current gesture is 'drag' by accessing Hammer.detection.current.name
- *
- *      @readonly
- *      @param  {Hammer.Instance}    inst
- *      the instance we do the detection for
- *
- *      @readonly
- *      @param  {Object}    startEvent
- *      contains the properties of the first gesture detection in this session.
- *      Used for calculations about timing, distance, etc.
- *
- *      @readonly
- *      @param  {Object}    lastEvent
- *      contains all the properties of the last gesture detect in this session.
- *
- * after the gesture detection session has been completed (user has released the screen)
- * the Hammer.detection.current object is copied into Hammer.detection.previous,
- * this is usefull for gestures like doubletap, where you need to know if the
- * previous gesture was a tap
- *
- * options that have been set by the instance can be received by calling inst.options
- *
- * You can trigger a gesture event by calling inst.trigger("mygesture", event).
- * The first param is the name of your gesture, the second the event argument
- *
- *
- * Register gestures
- * --------------------
- * When an gesture is added to the Hammer.gestures object, it is auto registered
- * at the setup of the first Hammer instance. You can also call Hammer.detection.register
- * manually and pass your gesture object as a param
- *
- */
-
-/**
- * Hold
- * Touch stays at the same place for x time
- * @events  hold
- */
-Hammer.gestures.Hold = {
-    name: 'hold',
-    index: 10,
-    defaults: {
-        hold_timeout   : 500,
-        hold_threshold : 1
-    },
-    timer: null,
-    handler: function holdGesture(ev, inst) {
-        switch(ev.eventType) {
-            case Hammer.EVENT_START:
-                // clear any running timers
-                clearTimeout(this.timer);
-
-                // set the gesture so we can check in the timeout if it still is
-                Hammer.detection.current.name = this.name;
-
-                // set timer and if after the timeout it still is hold,
-                // we trigger the hold event
-                this.timer = setTimeout(function() {
-                    if(Hammer.detection.current.name == 'hold') {
-                        inst.trigger('hold', ev);
-                    }
-                }, inst.options.hold_timeout);
-                break;
-
-            // when you move or end we clear the timer
-            case Hammer.EVENT_MOVE:
-                if(ev.distance > inst.options.hold_threshold) {
-                    clearTimeout(this.timer);
-                }
-                break;
-
-            case Hammer.EVENT_END:
-                clearTimeout(this.timer);
-                break;
-        }
-    }
-};
-
-
-/**
- * Tap/DoubleTap
- * Quick touch at a place or double at the same place
- * @events  tap, doubletap
- */
-Hammer.gestures.Tap = {
-    name: 'tap',
-    index: 100,
-    defaults: {
-        tap_max_touchtime      : 250,
-        tap_max_distance       : 10,
-               tap_always                      : true,
-        doubletap_distance     : 20,
-        doubletap_interval     : 300
-    },
-    handler: function tapGesture(ev, inst) {
-        if(ev.eventType == Hammer.EVENT_END) {
-            // previous gesture, for the double tap since these are two different gesture detections
-            var prev = Hammer.detection.previous,
-                               did_doubletap = false;
-
-            // when the touchtime is higher then the max touch time
-            // or when the moving distance is too much
-            if(ev.deltaTime > inst.options.tap_max_touchtime ||
-                ev.distance > inst.options.tap_max_distance) {
-                return;
-            }
-
-            // check if double tap
-            if(prev && prev.name == 'tap' &&
-                (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval &&
-                ev.distance < inst.options.doubletap_distance) {
-                               inst.trigger('doubletap', ev);
-                               did_doubletap = true;
-            }
-
-                       // do a single tap
-                       if(!did_doubletap || inst.options.tap_always) {
-                               Hammer.detection.current.name = 'tap';
-                               inst.trigger(Hammer.detection.current.name, ev);
-                       }
-        }
-    }
-};
-
-
-/**
- * Swipe
- * triggers swipe events when the end velocity is above the threshold
- * @events  swipe, swipeleft, swiperight, swipeup, swipedown
- */
-Hammer.gestures.Swipe = {
-    name: 'swipe',
-    index: 40,
-    defaults: {
-        // set 0 for unlimited, but this can conflict with transform
-        swipe_max_touches  : 1,
-        swipe_velocity     : 0.7
-    },
-    handler: function swipeGesture(ev, inst) {
-        if(ev.eventType == Hammer.EVENT_END) {
-            // max touches
-            if(inst.options.swipe_max_touches > 0 &&
-                ev.touches.length > inst.options.swipe_max_touches) {
-                return;
-            }
-
-            // when the distance we moved is too small we skip this gesture
-            // or we can be already in dragging
-            if(ev.velocityX > inst.options.swipe_velocity ||
-                ev.velocityY > inst.options.swipe_velocity) {
-                // trigger swipe events
-                inst.trigger(this.name, ev);
-                inst.trigger(this.name + ev.direction, ev);
-            }
-        }
-    }
-};
-
-
-/**
- * Drag
- * Move with x fingers (default 1) around on the page. Blocking the scrolling when
- * moving left and right is a good practice. When all the drag events are blocking
- * you disable scrolling on that area.
- * @events  drag, drapleft, dragright, dragup, dragdown
- */
-Hammer.gestures.Drag = {
-    name: 'drag',
-    index: 50,
-    defaults: {
-        drag_min_distance : 10,
-        // set 0 for unlimited, but this can conflict with transform
-        drag_max_touches  : 1,
-        // prevent default browser behavior when dragging occurs
-        // be careful with it, it makes the element a blocking element
-        // when you are using the drag gesture, it is a good practice to set this true
-        drag_block_horizontal   : false,
-        drag_block_vertical     : false,
-        // drag_lock_to_axis keeps the drag gesture on the axis that it started on,
-        // It disallows vertical directions if the initial direction was horizontal, and vice versa.
-        drag_lock_to_axis       : false,
-        // drag lock only kicks in when distance > drag_lock_min_distance
-        // This way, locking occurs only when the distance has become large enough to reliably determine the direction
-        drag_lock_min_distance : 25
-    },
-    triggered: false,
-    handler: function dragGesture(ev, inst) {
-        // current gesture isnt drag, but dragged is true
-        // this means an other gesture is busy. now call dragend
-        if(Hammer.detection.current.name != this.name && this.triggered) {
-            inst.trigger(this.name +'end', ev);
-            this.triggered = false;
-            return;
-        }
-
-        // max touches
-        if(inst.options.drag_max_touches > 0 &&
-            ev.touches.length > inst.options.drag_max_touches) {
-            return;
-        }
-
-        switch(ev.eventType) {
-            case Hammer.EVENT_START:
-                this.triggered = false;
-                break;
-
-            case Hammer.EVENT_MOVE:
-                // when the distance we moved is too small we skip this gesture
-                // or we can be already in dragging
-                if(ev.distance < inst.options.drag_min_distance &&
-                    Hammer.detection.current.name != this.name) {
-                    return;
-                }
-
-                // we are dragging!
-                Hammer.detection.current.name = this.name;
-
-                // lock drag to axis?
-                if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) {
-                    ev.drag_locked_to_axis = true;
-                }
-                var last_direction = Hammer.detection.current.lastEvent.direction;
-                if(ev.drag_locked_to_axis && last_direction !== ev.direction) {
-                    // keep direction on the axis that the drag gesture started on
-                    if(Hammer.utils.isVertical(last_direction)) {
-                        ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;
-                    }
-                    else {
-                        ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;
-                    }
-                }
-
-                // first time, trigger dragstart event
-                if(!this.triggered) {
-                    inst.trigger(this.name +'start', ev);
-                    this.triggered = true;
-                }
-
-                // trigger normal event
-                inst.trigger(this.name, ev);
-
-                // direction event, like dragdown
-                inst.trigger(this.name + ev.direction, ev);
-
-                // block the browser events
-                if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) ||
-                    (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) {
-                    ev.preventDefault();
-                }
-                break;
-
-            case Hammer.EVENT_END:
-                // trigger dragend
-                if(this.triggered) {
-                    inst.trigger(this.name +'end', ev);
-                }
-
-                this.triggered = false;
-                break;
-        }
-    }
-};
-
-
-/**
- * Transform
- * User want to scale or rotate with 2 fingers
- * @events  transform, pinch, pinchin, pinchout, rotate
- */
-Hammer.gestures.Transform = {
-    name: 'transform',
-    index: 45,
-    defaults: {
-        // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1
-        transform_min_scale     : 0.01,
-        // rotation in degrees
-        transform_min_rotation  : 1,
-        // prevent default browser behavior when two touches are on the screen
-        // but it makes the element a blocking element
-        // when you are using the transform gesture, it is a good practice to set this true
-        transform_always_block  : false
-    },
-    triggered: false,
-    handler: function transformGesture(ev, inst) {
-        // current gesture isnt drag, but dragged is true
-        // this means an other gesture is busy. now call dragend
-        if(Hammer.detection.current.name != this.name && this.triggered) {
-            inst.trigger(this.name +'end', ev);
-            this.triggered = false;
-            return;
-        }
-
-        // atleast multitouch
-        if(ev.touches.length < 2) {
-            return;
-        }
-
-        // prevent default when two fingers are on the screen
-        if(inst.options.transform_always_block) {
-            ev.preventDefault();
-        }
-
-        switch(ev.eventType) {
-            case Hammer.EVENT_START:
-                this.triggered = false;
-                break;
-
-            case Hammer.EVENT_MOVE:
-                var scale_threshold = Math.abs(1-ev.scale);
-                var rotation_threshold = Math.abs(ev.rotation);
-
-                // when the distance we moved is too small we skip this gesture
-                // or we can be already in dragging
-                if(scale_threshold < inst.options.transform_min_scale &&
-                    rotation_threshold < inst.options.transform_min_rotation) {
-                    return;
-                }
-
-                // we are transforming!
-                Hammer.detection.current.name = this.name;
-
-                // first time, trigger dragstart event
-                if(!this.triggered) {
-                    inst.trigger(this.name +'start', ev);
-                    this.triggered = true;
-                }
-
-                inst.trigger(this.name, ev); // basic transform event
-
-                // trigger rotate event
-                if(rotation_threshold > inst.options.transform_min_rotation) {
-                    inst.trigger('rotate', ev);
-                }
-
-                // trigger pinch event
-                if(scale_threshold > inst.options.transform_min_scale) {
-                    inst.trigger('pinch', ev);
-                    inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev);
-                }
-                break;
-
-            case Hammer.EVENT_END:
-                // trigger dragend
-                if(this.triggered) {
-                    inst.trigger(this.name +'end', ev);
-                }
-
-                this.triggered = false;
-                break;
-        }
-    }
-};
-
-
-/**
- * Touch
- * Called as first, tells the user has touched the screen
- * @events  touch
- */
-Hammer.gestures.Touch = {
-    name: 'touch',
-    index: -Infinity,
-    defaults: {
-        // call preventDefault at touchstart, and makes the element blocking by
-        // disabling the scrolling of the page, but it improves gestures like
-        // transforming and dragging.
-        // be careful with using this, it can be very annoying for users to be stuck
-        // on the page
-        prevent_default: false,
-
-        // disable mouse events, so only touch (or pen!) input triggers events
-        prevent_mouseevents: false
-    },
-    handler: function touchGesture(ev, inst) {
-        if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) {
-            ev.stopDetect();
-            return;
-        }
-
-        if(inst.options.prevent_default) {
-            ev.preventDefault();
-        }
-
-        if(ev.eventType ==  Hammer.EVENT_START) {
-            inst.trigger(this.name, ev);
-        }
-    }
-};
-
-
-/**
- * Release
- * Called as last, tells the user has released the screen
- * @events  release
- */
-Hammer.gestures.Release = {
-    name: 'release',
-    index: Infinity,
-    handler: function releaseGesture(ev, inst) {
-        if(ev.eventType ==  Hammer.EVENT_END) {
-            inst.trigger(this.name, ev);
-        }
-    }
-};
-
-// node export
-if(typeof module === 'object' && typeof module.exports === 'object'){
-    module.exports = Hammer;
-}
-// just window export
-else {
-    window.Hammer = Hammer;
-
-    // requireJS module definition
-    if(typeof window.define === 'function' && window.define.amd) {
-        window.define('hammer', [], function() {
-            return Hammer;
-        });
-    }
-}
-})(this);
-},{}],4:[function(require,module,exports){
-var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};//! moment.js
-//! version : 2.7.0
-//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
-//! license : MIT
-//! momentjs.com
-
-(function (undefined) {
-
-    /************************************
-        Constants
-    ************************************/
-
-    var moment,
-        VERSION = "2.7.0",
-        // the global-scope this is NOT the global object in Node.js
-        globalScope = typeof global !== 'undefined' ? global : this,
-        oldGlobalMoment,
-        round = Math.round,
-        i,
-
-        YEAR = 0,
-        MONTH = 1,
-        DATE = 2,
-        HOUR = 3,
-        MINUTE = 4,
-        SECOND = 5,
-        MILLISECOND = 6,
-
-        // internal storage for language config files
-        languages = {},
-
-        // moment internal properties
-        momentProperties = {
-            _isAMomentObject: null,
-            _i : null,
-            _f : null,
-            _l : null,
-            _strict : null,
-            _tzm : null,
-            _isUTC : null,
-            _offset : null,  // optional. Combine with _isUTC
-            _pf : null,
-            _lang : null  // optional
-        },
-
-        // check for nodeJS
-        hasModule = (typeof module !== 'undefined' && module.exports),
-
-        // ASP.NET json date format regex
-        aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
-        aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
-
-        // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
-        // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
-        isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
-
-        // format tokens
-        formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,
-        localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
-
-        // parsing token regexes
-        parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
-        parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
-        parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
-        parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
-        parseTokenDigits = /\d+/, // nonzero number of digits
-        parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
-        parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
-        parseTokenT = /T/i, // T (ISO separator)
-        parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
-        parseTokenOrdinal = /\d{1,2}/,
-
-        //strict parsing regexes
-        parseTokenOneDigit = /\d/, // 0 - 9
-        parseTokenTwoDigits = /\d\d/, // 00 - 99
-        parseTokenThreeDigits = /\d{3}/, // 000 - 999
-        parseTokenFourDigits = /\d{4}/, // 0000 - 9999
-        parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999
-        parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf
-
-        // iso 8601 regex
-        // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
-        isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
-
-        isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
-
-        isoDates = [
-            ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
-            ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
-            ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
-            ['GGGG-[W]WW', /\d{4}-W\d{2}/],
-            ['YYYY-DDD', /\d{4}-\d{3}/]
-        ],
-
-        // iso time formats and regexes
-        isoTimes = [
-            ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/],
-            ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
-            ['HH:mm', /(T| )\d\d:\d\d/],
-            ['HH', /(T| )\d\d/]
-        ],
-
-        // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
-        parseTimezoneChunker = /([\+\-]|\d\d)/gi,
-
-        // getter and setter names
-        proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
-        unitMillisecondFactors = {
-            'Milliseconds' : 1,
-            'Seconds' : 1e3,
-            'Minutes' : 6e4,
-            'Hours' : 36e5,
-            'Days' : 864e5,
-            'Months' : 2592e6,
-            'Years' : 31536e6
-        },
-
-        unitAliases = {
-            ms : 'millisecond',
-            s : 'second',
-            m : 'minute',
-            h : 'hour',
-            d : 'day',
-            D : 'date',
-            w : 'week',
-            W : 'isoWeek',
-            M : 'month',
-            Q : 'quarter',
-            y : 'year',
-            DDD : 'dayOfYear',
-            e : 'weekday',
-            E : 'isoWeekday',
-            gg: 'weekYear',
-            GG: 'isoWeekYear'
-        },
-
-        camelFunctions = {
-            dayofyear : 'dayOfYear',
-            isoweekday : 'isoWeekday',
-            isoweek : 'isoWeek',
-            weekyear : 'weekYear',
-            isoweekyear : 'isoWeekYear'
-        },
-
-        // format function strings
-        formatFunctions = {},
-
-        // default relative time thresholds
-        relativeTimeThresholds = {
-          s: 45,   //seconds to minutes
-          m: 45,   //minutes to hours
-          h: 22,   //hours to days
-          dd: 25,  //days to month (month == 1)
-          dm: 45,  //days to months (months > 1)
-          dy: 345  //days to year
-        },
-
-        // tokens to ordinalize and pad
-        ordinalizeTokens = 'DDD w W M D d'.split(' '),
-        paddedTokens = 'M D H h m s w W'.split(' '),
-
-        formatTokenFunctions = {
-            M    : function () {
-                return this.month() + 1;
-            },
-            MMM  : function (format) {
-                return this.lang().monthsShort(this, format);
-            },
-            MMMM : function (format) {
-                return this.lang().months(this, format);
-            },
-            D    : function () {
-                return this.date();
-            },
-            DDD  : function () {
-                return this.dayOfYear();
-            },
-            d    : function () {
-                return this.day();
-            },
-            dd   : function (format) {
-                return this.lang().weekdaysMin(this, format);
-            },
-            ddd  : function (format) {
-                return this.lang().weekdaysShort(this, format);
-            },
-            dddd : function (format) {
-                return this.lang().weekdays(this, format);
-            },
-            w    : function () {
-                return this.week();
-            },
-            W    : function () {
-                return this.isoWeek();
-            },
-            YY   : function () {
-                return leftZeroFill(this.year() % 100, 2);
-            },
-            YYYY : function () {
-                return leftZeroFill(this.year(), 4);
-            },
-            YYYYY : function () {
-                return leftZeroFill(this.year(), 5);
-            },
-            YYYYYY : function () {
-                var y = this.year(), sign = y >= 0 ? '+' : '-';
-                return sign + leftZeroFill(Math.abs(y), 6);
-            },
-            gg   : function () {
-                return leftZeroFill(this.weekYear() % 100, 2);
-            },
-            gggg : function () {
-                return leftZeroFill(this.weekYear(), 4);
-            },
-            ggggg : function () {
-                return leftZeroFill(this.weekYear(), 5);
-            },
-            GG   : function () {
-                return leftZeroFill(this.isoWeekYear() % 100, 2);
-            },
-            GGGG : function () {
-                return leftZeroFill(this.isoWeekYear(), 4);
-            },
-            GGGGG : function () {
-                return leftZeroFill(this.isoWeekYear(), 5);
-            },
-            e : function () {
-                return this.weekday();
-            },
-            E : function () {
-                return this.isoWeekday();
-            },
-            a    : function () {
-                return this.lang().meridiem(this.hours(), this.minutes(), true);
-            },
-            A    : function () {
-                return this.lang().meridiem(this.hours(), this.minutes(), false);
-            },
-            H    : function () {
-                return this.hours();
-            },
-            h    : function () {
-                return this.hours() % 12 || 12;
-            },
-            m    : function () {
-                return this.minutes();
-            },
-            s    : function () {
-                return this.seconds();
-            },
-            S    : function () {
-                return toInt(this.milliseconds() / 100);
-            },
-            SS   : function () {
-                return leftZeroFill(toInt(this.milliseconds() / 10), 2);
-            },
-            SSS  : function () {
-                return leftZeroFill(this.milliseconds(), 3);
-            },
-            SSSS : function () {
-                return leftZeroFill(this.milliseconds(), 3);
-            },
-            Z    : function () {
-                var a = -this.zone(),
-                    b = "+";
-                if (a < 0) {
-                    a = -a;
-                    b = "-";
-                }
-                return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2);
-            },
-            ZZ   : function () {
-                var a = -this.zone(),
-                    b = "+";
-                if (a < 0) {
-                    a = -a;
-                    b = "-";
-                }
-                return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
-            },
-            z : function () {
-                return this.zoneAbbr();
-            },
-            zz : function () {
-                return this.zoneName();
-            },
-            X    : function () {
-                return this.unix();
-            },
-            Q : function () {
-                return this.quarter();
-            }
-        },
-
-        lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'];
-
-    // Pick the first defined of two or three arguments. dfl comes from
-    // default.
-    function dfl(a, b, c) {
-        switch (arguments.length) {
-            case 2: return a != null ? a : b;
-            case 3: return a != null ? a : b != null ? b : c;
-            default: throw new Error("Implement me");
-        }
-    }
-
-    function defaultParsingFlags() {
-        // We need to deep clone this object, and es5 standard is not very
-        // helpful.
-        return {
-            empty : false,
-            unusedTokens : [],
-            unusedInput : [],
-            overflow : -2,
-            charsLeftOver : 0,
-            nullInput : false,
-            invalidMonth : null,
-            invalidFormat : false,
-            userInvalidated : false,
-            iso: false
-        };
-    }
-
-    function deprecate(msg, fn) {
-        var firstTime = true;
-        function printMsg() {
-            if (moment.suppressDeprecationWarnings === false &&
-                    typeof console !== 'undefined' && console.warn) {
-                console.warn("Deprecation warning: " + msg);
-            }
-        }
-        return extend(function () {
-            if (firstTime) {
-                printMsg();
-                firstTime = false;
-            }
-            return fn.apply(this, arguments);
-        }, fn);
-    }
-
-    function padToken(func, count) {
-        return function (a) {
-            return leftZeroFill(func.call(this, a), count);
-        };
-    }
-    function ordinalizeToken(func, period) {
-        return function (a) {
-            return this.lang().ordinal(func.call(this, a), period);
-        };
-    }
-
-    while (ordinalizeTokens.length) {
-        i = ordinalizeTokens.pop();
-        formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
-    }
-    while (paddedTokens.length) {
-        i = paddedTokens.pop();
-        formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
-    }
-    formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
-
-
-    /************************************
-        Constructors
-    ************************************/
-
-    function Language() {
-
-    }
-
-    // Moment prototype object
-    function Moment(config) {
-        checkOverflow(config);
-        extend(this, config);
-    }
-
-    // Duration Constructor
-    function Duration(duration) {
-        var normalizedInput = normalizeObjectUnits(duration),
-            years = normalizedInput.year || 0,
-            quarters = normalizedInput.quarter || 0,
-            months = normalizedInput.month || 0,
-            weeks = normalizedInput.week || 0,
-            days = normalizedInput.day || 0,
-            hours = normalizedInput.hour || 0,
-            minutes = normalizedInput.minute || 0,
-            seconds = normalizedInput.second || 0,
-            milliseconds = normalizedInput.millisecond || 0;
-
-        // representation for dateAddRemove
-        this._milliseconds = +milliseconds +
-            seconds * 1e3 + // 1000
-            minutes * 6e4 + // 1000 * 60
-            hours * 36e5; // 1000 * 60 * 60
-        // Because of dateAddRemove treats 24 hours as different from a
-        // day when working around DST, we need to store them separately
-        this._days = +days +
-            weeks * 7;
-        // It is impossible translate months into days without knowing
-        // which months you are are talking about, so we have to store
-        // it separately.
-        this._months = +months +
-            quarters * 3 +
-            years * 12;
-
-        this._data = {};
-
-        this._bubble();
-    }
-
-    /************************************
-        Helpers
-    ************************************/
-
-
-    function extend(a, b) {
-        for (var i in b) {
-            if (b.hasOwnProperty(i)) {
-                a[i] = b[i];
-            }
-        }
-
-        if (b.hasOwnProperty("toString")) {
-            a.toString = b.toString;
-        }
-
-        if (b.hasOwnProperty("valueOf")) {
-            a.valueOf = b.valueOf;
-        }
-
-        return a;
-    }
-
-    function cloneMoment(m) {
-        var result = {}, i;
-        for (i in m) {
-            if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) {
-                result[i] = m[i];
-            }
-        }
-
-        return result;
-    }
-
-    function absRound(number) {
-        if (number < 0) {
-            return Math.ceil(number);
-        } else {
-            return Math.floor(number);
-        }
-    }
-
-    // left zero fill a number
-    // see http://jsperf.com/left-zero-filling for performance comparison
-    function leftZeroFill(number, targetLength, forceSign) {
-        var output = '' + Math.abs(number),
-            sign = number >= 0;
-
-        while (output.length < targetLength) {
-            output = '0' + output;
-        }
-        return (sign ? (forceSign ? '+' : '') : '-') + output;
-    }
-
-    // helper function for _.addTime and _.subtractTime
-    function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) {
-        var milliseconds = duration._milliseconds,
-            days = duration._days,
-            months = duration._months;
-        updateOffset = updateOffset == null ? true : updateOffset;
-
-        if (milliseconds) {
-            mom._d.setTime(+mom._d + milliseconds * isAdding);
-        }
-        if (days) {
-            rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding);
-        }
-        if (months) {
-            rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding);
-        }
-        if (updateOffset) {
-            moment.updateOffset(mom, days || months);
-        }
-    }
-
-    // check if is an array
-    function isArray(input) {
-        return Object.prototype.toString.call(input) === '[object Array]';
-    }
-
-    function isDate(input) {
-        return  Object.prototype.toString.call(input) === '[object Date]' ||
-                input instanceof Date;
-    }
-
-    // compare two arrays, return the number of differences
-    function compareArrays(array1, array2, dontConvert) {
-        var len = Math.min(array1.length, array2.length),
-            lengthDiff = Math.abs(array1.length - array2.length),
-            diffs = 0,
-            i;
-        for (i = 0; i < len; i++) {
-            if ((dontConvert && array1[i] !== array2[i]) ||
-                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
-                diffs++;
-            }
-        }
-        return diffs + lengthDiff;
-    }
-
-    function normalizeUnits(units) {
-        if (units) {
-            var lowered = units.toLowerCase().replace(/(.)s$/, '$1');
-            units = unitAliases[units] || camelFunctions[lowered] || lowered;
-        }
-        return units;
-    }
-
-    function normalizeObjectUnits(inputObject) {
-        var normalizedInput = {},
-            normalizedProp,
-            prop;
-
-        for (prop in inputObject) {
-            if (inputObject.hasOwnProperty(prop)) {
-                normalizedProp = normalizeUnits(prop);
-                if (normalizedProp) {
-                    normalizedInput[normalizedProp] = inputObject[prop];
-                }
-            }
-        }
-
-        return normalizedInput;
-    }
-
-    function makeList(field) {
-        var count, setter;
-
-        if (field.indexOf('week') === 0) {
-            count = 7;
-            setter = 'day';
-        }
-        else if (field.indexOf('month') === 0) {
-            count = 12;
-            setter = 'month';
-        }
-        else {
-            return;
-        }
-
-        moment[field] = function (format, index) {
-            var i, getter,
-                method = moment.fn._lang[field],
-                results = [];
-
-            if (typeof format === 'number') {
-                index = format;
-                format = undefined;
-            }
-
-            getter = function (i) {
-                var m = moment().utc().set(setter, i);
-                return method.call(moment.fn._lang, m, format || '');
-            };
-
-            if (index != null) {
-                return getter(index);
-            }
-            else {
-                for (i = 0; i < count; i++) {
-                    results.push(getter(i));
-                }
-                return results;
-            }
-        };
-    }
-
-    function toInt(argumentForCoercion) {
-        var coercedNumber = +argumentForCoercion,
-            value = 0;
-
-        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
-            if (coercedNumber >= 0) {
-                value = Math.floor(coercedNumber);
-            } else {
-                value = Math.ceil(coercedNumber);
-            }
-        }
-
-        return value;
-    }
-
-    function daysInMonth(year, month) {
-        return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
-    }
-
-    function weeksInYear(year, dow, doy) {
-        return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week;
-    }
-
-    function daysInYear(year) {
-        return isLeapYear(year) ? 366 : 365;
-    }
-
-    function isLeapYear(year) {
-        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
-    }
-
-    function checkOverflow(m) {
-        var overflow;
-        if (m._a && m._pf.overflow === -2) {
-            overflow =
-                m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
-                m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
-                m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR :
-                m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
-                m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
-                m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
-                -1;
-
-            if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
-                overflow = DATE;
-            }
-
-            m._pf.overflow = overflow;
-        }
-    }
-
-    function isValid(m) {
-        if (m._isValid == null) {
-            m._isValid = !isNaN(m._d.getTime()) &&
-                m._pf.overflow < 0 &&
-                !m._pf.empty &&
-                !m._pf.invalidMonth &&
-                !m._pf.nullInput &&
-                !m._pf.invalidFormat &&
-                !m._pf.userInvalidated;
-
-            if (m._strict) {
-                m._isValid = m._isValid &&
-                    m._pf.charsLeftOver === 0 &&
-                    m._pf.unusedTokens.length === 0;
-            }
-        }
-        return m._isValid;
-    }
-
-    function normalizeLanguage(key) {
-        return key ? key.toLowerCase().replace('_', '-') : key;
-    }
-
-    // Return a moment from input, that is local/utc/zone equivalent to model.
-    function makeAs(input, model) {
-        return model._isUTC ? moment(input).zone(model._offset || 0) :
-            moment(input).local();
-    }
-
-    /************************************
-        Languages
-    ************************************/
-
-
-    extend(Language.prototype, {
-
-        set : function (config) {
-            var prop, i;
-            for (i in config) {
-                prop = config[i];
-                if (typeof prop === 'function') {
-                    this[i] = prop;
-                } else {
-                    this['_' + i] = prop;
-                }
-            }
-        },
-
-        _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
-        months : function (m) {
-            return this._months[m.month()];
-        },
-
-        _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
-        monthsShort : function (m) {
-            return this._monthsShort[m.month()];
-        },
-
-        monthsParse : function (monthName) {
-            var i, mom, regex;
-
-            if (!this._monthsParse) {
-                this._monthsParse = [];
-            }
-
-            for (i = 0; i < 12; i++) {
-                // make the regex if we don't have it already
-                if (!this._monthsParse[i]) {
-                    mom = moment.utc([2000, i]);
-                    regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
-                    this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
-                }
-                // test the regex
-                if (this._monthsParse[i].test(monthName)) {
-                    return i;
-                }
-            }
-        },
-
-        _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
-        weekdays : function (m) {
-            return this._weekdays[m.day()];
-        },
-
-        _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
-        weekdaysShort : function (m) {
-            return this._weekdaysShort[m.day()];
-        },
-
-        _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
-        weekdaysMin : function (m) {
-            return this._weekdaysMin[m.day()];
-        },
-
-        weekdaysParse : function (weekdayName) {
-            var i, mom, regex;
-
-            if (!this._weekdaysParse) {
-                this._weekdaysParse = [];
-            }
-
-            for (i = 0; i < 7; i++) {
-                // make the regex if we don't have it already
-                if (!this._weekdaysParse[i]) {
-                    mom = moment([2000, 1]).day(i);
-                    regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
-                    this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
-                }
-                // test the regex
-                if (this._weekdaysParse[i].test(weekdayName)) {
-                    return i;
-                }
-            }
-        },
-
-        _longDateFormat : {
-            LT : "h:mm A",
-            L : "MM/DD/YYYY",
-            LL : "MMMM D YYYY",
-            LLL : "MMMM D YYYY LT",
-            LLLL : "dddd, MMMM D YYYY LT"
-        },
-        longDateFormat : function (key) {
-            var output = this._longDateFormat[key];
-            if (!output && this._longDateFormat[key.toUpperCase()]) {
-                output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
-                    return val.slice(1);
-                });
-                this._longDateFormat[key] = output;
-            }
-            return output;
-        },
-
-        isPM : function (input) {
-            // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
-            // Using charAt should be more compatible.
-            return ((input + '').toLowerCase().charAt(0) === 'p');
-        },
-
-        _meridiemParse : /[ap]\.?m?\.?/i,
-        meridiem : function (hours, minutes, isLower) {
-            if (hours > 11) {
-                return isLower ? 'pm' : 'PM';
-            } else {
-                return isLower ? 'am' : 'AM';
-            }
-        },
-
-        _calendar : {
-            sameDay : '[Today at] LT',
-            nextDay : '[Tomorrow at] LT',
-            nextWeek : 'dddd [at] LT',
-            lastDay : '[Yesterday at] LT',
-            lastWeek : '[Last] dddd [at] LT',
-            sameElse : 'L'
-        },
-        calendar : function (key, mom) {
-            var output = this._calendar[key];
-            return typeof output === 'function' ? output.apply(mom) : output;
-        },
-
-        _relativeTime : {
-            future : "in %s",
-            past : "%s ago",
-            s : "a few seconds",
-            m : "a minute",
-            mm : "%d minutes",
-            h : "an hour",
-            hh : "%d hours",
-            d : "a day",
-            dd : "%d days",
-            M : "a month",
-            MM : "%d months",
-            y : "a year",
-            yy : "%d years"
-        },
-        relativeTime : function (number, withoutSuffix, string, isFuture) {
-            var output = this._relativeTime[string];
-            return (typeof output === 'function') ?
-                output(number, withoutSuffix, string, isFuture) :
-                output.replace(/%d/i, number);
-        },
-        pastFuture : function (diff, output) {
-            var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
-            return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
-        },
-
-        ordinal : function (number) {
-            return this._ordinal.replace("%d", number);
-        },
-        _ordinal : "%d",
-
-        preparse : function (string) {
-            return string;
-        },
-
-        postformat : function (string) {
-            return string;
-        },
-
-        week : function (mom) {
-            return weekOfYear(mom, this._week.dow, this._week.doy).week;
-        },
-
-        _week : {
-            dow : 0, // Sunday is the first day of the week.
-            doy : 6  // The week that contains Jan 1st is the first week of the year.
-        },
-
-        _invalidDate: 'Invalid date',
-        invalidDate: function () {
-            return this._invalidDate;
-        }
-    });
-
-    // Loads a language definition into the `languages` cache.  The function
-    // takes a key and optionally values.  If not in the browser and no values
-    // are provided, it will load the language file module.  As a convenience,
-    // this function also returns the language values.
-    function loadLang(key, values) {
-        values.abbr = key;
-        if (!languages[key]) {
-            languages[key] = new Language();
-        }
-        languages[key].set(values);
-        return languages[key];
-    }
-
-    // Remove a language from the `languages` cache. Mostly useful in tests.
-    function unloadLang(key) {
-        delete languages[key];
-    }
-
-    // Determines which language definition to use and returns it.
-    //
-    // With no parameters, it will return the global language.  If you
-    // pass in a language key, such as 'en', it will return the
-    // definition for 'en', so long as 'en' has already been loaded using
-    // moment.lang.
-    function getLangDefinition(key) {
-        var i = 0, j, lang, next, split,
-            get = function (k) {
-                if (!languages[k] && hasModule) {
-                    try {
-                        require('./lang/' + k);
-                    } catch (e) { }
-                }
-                return languages[k];
-            };
-
-        if (!key) {
-            return moment.fn._lang;
-        }
-
-        if (!isArray(key)) {
-            //short-circuit everything else
-            lang = get(key);
-            if (lang) {
-                return lang;
-            }
-            key = [key];
-        }
-
-        //pick the language from the array
-        //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
-        //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
-        while (i < key.length) {
-            split = normalizeLanguage(key[i]).split('-');
-            j = split.length;
-            next = normalizeLanguage(key[i + 1]);
-            next = next ? next.split('-') : null;
-            while (j > 0) {
-                lang = get(split.slice(0, j).join('-'));
-                if (lang) {
-                    return lang;
-                }
-                if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
-                    //the next array item is better than a shallower substring of this one
-                    break;
-                }
-                j--;
-            }
-            i++;
-        }
-        return moment.fn._lang;
-    }
-
-    /************************************
-        Formatting
-    ************************************/
-
-
-    function removeFormattingTokens(input) {
-        if (input.match(/\[[\s\S]/)) {
-            return input.replace(/^\[|\]$/g, "");
-        }
-        return input.replace(/\\/g, "");
-    }
-
-    function makeFormatFunction(format) {
-        var array = format.match(formattingTokens), i, length;
-
-        for (i = 0, length = array.length; i < length; i++) {
-            if (formatTokenFunctions[array[i]]) {
-                array[i] = formatTokenFunctions[array[i]];
-            } else {
-                array[i] = removeFormattingTokens(array[i]);
-            }
-        }
-
-        return function (mom) {
-            var output = "";
-            for (i = 0; i < length; i++) {
-                output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
-            }
-            return output;
-        };
-    }
-
-    // format date using native date object
-    function formatMoment(m, format) {
-
-        if (!m.isValid()) {
-            return m.lang().invalidDate();
-        }
-
-        format = expandFormat(format, m.lang());
-
-        if (!formatFunctions[format]) {
-            formatFunctions[format] = makeFormatFunction(format);
-        }
-
-        return formatFunctions[format](m);
-    }
-
-    function expandFormat(format, lang) {
-        var i = 5;
-
-        function replaceLongDateFormatTokens(input) {
-            return lang.longDateFormat(input) || input;
-        }
-
-        localFormattingTokens.lastIndex = 0;
-        while (i >= 0 && localFormattingTokens.test(format)) {
-            format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
-            localFormattingTokens.lastIndex = 0;
-            i -= 1;
-        }
-
-        return format;
-    }
-
-
-    /************************************
-        Parsing
-    ************************************/
-
-
-    // get the regex to find the next token
-    function getParseRegexForToken(token, config) {
-        var a, strict = config._strict;
-        switch (token) {
-        case 'Q':
-            return parseTokenOneDigit;
-        case 'DDDD':
-            return parseTokenThreeDigits;
-        case 'YYYY':
-        case 'GGGG':
-        case 'gggg':
-            return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
-        case 'Y':
-        case 'G':
-        case 'g':
-            return parseTokenSignedNumber;
-        case 'YYYYYY':
-        case 'YYYYY':
-        case 'GGGGG':
-        case 'ggggg':
-            return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
-        case 'S':
-            if (strict) { return parseTokenOneDigit; }
-            /* falls through */
-        case 'SS':
-            if (strict) { return parseTokenTwoDigits; }
-            /* falls through */
-        case 'SSS':
-            if (strict) { return parseTokenThreeDigits; }
-            /* falls through */
-        case 'DDD':
-            return parseTokenOneToThreeDigits;
-        case 'MMM':
-        case 'MMMM':
-        case 'dd':
-        case 'ddd':
-        case 'dddd':
-            return parseTokenWord;
-        case 'a':
-        case 'A':
-            return getLangDefinition(config._l)._meridiemParse;
-        case 'X':
-            return parseTokenTimestampMs;
-        case 'Z':
-        case 'ZZ':
-            return parseTokenTimezone;
-        case 'T':
-            return parseTokenT;
-        case 'SSSS':
-            return parseTokenDigits;
-        case 'MM':
-        case 'DD':
-        case 'YY':
-        case 'GG':
-        case 'gg':
-        case 'HH':
-        case 'hh':
-        case 'mm':
-        case 'ss':
-        case 'ww':
-        case 'WW':
-            return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
-        case 'M':
-        case 'D':
-        case 'd':
-        case 'H':
-        case 'h':
-        case 'm':
-        case 's':
-        case 'w':
-        case 'W':
-        case 'e':
-        case 'E':
-            return parseTokenOneOrTwoDigits;
-        case 'Do':
-            return parseTokenOrdinal;
-        default :
-            a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i"));
-            return a;
-        }
-    }
-
-    function timezoneMinutesFromString(string) {
-        string = string || "";
-        var possibleTzMatches = (string.match(parseTokenTimezone) || []),
-            tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
-            parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
-            minutes = +(parts[1] * 60) + toInt(parts[2]);
-
-        return parts[0] === '+' ? -minutes : minutes;
-    }
-
-    // function to convert string input to date
-    function addTimeToArrayFromToken(token, input, config) {
-        var a, datePartArray = config._a;
-
-        switch (token) {
-        // QUARTER
-        case 'Q':
-            if (input != null) {
-                datePartArray[MONTH] = (toInt(input) - 1) * 3;
-            }
-            break;
-        // MONTH
-        case 'M' : // fall through to MM
-        case 'MM' :
-            if (input != null) {
-                datePartArray[MONTH] = toInt(input) - 1;
-            }
-            break;
-        case 'MMM' : // fall through to MMMM
-        case 'MMMM' :
-            a = getLangDefinition(config._l).monthsParse(input);
-            // if we didn't find a month name, mark the date as invalid.
-            if (a != null) {
-                datePartArray[MONTH] = a;
-            } else {
-                config._pf.invalidMonth = input;
-            }
-            break;
-        // DAY OF MONTH
-        case 'D' : // fall through to DD
-        case 'DD' :
-            if (input != null) {
-                datePartArray[DATE] = toInt(input);
-            }
-            break;
-        case 'Do' :
-            if (input != null) {
-                datePartArray[DATE] = toInt(parseInt(input, 10));
-            }
-            break;
-        // DAY OF YEAR
-        case 'DDD' : // fall through to DDDD
-        case 'DDDD' :
-            if (input != null) {
-                config._dayOfYear = toInt(input);
-            }
-
-            break;
-        // YEAR
-        case 'YY' :
-            datePartArray[YEAR] = moment.parseTwoDigitYear(input);
-            break;
-        case 'YYYY' :
-        case 'YYYYY' :
-        case 'YYYYYY' :
-            datePartArray[YEAR] = toInt(input);
-            break;
-        // AM / PM
-        case 'a' : // fall through to A
-        case 'A' :
-            config._isPm = getLangDefinition(config._l).isPM(input);
-            break;
-        // 24 HOUR
-        case 'H' : // fall through to hh
-        case 'HH' : // fall through to hh
-        case 'h' : // fall through to hh
-        case 'hh' :
-            datePartArray[HOUR] = toInt(input);
-            break;
-        // MINUTE
-        case 'm' : // fall through to mm
-        case 'mm' :
-            datePartArray[MINUTE] = toInt(input);
-            break;
-        // SECOND
-        case 's' : // fall through to ss
-        case 'ss' :
-            datePartArray[SECOND] = toInt(input);
-            break;
-        // MILLISECOND
-        case 'S' :
-        case 'SS' :
-        case 'SSS' :
-        case 'SSSS' :
-            datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
-            break;
-        // UNIX TIMESTAMP WITH MS
-        case 'X':
-            config._d = new Date(parseFloat(input) * 1000);
-            break;
-        // TIMEZONE
-        case 'Z' : // fall through to ZZ
-        case 'ZZ' :
-            config._useUTC = true;
-            config._tzm = timezoneMinutesFromString(input);
-            break;
-        // WEEKDAY - human
-        case 'dd':
-        case 'ddd':
-        case 'dddd':
-            a = getLangDefinition(config._l).weekdaysParse(input);
-            // if we didn't get a weekday name, mark the date as invalid
-            if (a != null) {
-                config._w = config._w || {};
-                config._w['d'] = a;
-            } else {
-                config._pf.invalidWeekday = input;
-            }
-            break;
-        // WEEK, WEEK DAY - numeric
-        case 'w':
-        case 'ww':
-        case 'W':
-        case 'WW':
-        case 'd':
-        case 'e':
-        case 'E':
-            token = token.substr(0, 1);
-            /* falls through */
-        case 'gggg':
-        case 'GGGG':
-        case 'GGGGG':
-            token = token.substr(0, 2);
-            if (input) {
-                config._w = config._w || {};
-                config._w[token] = toInt(input);
-            }
-            break;
-        case 'gg':
-        case 'GG':
-            config._w = config._w || {};
-            config._w[token] = moment.parseTwoDigitYear(input);
-        }
-    }
-
-    function dayOfYearFromWeekInfo(config) {
-        var w, weekYear, week, weekday, dow, doy, temp, lang;
-
-        w = config._w;
-        if (w.GG != null || w.W != null || w.E != null) {
-            dow = 1;
-            doy = 4;
-
-            // TODO: We need to take the current isoWeekYear, but that depends on
-            // how we interpret now (local, utc, fixed offset). So create
-            // a now version of current config (take local/utc/offset flags, and
-            // create now).
-            weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year);
-            week = dfl(w.W, 1);
-            weekday = dfl(w.E, 1);
-        } else {
-            lang = getLangDefinition(config._l);
-            dow = lang._week.dow;
-            doy = lang._week.doy;
-
-            weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year);
-            week = dfl(w.w, 1);
-
-            if (w.d != null) {
-                // weekday -- low day numbers are considered next week
-                weekday = w.d;
-                if (weekday < dow) {
-                    ++week;
-                }
-            } else if (w.e != null) {
-                // local weekday -- counting starts from begining of week
-                weekday = w.e + dow;
-            } else {
-                // default to begining of week
-                weekday = dow;
-            }
-        }
-        temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);
-
-        config._a[YEAR] = temp.year;
-        config._dayOfYear = temp.dayOfYear;
-    }
-
-    // convert an array to a date.
-    // the array should mirror the parameters below
-    // note: all values past the year are optional and will default to the lowest possible value.
-    // [year, month, day , hour, minute, second, millisecond]
-    function dateFromConfig(config) {
-        var i, date, input = [], currentDate, yearToUse;
-
-        if (config._d) {
-            return;
-        }
-
-        currentDate = currentDateArray(config);
-
-        //compute day of the year from weeks and weekdays
-        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
-            dayOfYearFromWeekInfo(config);
-        }
-
-        //if the day of the year is set, figure out what it is
-        if (config._dayOfYear) {
-            yearToUse = dfl(config._a[YEAR], currentDate[YEAR]);
-
-            if (config._dayOfYear > daysInYear(yearToUse)) {
-                config._pf._overflowDayOfYear = true;
-            }
-
-            date = makeUTCDate(yearToUse, 0, config._dayOfYear);
-            config._a[MONTH] = date.getUTCMonth();
-            config._a[DATE] = date.getUTCDate();
-        }
-
-        // Default to current date.
-        // * if no year, month, day of month are given, default to today
-        // * if day of month is given, default month and year
-        // * if month is given, default only year
-        // * if year is given, don't default anything
-        for (i = 0; i < 3 && config._a[i] == null; ++i) {
-            config._a[i] = input[i] = currentDate[i];
-        }
-
-        // Zero out whatever was not defaulted, including time
-        for (; i < 7; i++) {
-            config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
-        }
-
-        config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
-        // Apply timezone offset from input. The actual zone can be changed
-        // with parseZone.
-        if (config._tzm != null) {
-            config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm);
-        }
-    }
-
-    function dateFromObject(config) {
-        var normalizedInput;
-
-        if (config._d) {
-            return;
-        }
-
-        normalizedInput = normalizeObjectUnits(config._i);
-        config._a = [
-            normalizedInput.year,
-            normalizedInput.month,
-            normalizedInput.day,
-            normalizedInput.hour,
-            normalizedInput.minute,
-            normalizedInput.second,
-            normalizedInput.millisecond
-        ];
-
-        dateFromConfig(config);
-    }
-
-    function currentDateArray(config) {
-        var now = new Date();
-        if (config._useUTC) {
-            return [
-                now.getUTCFullYear(),
-                now.getUTCMonth(),
-                now.getUTCDate()
-            ];
-        } else {
-            return [now.getFullYear(), now.getMonth(), now.getDate()];
-        }
-    }
-
-    // date from string and format string
-    function makeDateFromStringAndFormat(config) {
-
-        if (config._f === moment.ISO_8601) {
-            parseISO(config);
-            return;
-        }
-
-        config._a = [];
-        config._pf.empty = true;
-
-        // This array is used to make a Date, either with `new Date` or `Date.UTC`
-        var lang = getLangDefinition(config._l),
-            string = '' + config._i,
-            i, parsedInput, tokens, token, skipped,
-            stringLength = string.length,
-            totalParsedInputLength = 0;
-
-        tokens = expandFormat(config._f, lang).match(formattingTokens) || [];
-
-        for (i = 0; i < tokens.length; i++) {
-            token = tokens[i];
-            parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
-            if (parsedInput) {
-                skipped = string.substr(0, string.indexOf(parsedInput));
-                if (skipped.length > 0) {
-                    config._pf.unusedInput.push(skipped);
-                }
-                string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
-                totalParsedInputLength += parsedInput.length;
-            }
-            // don't parse if it's not a known token
-            if (formatTokenFunctions[token]) {
-                if (parsedInput) {
-                    config._pf.empty = false;
-                }
-                else {
-                    config._pf.unusedTokens.push(token);
-                }
-                addTimeToArrayFromToken(token, parsedInput, config);
-            }
-            else if (config._strict && !parsedInput) {
-                config._pf.unusedTokens.push(token);
-            }
-        }
-
-        // add remaining unparsed input length to the string
-        config._pf.charsLeftOver = stringLength - totalParsedInputLength;
-        if (string.length > 0) {
-            config._pf.unusedInput.push(string);
-        }
-
-        // handle am pm
-        if (config._isPm && config._a[HOUR] < 12) {
-            config._a[HOUR] += 12;
-        }
-        // if is 12 am, change hours to 0
-        if (config._isPm === false && config._a[HOUR] === 12) {
-            config._a[HOUR] = 0;
-        }
-
-        dateFromConfig(config);
-        checkOverflow(config);
-    }
-
-    function unescapeFormat(s) {
-        return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
-            return p1 || p2 || p3 || p4;
-        });
-    }
-
-    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
-    function regexpEscape(s) {
-        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
-    }
-
-    // date from string and array of format strings
-    function makeDateFromStringAndArray(config) {
-        var tempConfig,
-            bestMoment,
-
-            scoreToBeat,
-            i,
-            currentScore;
-
-        if (config._f.length === 0) {
-            config._pf.invalidFormat = true;
-            config._d = new Date(NaN);
-            return;
-        }
-
-        for (i = 0; i < config._f.length; i++) {
-            currentScore = 0;
-            tempConfig = extend({}, config);
-            tempConfig._pf = defaultParsingFlags();
-            tempConfig._f = config._f[i];
-            makeDateFromStringAndFormat(tempConfig);
-
-            if (!isValid(tempConfig)) {
-                continue;
-            }
-
-            // if there is any input that was not parsed add a penalty for that format
-            currentScore += tempConfig._pf.charsLeftOver;
-
-            //or tokens
-            currentScore += tempConfig._pf.unusedTokens.length * 10;
-
-            tempConfig._pf.score = currentScore;
-
-            if (scoreToBeat == null || currentScore < scoreToBeat) {
-                scoreToBeat = currentScore;
-                bestMoment = tempConfig;
-            }
-        }
-
-        extend(config, bestMoment || tempConfig);
-    }
-
-    // date from iso format
-    function parseISO(config) {
-        var i, l,
-            string = config._i,
-            match = isoRegex.exec(string);
-
-        if (match) {
-            config._pf.iso = true;
-            for (i = 0, l = isoDates.length; i < l; i++) {
-                if (isoDates[i][1].exec(string)) {
-                    // match[5] should be "T" or undefined
-                    config._f = isoDates[i][0] + (match[6] || " ");
-                    break;
-                }
-            }
-            for (i = 0, l = isoTimes.length; i < l; i++) {
-                if (isoTimes[i][1].exec(string)) {
-                    config._f += isoTimes[i][0];
-                    break;
-                }
-            }
-            if (string.match(parseTokenTimezone)) {
-                config._f += "Z";
-            }
-            makeDateFromStringAndFormat(config);
-        } else {
-            config._isValid = false;
-        }
-    }
-
-    // date from iso format or fallback
-    function makeDateFromString(config) {
-        parseISO(config);
-        if (config._isValid === false) {
-            delete config._isValid;
-            moment.createFromInputFallback(config);
-        }
-    }
-
-    function makeDateFromInput(config) {
-        var input = config._i,
-            matched = aspNetJsonRegex.exec(input);
-
-        if (input === undefined) {
-            config._d = new Date();
-        } else if (matched) {
-            config._d = new Date(+matched[1]);
-        } else if (typeof input === 'string') {
-            makeDateFromString(config);
-        } else if (isArray(input)) {
-            config._a = input.slice(0);
-            dateFromConfig(config);
-        } else if (isDate(input)) {
-            config._d = new Date(+input);
-        } else if (typeof(input) === 'object') {
-            dateFromObject(config);
-        } else if (typeof(input) === 'number') {
-            // from milliseconds
-            config._d = new Date(input);
-        } else {
-            moment.createFromInputFallback(config);
-        }
-    }
-
-    function makeDate(y, m, d, h, M, s, ms) {
-        //can't just apply() to create a date:
-        //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
-        var date = new Date(y, m, d, h, M, s, ms);
-
-        //the date constructor doesn't accept years < 1970
-        if (y < 1970) {
-            date.setFullYear(y);
-        }
-        return date;
-    }
-
-    function makeUTCDate(y) {
-        var date = new Date(Date.UTC.apply(null, arguments));
-        if (y < 1970) {
-            date.setUTCFullYear(y);
-        }
-        return date;
-    }
-
-    function parseWeekday(input, language) {
-        if (typeof input === 'string') {
-            if (!isNaN(input)) {
-                input = parseInt(input, 10);
-            }
-            else {
-                input = language.weekdaysParse(input);
-                if (typeof input !== 'number') {
-                    return null;
-                }
-            }
-        }
-        return input;
-    }
-
-    /************************************
-        Relative Time
-    ************************************/
-
-
-    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
-    function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
-        return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
-    }
-
-    function relativeTime(milliseconds, withoutSuffix, lang) {
-        var seconds = round(Math.abs(milliseconds) / 1000),
-            minutes = round(seconds / 60),
-            hours = round(minutes / 60),
-            days = round(hours / 24),
-            years = round(days / 365),
-            args = seconds < relativeTimeThresholds.s  && ['s', seconds] ||
-                minutes === 1 && ['m'] ||
-                minutes < relativeTimeThresholds.m && ['mm', minutes] ||
-                hours === 1 && ['h'] ||
-                hours < relativeTimeThresholds.h && ['hh', hours] ||
-                days === 1 && ['d'] ||
-                days <= relativeTimeThresholds.dd && ['dd', days] ||
-                days <= relativeTimeThresholds.dm && ['M'] ||
-                days < relativeTimeThresholds.dy && ['MM', round(days / 30)] ||
-                years === 1 && ['y'] || ['yy', years];
-        args[2] = withoutSuffix;
-        args[3] = milliseconds > 0;
-        args[4] = lang;
-        return substituteTimeAgo.apply({}, args);
-    }
-
-
-    /************************************
-        Week of Year
-    ************************************/
-
-
-    // firstDayOfWeek       0 = sun, 6 = sat
-    //                      the day of the week that starts the week
-    //                      (usually sunday or monday)
-    // firstDayOfWeekOfYear 0 = sun, 6 = sat
-    //                      the first week is the week that contains the first
-    //                      of this day of the week
-    //                      (eg. ISO weeks use thursday (4))
-    function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
-        var end = firstDayOfWeekOfYear - firstDayOfWeek,
-            daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
-            adjustedMoment;
-
-
-        if (daysToDayOfWeek > end) {
-            daysToDayOfWeek -= 7;
-        }
-
-        if (daysToDayOfWeek < end - 7) {
-            daysToDayOfWeek += 7;
-        }
-
-        adjustedMoment = moment(mom).add('d', daysToDayOfWeek);
-        return {
-            week: Math.ceil(adjustedMoment.dayOfYear() / 7),
-            year: adjustedMoment.year()
-        };
-    }
-
-    //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
-    function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
-        var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear;
-
-        d = d === 0 ? 7 : d;
-        weekday = weekday != null ? weekday : firstDayOfWeek;
-        daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);
-        dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
-
-        return {
-            year: dayOfYear > 0 ? year : year - 1,
-            dayOfYear: dayOfYear > 0 ?  dayOfYear : daysInYear(year - 1) + dayOfYear
-        };
-    }
-
-    /************************************
-        Top Level Functions
-    ************************************/
-
-    function makeMoment(config) {
-        var input = config._i,
-            format = config._f;
-
-        if (input === null || (format === undefined && input === '')) {
-            return moment.invalid({nullInput: true});
-        }
-
-        if (typeof input === 'string') {
-            config._i = input = getLangDefinition().preparse(input);
-        }
-
-        if (moment.isMoment(input)) {
-            config = cloneMoment(input);
-
-            config._d = new Date(+input._d);
-        } else if (format) {
-            if (isArray(format)) {
-                makeDateFromStringAndArray(config);
-            } else {
-                makeDateFromStringAndFormat(config);
-            }
-        } else {
-            makeDateFromInput(config);
-        }
-
-        return new Moment(config);
-    }
-
-    moment = function (input, format, lang, strict) {
-        var c;
-
-        if (typeof(lang) === "boolean") {
-            strict = lang;
-            lang = undefined;
-        }
-        // object construction must be done this way.
-        // https://github.com/moment/moment/issues/1423
-        c = {};
-        c._isAMomentObject = true;
-        c._i = input;
-        c._f = format;
-        c._l = lang;
-        c._strict = strict;
-        c._isUTC = false;
-        c._pf = defaultParsingFlags();
-
-        return makeMoment(c);
-    };
-
-    moment.suppressDeprecationWarnings = false;
-
-    moment.createFromInputFallback = deprecate(
-            "moment construction falls back to js Date. This is " +
-            "discouraged and will be removed in upcoming major " +
-            "release. Please refer to " +
-            "https://github.com/moment/moment/issues/1407 for more info.",
-            function (config) {
-        config._d = new Date(config._i);
-    });
-
-    // Pick a moment m from moments so that m[fn](other) is true for all
-    // other. This relies on the function fn to be transitive.
-    //
-    // moments should either be an array of moment objects or an array, whose
-    // first element is an array of moment objects.
-    function pickBy(fn, moments) {
-        var res, i;
-        if (moments.length === 1 && isArray(moments[0])) {
-            moments = moments[0];
-        }
-        if (!moments.length) {
-            return moment();
-        }
-        res = moments[0];
-        for (i = 1; i < moments.length; ++i) {
-            if (moments[i][fn](res)) {
-                res = moments[i];
-            }
-        }
-        return res;
-    }
-
-    moment.min = function () {
-        var args = [].slice.call(arguments, 0);
-
-        return pickBy('isBefore', args);
-    };
-
-    moment.max = function () {
-        var args = [].slice.call(arguments, 0);
-
-        return pickBy('isAfter', args);
-    };
-
-    // creating with utc
-    moment.utc = function (input, format, lang, strict) {
-        var c;
-
-        if (typeof(lang) === "boolean") {
-            strict = lang;
-            lang = undefined;
-        }
-        // object construction must be done this way.
-        // https://github.com/moment/moment/issues/1423
-        c = {};
-        c._isAMomentObject = true;
-        c._useUTC = true;
-        c._isUTC = true;
-        c._l = lang;
-        c._i = input;
-        c._f = format;
-        c._strict = strict;
-        c._pf = defaultParsingFlags();
-
-        return makeMoment(c).utc();
-    };
-
-    // creating with unix timestamp (in seconds)
-    moment.unix = function (input) {
-        return moment(input * 1000);
-    };
-
-    // duration
-    moment.duration = function (input, key) {
-        var duration = input,
-            // matching against regexp is expensive, do it on demand
-            match = null,
-            sign,
-            ret,
-            parseIso;
-
-        if (moment.isDuration(input)) {
-            duration = {
-                ms: input._milliseconds,
-                d: input._days,
-                M: input._months
-            };
-        } else if (typeof input === 'number') {
-            duration = {};
-            if (key) {
-                duration[key] = input;
-            } else {
-                duration.milliseconds = input;
-            }
-        } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {
-            sign = (match[1] === "-") ? -1 : 1;
-            duration = {
-                y: 0,
-                d: toInt(match[DATE]) * sign,
-                h: toInt(match[HOUR]) * sign,
-                m: toInt(match[MINUTE]) * sign,
-                s: toInt(match[SECOND]) * sign,
-                ms: toInt(match[MILLISECOND]) * sign
-            };
-        } else if (!!(match = isoDurationRegex.exec(input))) {
-            sign = (match[1] === "-") ? -1 : 1;
-            parseIso = function (inp) {
-                // We'd normally use ~~inp for this, but unfortunately it also
-                // converts floats to ints.
-                // inp may be undefined, so careful calling replace on it.
-                var res = inp && parseFloat(inp.replace(',', '.'));
-                // apply sign while we're at it
-                return (isNaN(res) ? 0 : res) * sign;
-            };
-            duration = {
-                y: parseIso(match[2]),
-                M: parseIso(match[3]),
-                d: parseIso(match[4]),
-                h: parseIso(match[5]),
-                m: parseIso(match[6]),
-                s: parseIso(match[7]),
-                w: parseIso(match[8])
-            };
-        }
-
-        ret = new Duration(duration);
-
-        if (moment.isDuration(input) && input.hasOwnProperty('_lang')) {
-            ret._lang = input._lang;
-        }
-
-        return ret;
-    };
-
-    // version number
-    moment.version = VERSION;
-
-    // default format
-    moment.defaultFormat = isoFormat;
-
-    // constant that refers to the ISO standard
-    moment.ISO_8601 = function () {};
-
-    // Plugins that add properties should also add the key here (null value),
-    // so we can properly clone ourselves.
-    moment.momentProperties = momentProperties;
-
-    // This function will be called whenever a moment is mutated.
-    // It is intended to keep the offset in sync with the timezone.
-    moment.updateOffset = function () {};
-
-    // This function allows you to set a threshold for relative time strings
-    moment.relativeTimeThreshold = function(threshold, limit) {
-      if (relativeTimeThresholds[threshold] === undefined) {
-        return false;
-      }
-      relativeTimeThresholds[threshold] = limit;
-      return true;
-    };
-
-    // This function will load languages and then set the global language.  If
-    // no arguments are passed in, it will simply return the current global
-    // language key.
-    moment.lang = function (key, values) {
-        var r;
-        if (!key) {
-            return moment.fn._lang._abbr;
-        }
-        if (values) {
-            loadLang(normalizeLanguage(key), values);
-        } else if (values === null) {
-            unloadLang(key);
-            key = 'en';
-        } else if (!languages[key]) {
-            getLangDefinition(key);
-        }
-        r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
-        return r._abbr;
-    };
-
-    // returns language data
-    moment.langData = function (key) {
-        if (key && key._lang && key._lang._abbr) {
-            key = key._lang._abbr;
-        }
-        return getLangDefinition(key);
-    };
-
-    // compare moment object
-    moment.isMoment = function (obj) {
-        return obj instanceof Moment ||
-            (obj != null &&  obj.hasOwnProperty('_isAMomentObject'));
-    };
-
-    // for typechecking Duration objects
-    moment.isDuration = function (obj) {
-        return obj instanceof Duration;
-    };
-
-    for (i = lists.length - 1; i >= 0; --i) {
-        makeList(lists[i]);
-    }
-
-    moment.normalizeUnits = function (units) {
-        return normalizeUnits(units);
-    };
-
-    moment.invalid = function (flags) {
-        var m = moment.utc(NaN);
-        if (flags != null) {
-            extend(m._pf, flags);
-        }
-        else {
-            m._pf.userInvalidated = true;
-        }
-
-        return m;
-    };
-
-    moment.parseZone = function () {
-        return moment.apply(null, arguments).parseZone();
-    };
-
-    moment.parseTwoDigitYear = function (input) {
-        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
-    };
-
-    /************************************
-        Moment Prototype
-    ************************************/
-
-
-    extend(moment.fn = Moment.prototype, {
-
-        clone : function () {
-            return moment(this);
-        },
-
-        valueOf : function () {
-            return +this._d + ((this._offset || 0) * 60000);
-        },
-
-        unix : function () {
-            return Math.floor(+this / 1000);
-        },
-
-        toString : function () {
-            return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
-        },
-
-        toDate : function () {
-            return this._offset ? new Date(+this) : this._d;
-        },
-
-        toISOString : function () {
-            var m = moment(this).utc();
-            if (0 < m.year() && m.year() <= 9999) {
-                return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
-            } else {
-                return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
-            }
-        },
-
-        toArray : function () {
-            var m = this;
-            return [
-                m.year(),
-                m.month(),
-                m.date(),
-                m.hours(),
-                m.minutes(),
-                m.seconds(),
-                m.milliseconds()
-            ];
-        },
-
-        isValid : function () {
-            return isValid(this);
-        },
-
-        isDSTShifted : function () {
-
-            if (this._a) {
-                return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
-            }
-
-            return false;
-        },
-
-        parsingFlags : function () {
-            return extend({}, this._pf);
-        },
-
-        invalidAt: function () {
-            return this._pf.overflow;
-        },
-
-        utc : function () {
-            return this.zone(0);
-        },
-
-        local : function () {
-            this.zone(0);
-            this._isUTC = false;
-            return this;
-        },
-
-        format : function (inputString) {
-            var output = formatMoment(this, inputString || moment.defaultFormat);
-            return this.lang().postformat(output);
-        },
-
-        add : function (input, val) {
-            var dur;
-            // switch args to support add('s', 1) and add(1, 's')
-            if (typeof input === 'string' && typeof val === 'string') {
-                dur = moment.duration(isNaN(+val) ? +input : +val, isNaN(+val) ? val : input);
-            } else if (typeof input === 'string') {
-                dur = moment.duration(+val, input);
-            } else {
-                dur = moment.duration(input, val);
-            }
-            addOrSubtractDurationFromMoment(this, dur, 1);
-            return this;
-        },
-
-        subtract : function (input, val) {
-            var dur;
-            // switch args to support subtract('s', 1) and subtract(1, 's')
-            if (typeof input === 'string' && typeof val === 'string') {
-                dur = moment.duration(isNaN(+val) ? +input : +val, isNaN(+val) ? val : input);
-            } else if (typeof input === 'string') {
-                dur = moment.duration(+val, input);
-            } else {
-                dur = moment.duration(input, val);
-            }
-            addOrSubtractDurationFromMoment(this, dur, -1);
-            return this;
-        },
-
-        diff : function (input, units, asFloat) {
-            var that = makeAs(input, this),
-                zoneDiff = (this.zone() - that.zone()) * 6e4,
-                diff, output;
-
-            units = normalizeUnits(units);
-
-            if (units === 'year' || units === 'month') {
-                // average number of days in the months in the given dates
-                diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
-                // difference in months
-                output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
-                // adjust by taking difference in days, average number of days
-                // and dst in the given months.
-                output += ((this - moment(this).startOf('month')) -
-                        (that - moment(that).startOf('month'))) / diff;
-                // same as above but with zones, to negate all dst
-                output -= ((this.zone() - moment(this).startOf('month').zone()) -
-                        (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff;
-                if (units === 'year') {
-                    output = output / 12;
-                }
-            } else {
-                diff = (this - that);
-                output = units === 'second' ? diff / 1e3 : // 1000
-                    units === 'minute' ? diff / 6e4 : // 1000 * 60
-                    units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
-                    units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
-                    units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
-                    diff;
-            }
-            return asFloat ? output : absRound(output);
-        },
-
-        from : function (time, withoutSuffix) {
-            return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
-        },
-
-        fromNow : function (withoutSuffix) {
-            return this.from(moment(), withoutSuffix);
-        },
-
-        calendar : function (time) {
-            // We want to compare the start of today, vs this.
-            // Getting start-of-today depends on whether we're zone'd or not.
-            var now = time || moment(),
-                sod = makeAs(now, this).startOf('day'),
-                diff = this.diff(sod, 'days', true),
-                format = diff < -6 ? 'sameElse' :
-                    diff < -1 ? 'lastWeek' :
-                    diff < 0 ? 'lastDay' :
-                    diff < 1 ? 'sameDay' :
-                    diff < 2 ? 'nextDay' :
-                    diff < 7 ? 'nextWeek' : 'sameElse';
-            return this.format(this.lang().calendar(format, this));
-        },
-
-        isLeapYear : function () {
-            return isLeapYear(this.year());
-        },
-
-        isDST : function () {
-            return (this.zone() < this.clone().month(0).zone() ||
-                this.zone() < this.clone().month(5).zone());
-        },
-
-        day : function (input) {
-            var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
-            if (input != null) {
-                input = parseWeekday(input, this.lang());
-                return this.add({ d : input - day });
-            } else {
-                return day;
-            }
-        },
-
-        month : makeAccessor('Month', true),
-
-        startOf: function (units) {
-            units = normalizeUnits(units);
-            // the following switch intentionally omits break keywords
-            // to utilize falling through the cases.
-            switch (units) {
-            case 'year':
-                this.month(0);
-                /* falls through */
-            case 'quarter':
-            case 'month':
-                this.date(1);
-                /* falls through */
-            case 'week':
-            case 'isoWeek':
-            case 'day':
-                this.hours(0);
-                /* falls through */
-            case 'hour':
-                this.minutes(0);
-                /* falls through */
-            case 'minute':
-                this.seconds(0);
-                /* falls through */
-            case 'second':
-                this.milliseconds(0);
-                /* falls through */
-            }
-
-            // weeks are a special case
-            if (units === 'week') {
-                this.weekday(0);
-            } else if (units === 'isoWeek') {
-                this.isoWeekday(1);
-            }
-
-            // quarters are also special
-            if (units === 'quarter') {
-                this.month(Math.floor(this.month() / 3) * 3);
-            }
-
-            return this;
-        },
-
-        endOf: function (units) {
-            units = normalizeUnits(units);
-            return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1);
-        },
-
-        isAfter: function (input, units) {
-            units = typeof units !== 'undefined' ? units : 'millisecond';
-            return +this.clone().startOf(units) > +moment(input).startOf(units);
-        },
-
-        isBefore: function (input, units) {
-            units = typeof units !== 'undefined' ? units : 'millisecond';
-            return +this.clone().startOf(units) < +moment(input).startOf(units);
-        },
-
-        isSame: function (input, units) {
-            units = units || 'ms';
-            return +this.clone().startOf(units) === +makeAs(input, this).startOf(units);
-        },
-
-        min: deprecate(
-                 "moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",
-                 function (other) {
-                     other = moment.apply(null, arguments);
-                     return other < this ? this : other;
-                 }
-         ),
-
-        max: deprecate(
-                "moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",
-                function (other) {
-                    other = moment.apply(null, arguments);
-                    return other > this ? this : other;
-                }
-        ),
-
-        // keepTime = true means only change the timezone, without affecting
-        // the local hour. So 5:31:26 +0300 --[zone(2, true)]--> 5:31:26 +0200
-        // It is possible that 5:31:26 doesn't exist int zone +0200, so we
-        // adjust the time as needed, to be valid.
-        //
-        // Keeping the time actually adds/subtracts (one hour)
-        // from the actual represented time. That is why we call updateOffset
-        // a second time. In case it wants us to change the offset again
-        // _changeInProgress == true case, then we have to adjust, because
-        // there is no such time in the given timezone.
-        zone : function (input, keepTime) {
-            var offset = this._offset || 0;
-            if (input != null) {
-                if (typeof input === "string") {
-                    input = timezoneMinutesFromString(input);
-                }
-                if (Math.abs(input) < 16) {
-                    input = input * 60;
-                }
-                this._offset = input;
-                this._isUTC = true;
-                if (offset !== input) {
-                    if (!keepTime || this._changeInProgress) {
-                        addOrSubtractDurationFromMoment(this,
-                                moment.duration(offset - input, 'm'), 1, false);
-                    } else if (!this._changeInProgress) {
-                        this._changeInProgress = true;
-                        moment.updateOffset(this, true);
-                        this._changeInProgress = null;
-                    }
-                }
-            } else {
-                return this._isUTC ? offset : this._d.getTimezoneOffset();
-            }
-            return this;
-        },
-
-        zoneAbbr : function () {
-            return this._isUTC ? "UTC" : "";
-        },
-
-        zoneName : function () {
-            return this._isUTC ? "Coordinated Universal Time" : "";
-        },
-
-        parseZone : function () {
-            if (this._tzm) {
-                this.zone(this._tzm);
-            } else if (typeof this._i === 'string') {
-                this.zone(this._i);
-            }
-            return this;
-        },
-
-        hasAlignedHourOffset : function (input) {
-            if (!input) {
-                input = 0;
-            }
-            else {
-                input = moment(input).zone();
-            }
-
-            return (this.zone() - input) % 60 === 0;
-        },
-
-        daysInMonth : function () {
-            return daysInMonth(this.year(), this.month());
-        },
-
-        dayOfYear : function (input) {
-            var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
-            return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
-        },
-
-        quarter : function (input) {
-            return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
-        },
-
-        weekYear : function (input) {
-            var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year;
-            return input == null ? year : this.add("y", (input - year));
-        },
-
-        isoWeekYear : function (input) {
-            var year = weekOfYear(this, 1, 4).year;
-            return input == null ? year : this.add("y", (input - year));
-        },
-
-        week : function (input) {
-            var week = this.lang().week(this);
-            return input == null ? week : this.add("d", (input - week) * 7);
-        },
-
-        isoWeek : function (input) {
-            var week = weekOfYear(this, 1, 4).week;
-            return input == null ? week : this.add("d", (input - week) * 7);
-        },
-
-        weekday : function (input) {
-            var weekday = (this.day() + 7 - this.lang()._week.dow) % 7;
-            return input == null ? weekday : this.add("d", input - weekday);
-        },
-
-        isoWeekday : function (input) {
-            // behaves the same as moment#day except
-            // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
-            // as a setter, sunday should belong to the previous week.
-            return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
-        },
-
-        isoWeeksInYear : function () {
-            return weeksInYear(this.year(), 1, 4);
-        },
-
-        weeksInYear : function () {
-            var weekInfo = this._lang._week;
-            return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
-        },
-
-        get : function (units) {
-            units = normalizeUnits(units);
-            return this[units]();
-        },
-
-        set : function (units, value) {
-            units = normalizeUnits(units);
-            if (typeof this[units] === 'function') {
-                this[units](value);
-            }
-            return this;
-        },
-
-        // If passed a language key, it will set the language for this
-        // instance.  Otherwise, it will return the language configuration
-        // variables for this instance.
-        lang : function (key) {
-            if (key === undefined) {
-                return this._lang;
-            } else {
-                this._lang = getLangDefinition(key);
-                return this;
-            }
-        }
-    });
-
-    function rawMonthSetter(mom, value) {
-        var dayOfMonth;
-
-        // TODO: Move this out of here!
-        if (typeof value === 'string') {
-            value = mom.lang().monthsParse(value);
-            // TODO: Another silent failure?
-            if (typeof value !== 'number') {
-                return mom;
-            }
-        }
-
-        dayOfMonth = Math.min(mom.date(),
-                daysInMonth(mom.year(), value));
-        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
-        return mom;
-    }
-
-    function rawGetter(mom, unit) {
-        return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();
-    }
-
-    function rawSetter(mom, unit, value) {
-        if (unit === 'Month') {
-            return rawMonthSetter(mom, value);
-        } else {
-            return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
-        }
-    }
-
-    function makeAccessor(unit, keepTime) {
-        return function (value) {
-            if (value != null) {
-                rawSetter(this, unit, value);
-                moment.updateOffset(this, keepTime);
-                return this;
-            } else {
-                return rawGetter(this, unit);
-            }
-        };
-    }
-
-    moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false);
-    moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false);
-    moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false);
-    // Setting the hour should keep the time, because the user explicitly
-    // specified which hour he wants. So trying to maintain the same hour (in
-    // a new timezone) makes sense. Adding/subtracting hours does not follow
-    // this rule.
-    moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true);
-    // moment.fn.month is defined separately
-    moment.fn.date = makeAccessor('Date', true);
-    moment.fn.dates = deprecate("dates accessor is deprecated. Use date instead.", makeAccessor('Date', true));
-    moment.fn.year = makeAccessor('FullYear', true);
-    moment.fn.years = deprecate("years accessor is deprecated. Use year instead.", makeAccessor('FullYear', true));
-
-    // add plural methods
-    moment.fn.days = moment.fn.day;
-    moment.fn.months = moment.fn.month;
-    moment.fn.weeks = moment.fn.week;
-    moment.fn.isoWeeks = moment.fn.isoWeek;
-    moment.fn.quarters = moment.fn.quarter;
-
-    // add aliased format methods
-    moment.fn.toJSON = moment.fn.toISOString;
-
-    /************************************
-        Duration Prototype
-    ************************************/
-
-
-    extend(moment.duration.fn = Duration.prototype, {
-
-        _bubble : function () {
-            var milliseconds = this._milliseconds,
-                days = this._days,
-                months = this._months,
-                data = this._data,
-                seconds, minutes, hours, years;
-
-            // The following code bubbles up values, see the tests for
-            // examples of what that means.
-            data.milliseconds = milliseconds % 1000;
-
-            seconds = absRound(milliseconds / 1000);
-            data.seconds = seconds % 60;
-
-            minutes = absRound(seconds / 60);
-            data.minutes = minutes % 60;
-
-            hours = absRound(minutes / 60);
-            data.hours = hours % 24;
-
-            days += absRound(hours / 24);
-            data.days = days % 30;
-
-            months += absRound(days / 30);
-            data.months = months % 12;
-
-            years = absRound(months / 12);
-            data.years = years;
-        },
-
-        weeks : function () {
-            return absRound(this.days() / 7);
-        },
-
-        valueOf : function () {
-            return this._milliseconds +
-              this._days * 864e5 +
-              (this._months % 12) * 2592e6 +
-              toInt(this._months / 12) * 31536e6;
-        },
-
-        humanize : function (withSuffix) {
-            var difference = +this,
-                output = relativeTime(difference, !withSuffix, this.lang());
-
-            if (withSuffix) {
-                output = this.lang().pastFuture(difference, output);
-            }
-
-            return this.lang().postformat(output);
-        },
-
-        add : function (input, val) {
-            // supports only 2.0-style add(1, 's') or add(moment)
-            var dur = moment.duration(input, val);
-
-            this._milliseconds += dur._milliseconds;
-            this._days += dur._days;
-            this._months += dur._months;
-
-            this._bubble();
-
-            return this;
-        },
-
-        subtract : function (input, val) {
-            var dur = moment.duration(input, val);
-
-            this._milliseconds -= dur._milliseconds;
-            this._days -= dur._days;
-            this._months -= dur._months;
-
-            this._bubble();
-
-            return this;
-        },
-
-        get : function (units) {
-            units = normalizeUnits(units);
-            return this[units.toLowerCase() + 's']();
-        },
-
-        as : function (units) {
-            units = normalizeUnits(units);
-            return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's']();
-        },
-
-        lang : moment.fn.lang,
-
-        toIsoString : function () {
-            // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
-            var years = Math.abs(this.years()),
-                months = Math.abs(this.months()),
-                days = Math.abs(this.days()),
-                hours = Math.abs(this.hours()),
-                minutes = Math.abs(this.minutes()),
-                seconds = Math.abs(this.seconds() + this.milliseconds() / 1000);
-
-            if (!this.asSeconds()) {
-                // this is the same as C#'s (Noda) and python (isodate)...
-                // but not other JS (goog.date)
-                return 'P0D';
-            }
-
-            return (this.asSeconds() < 0 ? '-' : '') +
-                'P' +
-                (years ? years + 'Y' : '') +
-                (months ? months + 'M' : '') +
-                (days ? days + 'D' : '') +
-                ((hours || minutes || seconds) ? 'T' : '') +
-                (hours ? hours + 'H' : '') +
-                (minutes ? minutes + 'M' : '') +
-                (seconds ? seconds + 'S' : '');
-        }
-    });
-
-    function makeDurationGetter(name) {
-        moment.duration.fn[name] = function () {
-            return this._data[name];
-        };
-    }
-
-    function makeDurationAsGetter(name, factor) {
-        moment.duration.fn['as' + name] = function () {
-            return +this / factor;
-        };
-    }
-
-    for (i in unitMillisecondFactors) {
-        if (unitMillisecondFactors.hasOwnProperty(i)) {
-            makeDurationAsGetter(i, unitMillisecondFactors[i]);
-            makeDurationGetter(i.toLowerCase());
-        }
-    }
-
-    makeDurationAsGetter('Weeks', 6048e5);
-    moment.duration.fn.asMonths = function () {
-        return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12;
-    };
-
-
-    /************************************
-        Default Lang
-    ************************************/
-
-
-    // Set default language, other languages will inherit from English.
-    moment.lang('en', {
-        ordinal : function (number) {
-            var b = number % 10,
-                output = (toInt(number % 100 / 10) === 1) ? 'th' :
-                (b === 1) ? 'st' :
-                (b === 2) ? 'nd' :
-                (b === 3) ? 'rd' : 'th';
-            return number + output;
-        }
-    });
-
-    /* EMBED_LANGUAGES */
-
-    /************************************
-        Exposing Moment
-    ************************************/
-
-    function makeGlobal(shouldDeprecate) {
-        /*global ender:false */
-        if (typeof ender !== 'undefined') {
-            return;
-        }
-        oldGlobalMoment = globalScope.moment;
-        if (shouldDeprecate) {
-            globalScope.moment = deprecate(
-                    "Accessing Moment through the global scope is " +
-                    "deprecated, and will be removed in an upcoming " +
-                    "release.",
-                    moment);
-        } else {
-            globalScope.moment = moment;
-        }
-    }
-
-    // CommonJS module is defined
-    if (hasModule) {
-        module.exports = moment;
-    } else if (typeof define === "function" && define.amd) {
-        define("moment", function (require, exports, module) {
-            if (module.config && module.config() && module.config().noGlobal === true) {
-                // release the global variable
-                globalScope.moment = oldGlobalMoment;
-            }
-
-            return moment;
-        });
-        makeGlobal(true);
-    } else {
-        makeGlobal();
-    }
-}).call(this);
-
-},{}],5:[function(require,module,exports){
-/**
- * Copyright 2012 Craig Campbell
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Mousetrap is a simple keyboard shortcut library for Javascript with
- * no external dependencies
- *
- * @version 1.1.2
- * @url craig.is/killing/mice
- */
-
-  /**
-   * mapping of special keycodes to their corresponding keys
-   *
-   * everything in this dictionary cannot use keypress events
-   * so it has to be here to map to the correct keycodes for
-   * keyup/keydown events
-   *
-   * @type {Object}
-   */
-  var _MAP = {
-          8: 'backspace',
-          9: 'tab',
-          13: 'enter',
-          16: 'shift',
-          17: 'ctrl',
-          18: 'alt',
-          20: 'capslock',
-          27: 'esc',
-          32: 'space',
-          33: 'pageup',
-          34: 'pagedown',
-          35: 'end',
-          36: 'home',
-          37: 'left',
-          38: 'up',
-          39: 'right',
-          40: 'down',
-          45: 'ins',
-          46: 'del',
-          91: 'meta',
-          93: 'meta',
-          224: 'meta'
-      },
-
-      /**
-       * mapping for special characters so they can support
-       *
-       * this dictionary is only used incase you want to bind a
-       * keyup or keydown event to one of these keys
-       *
-       * @type {Object}
-       */
-      _KEYCODE_MAP = {
-          106: '*',
-          107: '+',
-          109: '-',
-          110: '.',
-          111 : '/',
-          186: ';',
-          187: '=',
-          188: ',',
-          189: '-',
-          190: '.',
-          191: '/',
-          192: '`',
-          219: '[',
-          220: '\\',
-          221: ']',
-          222: '\''
-      },
-
-      /**
-       * this is a mapping of keys that require shift on a US keypad
-       * back to the non shift equivelents
-       *
-       * this is so you can use keyup events with these keys
-       *
-       * note that this will only work reliably on US keyboards
-       *
-       * @type {Object}
-       */
-      _SHIFT_MAP = {
-          '~': '`',
-          '!': '1',
-          '@': '2',
-          '#': '3',
-          '$': '4',
-          '%': '5',
-          '^': '6',
-          '&': '7',
-          '*': '8',
-          '(': '9',
-          ')': '0',
-          '_': '-',
-          '+': '=',
-          ':': ';',
-          '\"': '\'',
-          '<': ',',
-          '>': '.',
-          '?': '/',
-          '|': '\\'
-      },
-
-      /**
-       * this is a list of special strings you can use to map
-       * to modifier keys when you specify your keyboard shortcuts
-       *
-       * @type {Object}
-       */
-      _SPECIAL_ALIASES = {
-          'option': 'alt',
-          'command': 'meta',
-          'return': 'enter',
-          'escape': 'esc'
-      },
-
-      /**
-       * variable to store the flipped version of _MAP from above
-       * needed to check if we should use keypress or not when no action
-       * is specified
-       *
-       * @type {Object|undefined}
-       */
-      _REVERSE_MAP,
-
-      /**
-       * a list of all the callbacks setup via Mousetrap.bind()
-       *
-       * @type {Object}
-       */
-      _callbacks = {},
-
-      /**
-       * direct map of string combinations to callbacks used for trigger()
-       *
-       * @type {Object}
-       */
-      _direct_map = {},
-
-      /**
-       * keeps track of what level each sequence is at since multiple
-       * sequences can start out with the same sequence
-       *
-       * @type {Object}
-       */
-      _sequence_levels = {},
-
-      /**
-       * variable to store the setTimeout call
-       *
-       * @type {null|number}
-       */
-      _reset_timer,
-
-      /**
-       * temporary state where we will ignore the next keyup
-       *
-       * @type {boolean|string}
-       */
-      _ignore_next_keyup = false,
-
-      /**
-       * are we currently inside of a sequence?
-       * type of action ("keyup" or "keydown" or "keypress") or false
-       *
-       * @type {boolean|string}
-       */
-      _inside_sequence = false;
-
-  /**
-   * loop through the f keys, f1 to f19 and add them to the map
-   * programatically
-   */
-  for (var i = 1; i < 20; ++i) {
-      _MAP[111 + i] = 'f' + i;
-  }
-
-  /**
-   * loop through to map numbers on the numeric keypad
-   */
-  for (i = 0; i <= 9; ++i) {
-      _MAP[i + 96] = i;
-  }
-
-  /**
-   * cross browser add event method
-   *
-   * @param {Element|HTMLDocument} object
-   * @param {string} type
-   * @param {Function} callback
-   * @returns void
-   */
-  function _addEvent(object, type, callback) {
-      if (object.addEventListener) {
-          return object.addEventListener(type, callback, false);
-      }
-
-      object.attachEvent('on' + type, callback);
-  }
-
-  /**
-   * takes the event and returns the key character
-   *
-   * @param {Event} e
-   * @return {string}
-   */
-  function _characterFromEvent(e) {
-
-      // for keypress events we should return the character as is
-      if (e.type == 'keypress') {
-          return String.fromCharCode(e.which);
-      }
-
-      // for non keypress events the special maps are needed
-      if (_MAP[e.which]) {
-          return _MAP[e.which];
-      }
-
-      if (_KEYCODE_MAP[e.which]) {
-          return _KEYCODE_MAP[e.which];
-      }
-
-      // if it is not in the special map
-      return String.fromCharCode(e.which).toLowerCase();
-  }
-
-  /**
-   * should we stop this event before firing off callbacks
-   *
-   * @param {Event} e
-   * @return {boolean}
-   */
-  function _stop(e) {
-      var element = e.target || e.srcElement,
-          tag_name = element.tagName;
-
-      // if the element has the class "mousetrap" then no need to stop
-      if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) {
-          return false;
-      }
-
-      // stop for input, select, and textarea
-      return tag_name == 'INPUT' || tag_name == 'SELECT' || tag_name == 'TEXTAREA' || (element.contentEditable && element.contentEditable == 'true');
-  }
-
-  /**
-   * checks if two arrays are equal
-   *
-   * @param {Array} modifiers1
-   * @param {Array} modifiers2
-   * @returns {boolean}
-   */
-  function _modifiersMatch(modifiers1, modifiers2) {
-      return modifiers1.sort().join(',') === modifiers2.sort().join(',');
-  }
-
-  /**
-   * resets all sequence counters except for the ones passed in
-   *
-   * @param {Object} do_not_reset
-   * @returns void
-   */
-  function _resetSequences(do_not_reset) {
-      do_not_reset = do_not_reset || {};
-
-      var active_sequences = false,
-          key;
-
-      for (key in _sequence_levels) {
-          if (do_not_reset[key]) {
-              active_sequences = true;
-              continue;
-          }
-          _sequence_levels[key] = 0;
-      }
-
-      if (!active_sequences) {
-          _inside_sequence = false;
-      }
-  }
-
-  /**
-   * finds all callbacks that match based on the keycode, modifiers,
-   * and action
-   *
-   * @param {string} character
-   * @param {Array} modifiers
-   * @param {string} action
-   * @param {boolean=} remove - should we remove any matches
-   * @param {string=} combination
-   * @returns {Array}
-   */
-  function _getMatches(character, modifiers, action, remove, combination) {
-      var i,
-          callback,
-          matches = [];
-
-      // if there are no events related to this keycode
-      if (!_callbacks[character]) {
-          return [];
-      }
-
-      // if a modifier key is coming up on its own we should allow it
-      if (action == 'keyup' && _isModifier(character)) {
-          modifiers = [character];
-      }
-
-      // loop through all callbacks for the key that was pressed
-      // and see if any of them match
-      for (i = 0; i < _callbacks[character].length; ++i) {
-          callback = _callbacks[character][i];
-
-          // if this is a sequence but it is not at the right level
-          // then move onto the next match
-          if (callback.seq && _sequence_levels[callback.seq] != callback.level) {
-              continue;
-          }
-
-          // if the action we are looking for doesn't match the action we got
-          // then we should keep going
-          if (action != callback.action) {
-              continue;
-          }
-
-          // if this is a keypress event that means that we need to only
-          // look at the character, otherwise check the modifiers as
-          // well
-          if (action == 'keypress' || _modifiersMatch(modifiers, callback.modifiers)) {
-
-              // remove is used so if you change your mind and call bind a
-              // second time with a new function the first one is overwritten
-              if (remove && callback.combo == combination) {
-                  _callbacks[character].splice(i, 1);
-              }
-
-              matches.push(callback);
-          }
-      }
-
-      return matches;
-  }
-
-  /**
-   * takes a key event and figures out what the modifiers are
-   *
-   * @param {Event} e
-   * @returns {Array}
-   */
-  function _eventModifiers(e) {
-      var modifiers = [];
-
-      if (e.shiftKey) {
-          modifiers.push('shift');
-      }
-
-      if (e.altKey) {
-          modifiers.push('alt');
-      }
-
-      if (e.ctrlKey) {
-          modifiers.push('ctrl');
-      }
-
-      if (e.metaKey) {
-          modifiers.push('meta');
-      }
-
-      return modifiers;
-  }
-
-  /**
-   * actually calls the callback function
-   *
-   * if your callback function returns false this will use the jquery
-   * convention - prevent default and stop propogation on the event
-   *
-   * @param {Function} callback
-   * @param {Event} e
-   * @returns void
-   */
-  function _fireCallback(callback, e) {
-      if (callback(e) === false) {
-          if (e.preventDefault) {
-              e.preventDefault();
-          }
-
-          if (e.stopPropagation) {
-              e.stopPropagation();
-          }
-
-          e.returnValue = false;
-          e.cancelBubble = true;
-      }
-  }
-
-  /**
-   * handles a character key event
-   *
-   * @param {string} character
-   * @param {Event} e
-   * @returns void
-   */
-  function _handleCharacter(character, e) {
-
-      // if this event should not happen stop here
-      if (_stop(e)) {
-          return;
-      }
-
-      var callbacks = _getMatches(character, _eventModifiers(e), e.type),
-          i,
-          do_not_reset = {},
-          processed_sequence_callback = false;
-
-      // loop through matching callbacks for this key event
-      for (i = 0; i < callbacks.length; ++i) {
-
-          // fire for all sequence callbacks
-          // this is because if for example you have multiple sequences
-          // bound such as "g i" and "g t" they both need to fire the
-          // callback for matching g cause otherwise you can only ever
-          // match the first one
-          if (callbacks[i].seq) {
-              processed_sequence_callback = true;
-
-              // keep a list of which sequences were matches for later
-              do_not_reset[callbacks[i].seq] = 1;
-              _fireCallback(callbacks[i].callback, e);
-              continue;
-          }
-
-          // if there were no sequence matches but we are still here
-          // that means this is a regular match so we should fire that
-          if (!processed_sequence_callback && !_inside_sequence) {
-              _fireCallback(callbacks[i].callback, e);
-          }
-      }
-
-      // if you are inside of a sequence and the key you are pressing
-      // is not a modifier key then we should reset all sequences
-      // that were not matched by this key event
-      if (e.type == _inside_sequence && !_isModifier(character)) {
-          _resetSequences(do_not_reset);
-      }
-  }
-
-  /**
-   * handles a keydown event
-   *
-   * @param {Event} e
-   * @returns void
-   */
-  function _handleKey(e) {
-
-      // normalize e.which for key events
-      // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion
-      e.which = typeof e.which == "number" ? e.which : e.keyCode;
-
-      var character = _characterFromEvent(e);
-
-      // no character found then stop
-      if (!character) {
-          return;
-      }
-
-      if (e.type == 'keyup' && _ignore_next_keyup == character) {
-          _ignore_next_keyup = false;
-          return;
-      }
-
-      _handleCharacter(character, e);
-  }
-
-  /**
-   * determines if the keycode specified is a modifier key or not
-   *
-   * @param {string} key
-   * @returns {boolean}
-   */
-  function _isModifier(key) {
-      return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta';
-  }
-
-  /**
-   * called to set a 1 second timeout on the specified sequence
-   *
-   * this is so after each key press in the sequence you have 1 second
-   * to press the next key before you have to start over
-   *
-   * @returns void
-   */
-  function _resetSequenceTimer() {
-      clearTimeout(_reset_timer);
-      _reset_timer = setTimeout(_resetSequences, 1000);
-  }
-
-  /**
-   * reverses the map lookup so that we can look for specific keys
-   * to see what can and can't use keypress
-   *
-   * @return {Object}
-   */
-  function _getReverseMap() {
-      if (!_REVERSE_MAP) {
-          _REVERSE_MAP = {};
-          for (var key in _MAP) {
-
-              // pull out the numeric keypad from here cause keypress should
-              // be able to detect the keys from the character
-              if (key > 95 && key < 112) {
-                  continue;
-              }
-
-              if (_MAP.hasOwnProperty(key)) {
-                  _REVERSE_MAP[_MAP[key]] = key;
-              }
-          }
-      }
-      return _REVERSE_MAP;
-  }
-
-  /**
-   * picks the best action based on the key combination
-   *
-   * @param {string} key - character for key
-   * @param {Array} modifiers
-   * @param {string=} action passed in
-   */
-  function _pickBestAction(key, modifiers, action) {
-
-      // if no action was picked in we should try to pick the one
-      // that we think would work best for this key
-      if (!action) {
-          action = _getReverseMap()[key] ? 'keydown' : 'keypress';
-      }
-
-      // modifier keys don't work as expected with keypress,
-      // switch to keydown
-      if (action == 'keypress' && modifiers.length) {
-          action = 'keydown';
-      }
-
-      return action;
-  }
-
-  /**
-   * binds a key sequence to an event
-   *
-   * @param {string} combo - combo specified in bind call
-   * @param {Array} keys
-   * @param {Function} callback
-   * @param {string=} action
-   * @returns void
-   */
-  function _bindSequence(combo, keys, callback, action) {
-
-      // start off by adding a sequence level record for this combination
-      // and setting the level to 0
-      _sequence_levels[combo] = 0;
-
-      // if there is no action pick the best one for the first key
-      // in the sequence
-      if (!action) {
-          action = _pickBestAction(keys[0], []);
-      }
-
-      /**
-       * callback to increase the sequence level for this sequence and reset
-       * all other sequences that were active
-       *
-       * @param {Event} e
-       * @returns void
-       */
-      var _increaseSequence = function(e) {
-              _inside_sequence = action;
-              ++_sequence_levels[combo];
-              _resetSequenceTimer();
-          },
-
-          /**
-           * wraps the specified callback inside of another function in order
-           * to reset all sequence counters as soon as this sequence is done
-           *
-           * @param {Event} e
-           * @returns void
-           */
-          _callbackAndReset = function(e) {
-              _fireCallback(callback, e);
-
-              // we should ignore the next key up if the action is key down
-              // or keypress.  this is so if you finish a sequence and
-              // release the key the final key will not trigger a keyup
-              if (action !== 'keyup') {
-                  _ignore_next_keyup = _characterFromEvent(e);
-              }
-
-              // weird race condition if a sequence ends with the key
-              // another sequence begins with
-              setTimeout(_resetSequences, 10);
-          },
-          i;
-
-      // loop through keys one at a time and bind the appropriate callback
-      // function.  for any key leading up to the final one it should
-      // increase the sequence. after the final, it should reset all sequences
-      for (i = 0; i < keys.length; ++i) {
-          _bindSingle(keys[i], i < keys.length - 1 ? _increaseSequence : _callbackAndReset, action, combo, i);
-      }
-  }
-
-  /**
-   * binds a single keyboard combination
-   *
-   * @param {string} combination
-   * @param {Function} callback
-   * @param {string=} action
-   * @param {string=} sequence_name - name of sequence if part of sequence
-   * @param {number=} level - what part of the sequence the command is
-   * @returns void
-   */
-  function _bindSingle(combination, callback, action, sequence_name, level) {
-
-      // make sure multiple spaces in a row become a single space
-      combination = combination.replace(/\s+/g, ' ');
-
-      var sequence = combination.split(' '),
-          i,
-          key,
-          keys,
-          modifiers = [];
-
-      // if this pattern is a sequence of keys then run through this method
-      // to reprocess each pattern one key at a time
-      if (sequence.length > 1) {
-          return _bindSequence(combination, sequence, callback, action);
-      }
-
-      // take the keys from this pattern and figure out what the actual
-      // pattern is all about
-      keys = combination === '+' ? ['+'] : combination.split('+');
-
-      for (i = 0; i < keys.length; ++i) {
-          key = keys[i];
-
-          // normalize key names
-          if (_SPECIAL_ALIASES[key]) {
-              key = _SPECIAL_ALIASES[key];
-          }
-
-          // if this is not a keypress event then we should
-          // be smart about using shift keys
-          // this will only work for US keyboards however
-          if (action && action != 'keypress' && _SHIFT_MAP[key]) {
-              key = _SHIFT_MAP[key];
-              modifiers.push('shift');
-          }
-
-          // if this key is a modifier then add it to the list of modifiers
-          if (_isModifier(key)) {
-              modifiers.push(key);
-          }
-      }
-
-      // depending on what the key combination is
-      // we will try to pick the best event for it
-      action = _pickBestAction(key, modifiers, action);
-
-      // make sure to initialize array if this is the first time
-      // a callback is added for this key
-      if (!_callbacks[key]) {
-          _callbacks[key] = [];
-      }
-
-      // remove an existing match if there is one
-      _getMatches(key, modifiers, action, !sequence_name, combination);
-
-      // add this call back to the array
-      // if it is a sequence put it at the beginning
-      // if not put it at the end
-      //
-      // this is important because the way these are processed expects
-      // the sequence ones to come first
-      _callbacks[key][sequence_name ? 'unshift' : 'push']({
-          callback: callback,
-          modifiers: modifiers,
-          action: action,
-          seq: sequence_name,
-          level: level,
-          combo: combination
-      });
-  }
-
-  /**
-   * binds multiple combinations to the same callback
-   *
-   * @param {Array} combinations
-   * @param {Function} callback
-   * @param {string|undefined} action
-   * @returns void
-   */
-  function _bindMultiple(combinations, callback, action) {
-      for (var i = 0; i < combinations.length; ++i) {
-          _bindSingle(combinations[i], callback, action);
-      }
-  }
-
-  // start!
-  _addEvent(document, 'keypress', _handleKey);
-  _addEvent(document, 'keydown', _handleKey);
-  _addEvent(document, 'keyup', _handleKey);
-
-  var mousetrap = {
-
-      /**
-       * binds an event to mousetrap
-       *
-       * can be a single key, a combination of keys separated with +,
-       * a comma separated list of keys, an array of keys, or
-       * a sequence of keys separated by spaces
-       *
-       * be sure to list the modifier keys first to make sure that the
-       * correct key ends up getting bound (the last key in the pattern)
-       *
-       * @param {string|Array} keys
-       * @param {Function} callback
-       * @param {string=} action - 'keypress', 'keydown', or 'keyup'
-       * @returns void
-       */
-      bind: function(keys, callback, action) {
-          _bindMultiple(keys instanceof Array ? keys : [keys], callback, action);
-          _direct_map[keys + ':' + action] = callback;
-          return this;
-      },
-
-      /**
-       * unbinds an event to mousetrap
-       *
-       * the unbinding sets the callback function of the specified key combo
-       * to an empty function and deletes the corresponding key in the
-       * _direct_map dict.
-       *
-       * the keycombo+action has to be exactly the same as
-       * it was defined in the bind method
-       *
-       * TODO: actually remove this from the _callbacks dictionary instead
-       * of binding an empty function
-       *
-       * @param {string|Array} keys
-       * @param {string} action
-       * @returns void
-       */
-      unbind: function(keys, action) {
-          if (_direct_map[keys + ':' + action]) {
-              delete _direct_map[keys + ':' + action];
-              this.bind(keys, function() {}, action);
-          }
-          return this;
-      },
-
-      /**
-       * triggers an event that has already been bound
-       *
-       * @param {string} keys
-       * @param {string=} action
-       * @returns void
-       */
-      trigger: function(keys, action) {
-          _direct_map[keys + ':' + action]();
-          return this;
-      },
-
-      /**
-       * resets the library back to its initial state.  this is useful
-       * if you want to clear out the current keyboard shortcuts and bind
-       * new ones - for example if you switch to another page
-       *
-       * @returns void
-       */
-      reset: function() {
-          _callbacks = {};
-          _direct_map = {};
-          return this;
-      }
-  };
-
-module.exports = mousetrap;
-
-
-},{}]},{},[1])
-(1)
-});
\ No newline at end of file
diff --git a/nemo-ui/src/main/resources/nemo/nemo.controller.js b/nemo-ui/src/main/resources/nemo/nemo.controller.js
deleted file mode 100644 (file)
index ec24662..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2015 Huawei, Inc and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-define(['app/nemo/nemo.module','app/nemo/nemo.services','app/nemo/js/vis'], function(topology) {
-  topology.register.controller('NemoController', ['$scope', '$rootScope', 'NemoService' ,  function ($scope, $rootScope, NemoService) {
-    $scope.updateChannels = function() {
-      NemoService.updateChannels();
-    };
-    $scope.updateChannels();
-  }]);
-
-});
diff --git a/nemo-ui/src/main/resources/nemo/nemo.directives.js b/nemo-ui/src/main/resources/nemo/nemo.directives.js
deleted file mode 100644 (file)
index 89e92da..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (c) 2015 Huawei, Inc and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-define(['app/nemo/nemo.module'], function(topology) {
-//define(['app/nemo/nemo.module'], function(topology) {
-  topology.register.directive('nemoChannel', function() {  
-  });
-});
diff --git a/nemo-ui/src/main/resources/nemo/nemo.module.js b/nemo-ui/src/main/resources/nemo/nemo.module.js
deleted file mode 100644 (file)
index ce30c34..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2015 Huawei, Inc and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-define(['angularAMD', 'app/routingConfig', 'app/core/core.services','Restangular', 'common/config/env.module'], function(ng) {
-
-  var nemo = angular.module('app.nemo', ['ui.router.state','app.core','restangular', 'config']);
-
-
-  nemo.config(function($stateProvider, $controllerProvider, $compileProvider, $provide, $translateProvider, NavHelperProvider) {
-
-  nemo.register = {
-      controller : $controllerProvider.register,
-      directive : $compileProvider.directive,
-      service : $provide.service,
-      factory : $provide.factory
-    };
-
-    $translateProvider.useStaticFilesLoader({
-      prefix: 'assets/data/locale-',
-      suffix: '.json'
-    });
-
-    NavHelperProvider.addControllerUrl('app/nemo/nemo.controller');
-    NavHelperProvider.addToMenu('nemo', {
-      "link": "#/nemo",
-      "title": "Nemo",
-      "active": "main.nemo",
-      "icon": "icon-link",
-      "page": {
-        "title": "NEMO",
-        "description": "NEMO"
-      }
-    });
-
-    var access = routingConfig.accessLevels;
-    $stateProvider.state('main.nemo', {
-      url: 'nemo',
-      access: access.public,
-      views : {
-        'content' : {
-          templateUrl: 'src/app/nemo/register.html',
-          controller: 'NemoController'
-        }
-      }
-    });
-
-  });
-
-  return nemo;
-
-});
-
diff --git a/nemo-ui/src/main/resources/nemo/nemo.services.js b/nemo-ui/src/main/resources/nemo/nemo.services.js
deleted file mode 100644 (file)
index eb80596..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2015 Huawei, Inc and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-define(['app/nemo/nemo.module'], function(nemo) {
-  nemo.register.factory('NemoRestangular', function(Restangular, ENV) {
-    var NemoRestangular = Restangular.withConfig(function(RestangularConfig) {
-      RestangularConfig.setBaseUrl(ENV.getBaseURL("MD_SAL"));
-    });
-    return NemoRestangular;
-  });
-  nemo.register.factory('NemoService', function(NemoRestangular) {
-    var org = org || {};
-    org.opendaylight = org.opendaylight || {};
-    org.opendaylight.nemo = org.opendaylight.nemo || {};
-    org.opendaylight.nemo.utils = org.opendaylight.nemo.utils || {};
-    org.opendaylight.nemo.utils.get = function(id) {
-      return document.getElementById(id);
-    };
-    org.opendaylight.nemo.utils.create = function(tag) {
-      return document.createElement(tag);
-    };
-    org.opendaylight.nemo.update = function() {
-      jQuery.ajax({
-        type: "POST",
-        "url": "/restconf/operations/nemo-channel:view-channel", //
-        processData: false,
-        contentType: "application/json",
-        data: JSON.stringify({"input":{"topology-id":"nemo"}}),
-        success:function (response) {
-          org.opendaylight.nemo.process(response);
-        }
-      });
-      return true;
-    };
-    org.opendaylight.nemo.process = function(data) {
-      var channelPannelHTML = "";
-      channelPannelHTML += '<div style="color:#ffffff;padding-top:15px;padding-bottom:15px;">';
-      channelPannelHTML += '<table style="width:100%;" cellspacing="1" cellpadding="1"><tr>';
-      channelPannelHTML += '<td style="width:50px;"><div>Alarms</div></td>';
-      channelPannelHTML += '<td><div>Description</div></td>';
-      channelPannelHTML += '<td style="width:100px;"><div>Bytes In</div></td>';
-      channelPannelHTML += '<td style="width:100px;"><div>Bytes Out</div></td>';
-      channelPannelHTML += '</tr></table>';
-      channelPannelHTML += '</div>';  
-      var topologies = data["output"]["topology"];
-      for (var i = 0; i < topologies.length; i++) {
-        var channels = topologies[i]["channel"];
-        if (typeof channels == "undefined" || channels == null) {
-          break;
-        }
-        for (var j = 0; j < channels.length; j++) {
-          var channel = channels[j];
-          channelPannelHTML += '<div style="color:#ffffff;padding-top:15px;padding-bottom:15px;border-top: 1px solid #888888;">';
-          channelPannelHTML += '<table style="width:100%;" cellspacing="1" cellpadding="1"><tr>';
-          channelPannelHTML += '<td style="width:50px;vertical-align:top;"><div><div class="' + (channel["channel-alarms"] > 0 ? 'label-danger' : 'label-success') + '" style="background-color:' + (channel["channel-alarms"] > 0 ? '#d9534f' : '#5cb85c') + '; border-radius:35px;width:35px;height:35px;line-height:35px;text-align:center;font-size:10px;">'+channel["channel-alarms"]+'</div></div></td>';
-          channelPannelHTML += '<td style="vertical-align:top;"><div>';
-          channelPannelHTML += '<div><span>Channel </span><span>'+channel["channel-id"]+'</span></div>';
-          channelPannelHTML += '<div><span style="color:#888888;">Controller: </span><span>'+channel["source"]["source-node"]+'</span></div>';
-          channelPannelHTML += '<div><span style="color:#888888;">Device: </span><span>'+channel["destination"]["dest-node"]+'</span></div>';
-          channelPannelHTML += '<div><span style="color:#888888;">Type: </span><span>'+channel["channel-type"]+'</span></div>';
-          channelPannelHTML += '<div><span style="color:#888888;">Call Home: </span><span>'+channel["call-home"]+'</span></div>';
-          channelPannelHTML += '<div><span style="color:#888888;">Number of Sessions: </span><span>'+channel["sessions"]+'</span></div>';
-          channelPannelHTML += '</div></td>';
-          channelPannelHTML += '<td style="width:100px;vertical-align:top;"><div>'+channel["bytes-in"]+' B'+'</div></td>';
-          channelPannelHTML += '<td style="width:100px;vertical-align:top;"><div>'+channel["bytes-out"]+' B'+'</div></td>';
-          channelPannelHTML += '</tr></table>';
-          channelPannelHTML += '</div>';
-          var sessions = channel["session"];
-          if (typeof sessions != "undefined" && sessions != null) {
-            for (var k = 0; k < sessions.length; k++) {
-              var session = sessions[k];
-              channelPannelHTML += '<div style="color:#ffffff;padding-top:15px;padding-bottom:15px;border-top: 1px solid #888888;">';
-              channelPannelHTML += '<table style="width:100%;" cellspacing="1" cellpadding="1"><tr>';
-              channelPannelHTML += '<td style="width:100px;vertical-align:top;"><div style="padding-left:50px;"><div class="' + (session["session-alarms"] > 0 ? 'label-danger' : 'label-success') + '" style="background-color:' + (session["session-alarms"] > 0 ? '#d9534f' : '#5cb85c') + '; border-radius:35px;width:35px;height:35px;line-height:35px;text-align:center;font-size:10px;">'+session["session-alarms"]+'</div></div></td>';
-              channelPannelHTML += '<td style="vertical-align:top;"><div>';
-              channelPannelHTML += '<div><span>Session </span><span>'+session["session-id"]+'</span></div>';
-              channelPannelHTML += '<div><span style="color:#888888;">Port: </span><span>'+session["termination-point"]["termination-point-id"]+'</span></div>';
-              channelPannelHTML += '</div></td>';
-              channelPannelHTML += '<td style="width:100px;vertical-align:top;"><div>'+session["bytes-in"]+' B'+'</div></td>';
-              channelPannelHTML += '<td style="width:100px;vertical-align:top;"><div>'+session["bytes-out"]+' B'+'</div></td>';
-              channelPannelHTML += '</tr></table>';
-              channelPannelHTML += '</div>';
-            }
-          }
-        }
-      }  
-      var channelPanel = org.opendaylight.nemo.utils.get("channelPanel");
-      channelPanel.innerHTML = channelPannelHTML;
-      return true;
-    };
-    org.opendaylight.nemo.initialize = function() {
-      org.opendaylight.nemo.update();
-    };
-    window.org = org;
-    var NemoService = {
-      updateChannels: function() {
-        org.opendaylight.nemo.initialize();
-      }
-    };
-    return NemoService;
-  });
-});
diff --git a/nemo-ui/src/main/resources/nemo/nemo.tpl.html b/nemo-ui/src/main/resources/nemo/nemo.tpl.html
deleted file mode 100644 (file)
index 69be44d..0000000
+++ /dev/null
@@ -1,1063 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">\r
-<head>\r
-    <meta http-equiv="Content-Type" content="text/html"; charset="utf-8" />\r
-    <title>nemo-ui-cn</title>\r
-    <link href="src/app/nemo/css/jquery-ui.min.css" rel="stylesheet" />\r
-    <link href="src/app/nemo/css/nemo_main.css" rel="stylesheet" />\r
-    <link rel="stylesheet" href="src/app/nemo/css/SI.css">\r
-    <link rel="stylesheet" href="src/app/nemo/css/NE.css">\r
-    <link href="src/app/nemo/css/SP.css" rel="stylesheet" />\r
-    <link rel="stylesheet" href="src/app/nemo/css/RR.css">\r
-    <link rel="stylesheet" href="src/app/nemo/css/AQ.css">\r
-\r
-    <script src="js/jquery-1.11.3.min.js"></script>\r
-    <script src="js/jquery-ui.min.js"></script>\r
-\r
-\r
-    <script src="src/app/nemo/js/vis.js"></script>\r
-    <script src="src/app/nemo/js/jquery.shCircleLoader-min.js"></script>\r
-    <script src="src/app/nemo/js/Nemo_Annouce_vis.js"></script>\r
-    <script src="src/app/nemo/js/Nemo_Main.js"></script>\r
-    <script src="src/app/nemo/js/Service_Instance.js"></script>\r
-       <script src="src/app/nemo/js/analyjson.js"></script>\r
-    <script src="src/app/nemo/js/Network_Entity.js"></script>\r
-    <script src="src/app/nemo/js/Service_Policy.js"></script>\r
-    <script type="text/javascript" src="src/app/nemo/js/submit.js" charset="utf-8"></script>\r
-    <script src="src/app/nemo/js/scrollrun.js"></script>\r
-    <script src="src/app/nemo/js/EI_tranjson.js"></script>\r
-    <script src="src/app/nemo/js/topo_data.js"></script>\r
-\r
-    <script>\r
-\r
-      var hostname = document.location.hostname;\r
-               var user_id = 1;\r
-               var user_password = 2;\r
-               var user_name = 3;\r
-               var user_role = 4;\r
-        var service_select = "";\r
-        var json_data, json_str;\r
-        nodes.add({\r
-            id: 100000,\r
-            group: 'null',\r
-            x: 700,\r
-            y: 400 \r
-        });\r
-               var user_str = localStorage.getItem("useinfo").split(",");\r
-               user_id = user_str[0];\r
-               user_name = user_str[1];\r
-               user_password = user_str[2];\r
-               user_role = user_str[3];\r
-\r
-        function guid() {\r
-            function S4() {\r
-                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\r
-            }\r
-            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());\r
-        }\r
-\r
-\r
-        jQuery(document).ready(function ($) {\r
-            //$('#loader').shCircleLoader();\r
-        \r
-            $(".id_").each(function () { $(this).val(guid()).attr("disabled", "true") });\r
-\r
-        });\r
-    </script>\r
-</head>\r
-<body>\r
-    <div class="group">\r
-\r
-        <div class="group_left">\r
-            <div class="title tt">\r
-                <h2>Service Configuration</h2>\r
-            </div>\r
-\r
-            <div class="btn_group">\r
-                <button class="btn_item" id="ser_init" >Service Instance</button>\r
-\r
-                <button class="btn_item" id="nemo-business-model">Service Modeling</button>\r
-\r
-                <button class="btn_item" id="net_ent_init">Network Entity</button>\r
-\r
-                <button class="btn_item" id="ser_poc_init">Service Policy</button>\r
-\r
-                <button class="btn_item" id="advance_query" style="display: none;">Advance Query</button>\r
-\r
-                <button class="btn_item">Resource Mapping Info</button>\r
-\r
-            </div>\r
-\r
-            <div class="btn_item_show" id="ser_inst_show">\r
-                <div class="Si_group">\r
-\r
-                    <div class="close_item_show">\r
-                        <img src="src/app/nemo/images/shut.png" />\r
-                    </div>\r
-                    <div class="h3_style">\r
-                        <h3>Service Instance</h3>\r
-                    </div>\r
-                    <p>Service Instance List:</p>\r
-                    <div class="select_btn">\r
-                        <select class="select_item">\r
-                        </select>\r
-                        <div class="btn_group_less">\r
-                            <input type="button" id="SI_Add" class="btn_ btn_SI" value="Add" />\r
-                            <input type="button" id="SI_Edit" class="btn_ btn_SI" value="Edit" />\r
-                            <input type="button" id="SI_Delete" class="btn_ btn_SI" value="Delete" />\r
-                        </div>\r
-                    </div>\r
-                    <div id="Add_show">\r
-                        <img class="close_group" src="src/app/nemo/images/shut.png" alt="close" />\r
-                        <span class="second_title">Service Name:</span><input class="text_item name_text" type="text" />\r
-                        <span class="second_title">Service Description:</span>\r
-                        <input class="text_item desc_text" type="text" />\r
-\r
-                        <input type="button" id="SI_Save" class="btn_ save_group" value="Save" />\r
-                    </div>\r
-\r
-                </div>\r
-            </div>\r
-\r
-            <div class="btn_item_show"></div>\r
-\r
-            <div class="btn_item_show">\r
-\r
-                <div class="close_item_show">\r
-                    <img src="src/app/nemo/images/shut.png" />\r
-                </div>\r
-\r
-                <div class="NE_up">\r
-                    <div class="up_group1" id="up_service_name">\r
-                        <div class="h3_style">\r
-                            <h3>Network Entity</h3>\r
-                        </div>\r
-                        <span class="second_title NE_serviceName">Service Name:</span>\r
-                        <select id="sel_1"></select>\r
-                    </div>\r
-                    <div class="up_group1 up_group1_2">\r
-                        <span class="second_title">Entity Instance List:</span>\r
-                        <select id="sel_2"></select>\r
-                    </div>\r
-                    <input type="button" id="NE_Edit" name="name" class="btn_" value="Edit" />\r
-                    <input type="button" id="NE_Delete" name="name" class="btn_" value="Delete" />\r
-                    <div id="up_down">\r
-                        <span class="second_title">Entity Type:</span>\r
-                        <select id="entity_type">\r
-                            <option value="node">node</option>\r
-                            <option value="connection">connection</option>\r
-                            <option value="flow">flow</option>\r
-                        </select>\r
-                        <input type="button" name="name" id="add_entity" class="btn_" value="Add" />\r
-                    </div>\r
-\r
-                </div>\r
-\r
-                <div class="NE_Add_show NE_node_show NE_close_item">\r
-\r
-                    <img class="NE_close_show" src="src/app/nemo/images/shut.png" alt="close" />\r
-                    <div class="NE_middle">\r
-                        <table>\r
-                            <tr>\r
-                                <td><span class="second_title">Node ID:</span> </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <input class="id_" id="node_id" type="text" name="name" value="" /></td>\r
-                            </tr>\r
-\r
-                            <tr>\r
-                                <td><span class="second_title">Node Type:</span></td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <select id="sel_show">                                        \r
-                                        <option value="l2-group">l2-group</option>\r
-                                        <option value="l3-group">l3-group</option>\r
-                                        <option value="ext-group">ext-group</option>\r
-                                        <option value="chain-group">chain-group</option>\r
-                                        <option value="fw">firewall</option>\r
-                                        <option value="lb">loadbalance</option>\r
-                                        <option value="cache">cache</option>\r
-                                    </select>\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td><span class="second_title">Node Name:</span><img class="alert_" id="node_icon" src="src/app/nemo/images/alert.png" /></td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <input type="text" id="node_name" name="name" value="" />\r
-                                </td>\r
-                            </tr>\r
-                        </table>\r
-                    </div>\r
-\r
-                    <div class="NE_down">\r
-                       \r
-                        <div id="l2-group_type" class="node_type_group node_type_group_group">\r
-                            <table class="select_table">\r
-                                <tr>\r
-                                    <td class="second_title">sub-node</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <select id="l2_addhost" class="txt2">\r
-                                         \r
-                                        </select>\r
-                                        <input class="btn_ add_node" id="l2_ok" type="button" name="name" value="Add" />\r
-                                    </td>\r
-                                </tr>                                                                                                                  \r
-                                <tr>\r
-                                    <td>\r
-                                        <div id="l2_delgroup" class="delgroup">\r
-                                            <table id="l2_select_table"></table>\r
-                                        </div>                                                               \r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-                            <div class="big_second_title">\r
-                                <span>Property</span>\r
-                            </div>\r
-                            <table>\r
-                                <tr>\r
-                                    <td class="second_title">ip-prefix:\r
-                                        <!--img class="alert_" id="" src="#" /--></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="l2-group_ip-prefix" value=""/></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">gateway-ip:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="l2-group_gateway-ip" value="" />\r
-                                    </td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">location:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="l2-group_location" value="" />\r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-                        </div>\r
-\r
-                        <div id="l3-group_type" class="node_type_group node_type_group_group">\r
-                            <table class="select_table">\r
-                                <tr>\r
-                                    <td class="second_title">sub-node</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <select id="l3_addhost" class="txt2">                                        \r
-                                        </select>\r
-                                        <input class="btn_ add_node" id="l3_ok" type="button" name="name" value="Add" />\r
-                                    </td>\r
-                                </tr>                                                                                                                  \r
-                                <tr>\r
-                                    <td>\r
-                                        <div id="l3_delgroup" class="delgroup">\r
-                                              <table id="l3_select_table"></table>\r
-                                        </div>                                                               \r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-\r
-                            <div class="big_second_title">\r
-                                <span>Property</span>\r
-                            </div>\r
-                            <table>\r
-                                <tr>\r
-                                    <td class="second_title">ip-prefix:\r
-                                        <!--img class="alert_" id="" src="#" /--></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="l3-group_ip-prefix" value=""/></td>\r
-                                </tr>\r
-                   \r
-                            </table>\r
-                        </div>\r
-\r
-                        <div id="ext-group_type" class="node_type_group">                                                                                                                  \r
-\r
-                            <div class="big_second_title">\r
-                                <span>Property</span>\r
-                            </div>\r
-                            <table>\r
-                                <tr>\r
-                                    <td class="second_title">location:\r
-                                        <!--img class="alert_" id="" src="#" /--></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="ext-group_location" value=""/></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">ac-info-network:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="ext-group_ac-info-network" value=""/>\r
-                                    </td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">ac-info-protocol:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="ext-group_ac-info-protocol" value=""/>\r
-                                    </td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">ip-prefix:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="ext-group_ip-prefix" value=""/>\r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-                        </div>\r
-                        <div id="chain-group_type" class="node_type_group node_type_group_group">\r
-                               <table class="select_table">\r
-                                <tr>\r
-                                    <td class="second_title">Vas Node:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <select id="chain_addhost" class="txt2">  </select>\r
-                                        <input class="btn_ add_node" id="chain_ok" type="button" name="name" value="Add" />\r
-                                    </td>\r
-                                </tr>                                                                                                                  \r
-                                <tr>\r
-                                    <td>\r
-                                        <div id="chain_delgroup" class="delgroup">\r
-                                              <table id="chain_select_table"></table>\r
-                                        </div>                                                               \r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-                        </div>\r
-                         <div id="fw_type" class="node_type_group">\r
-                            <div class="big_second_title">\r
-                                <span>Property</span>\r
-                            </div>\r
-                            <table>\r
-                                <tr>\r
-                                    <td class="second_title">location:\r
-                                        <!--img class="alert_" id="firewall_loc_icon" src="src/app/nemo/images/alert.png" /--></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="fw_location" value=""/></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">operating-mode:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="fw_operating-mode" value=""/>\r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-                        </div>\r
-\r
-                        <div id="lb_type" class="node_type_group">\r
-                            <div class="big_second_title">\r
-                                <span>Property</span>\r
-                            </div>\r
-                            <table>\r
-                                <tr>\r
-                                    <td class="second_title">location:\r
-                                        <!--img class="alert_" id="Img1" src="#" /--></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="lb_location" value=""/></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">operating-mode:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="lb_operating-mode" value="" />\r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-                        </div>\r
-                         <div id="cache_type" class="node_type_group">\r
-                            <div class="big_second_title">\r
-                                <span>Property</span>\r
-                            </div>\r
-                            <table>\r
-                                <tr>\r
-                                    <td class="second_title">location:\r
-                                        <!--img class="alert_" id="Img1" src="#" /--></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="cache_location" value=""/></td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td class="second_title">operating-mode:</td>\r
-                                </tr>\r
-                                <tr>\r
-                                    <td>\r
-                                        <input type="text" class="txt" id="cache_operating-mode" value="" />\r
-                                    </td>\r
-                                </tr>\r
-                            </table>\r
-                        </div>\r
-\r
-                        <input type="button" name="name" class="btn_ NE_save net_entity_save" id="node_save" value="Save" />\r
-\r
-                    </div>\r
-\r
-                </div>\r
-\r
-                <div class="NE_conn_show  NE_connection_show NE_close_item">\r
-                    <img class="NE_close_show" src="src/app/nemo/images/shut.png" alt="close" />\r
-                    <table>\r
-                        <tr>\r
-                            <td><span class="second_title">connection ID:</span></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input class="id_ long" id="connection_id" type="text" name="name" value="" /></td>\r
-                        </tr>\r
-\r
-                        <tr>\r
-                            <td><span class="second_title">connection type:</span></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <select id="con_type">\r
-                                    <option value="p2p">p2p</option>\r
-                                    <option value="p2mp">p2mp</option>\r
-                                    <option value="mesh">mesh</option>\r
-                                    <!-- <option value="chain">chain</option> -->\r
-                                </select>\r
-                            </td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <span class="second_title">connection name:</span><img class="alert_" id="connection_icon" src="src/app/nemo/images/alert.png" />\r
-                            </td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input class="long" id="connection_name" type="text" name="name" value="" />\r
-                            </td>\r
-                        </tr>\r
-                    </table>\r
-\r
-                    <div id="p2p_type" class="conn_type_group">\r
-                        <div class="big_second_title">\r
-                            <span>End Point:</span>\r
-                        </div>\r
-                        <table class="conn_node_group">\r
-                            <tr>\r
-                                <td>\r
-                                <select id="p2p_select" class="txt3"> </select>\r
-                                <input class="btn_ add_node" id="p2p_select_ok" type="button" name="name" value="Add One">\r
-                                <input class="btn_ add_node" id="p2p_select_ok2" type="button" name="name" value="Add The Other">\r
-                                </td>\r
-                           </tr>\r
-                            <tr>\r
-                                <td>\r
-                                <div id="p2p_node_group">\r
-                                    <table >\r
-                                        <tr>\r
-                                            <td colspan="2"><span  class="second_title">One End Point:</span></td>\r
-                                        </tr>\r
-                                        <tr>\r
-                                            <td width="60px"></td><td></td>\r
-                                        </tr>\r
-                                        <tr>\r
-                                            <td colspan="2"><span class="second_title">Other End Point:</span></td>\r
-                                        </tr>\r
-                                        <tr>\r
-                                            <td></td><td></td>\r
-                                        </tr>\r
-                                    </table>\r
-                                </div>\r
-                                    </td>\r
-                            </tr>\r
-                            <!--<tr>\r
-                                <td><span class="second_title">一端点名称:</span>\r
-                                    <select class="sel_1" id="p2p_node-name1">\r
-                                    </select>\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td><span class="second_title">另一端点名称:</span>\r
-                                    <select id="p2p_node-name2"></select>\r
-                                </td>\r
-                            </tr>-->\r
-                        </table>\r
-                    </div>\r
-\r
-                    <div id="p2mp_type" class="conn_type_group ">\r
-                        <div class="big_second_title">\r
-                            <span>End Point Information</span>\r
-                        </div>\r
-                        <table class="conn_node_group_p2mp">\r
-                        <!--    <tr>\r
-                                <td><span class="second_title">一端点名称:</span>\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <select id="p2mp_node-name1">\r
-                                    </select>\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td><span class="second_title">另一端点名称:</span>\r
-                                    <div class="other_node_list" id="p2mp_node-name2">\r
-                                    </div>\r
-                                </td>\r
-                            </tr>-->\r
-                             <tr>\r
-                                <td>\r
-                                <select id="p2mp_select" class="txt3"> </select>\r
-                                <input class="btn_ add_node" id="p2mp_select_ok" type="button" name="name" value="Add One">\r
-                                <input class="btn_ add_node" id="p2mp_select_ok2" type="button" name="name" value="Add The Other">\r
-                                </td>\r
-                           </tr>\r
-                            <tr>\r
-                                <td>\r
-                                <div id="p2mp_node_group">\r
-                                    <table class="">\r
-                                        <tr>\r
-                                            <td colspan="2"><span  class="second_title">One End Point:</span></td>\r
-                                        </tr>\r
-                                        <tr>\r
-                                            <td width="60px"></td><td></td>\r
-                                        </tr>\r
-                                        <tr>\r
-                                            <td colspan="2"><span class="second_title">Other End Point:</span></td>\r
-                                        </tr>\r
-                                        <tr><td></td><td></td></tr>\r
-                                    </table>\r
-                                </div>\r
-                                    </td>\r
-                            </tr>\r
-                        </table>\r
-                    </div>\r
-                    <div id="mesh_type" class="conn_type_group">\r
-                         <div class="big_second_title">\r
-                            <span>End Point Information</span>\r
-                        </div>\r
-                        <table class="conn_node_group_mesh">\r
-                             <tr>\r
-                                <td>\r
-                                <select id="mesh_select" class="txt2"> </select>\r
-                                <input class="btn_ add_node" id="mesh_select_ok" type="button" name="name" value="Add">                             \r
-                                </td>\r
-                           </tr>\r
-                            <tr>\r
-                                <td>\r
-                                <div id="mesh_node_group">\r
-                                    <table class="">\r
-                                        <tr>\r
-                                            <td><span  class="second_title">End Point:</span></td><td></td>\r
-                                        </tr>\r
-                                        <tr>\r
-                                            <td></td><td></td>\r
-                                        </tr>\r
-                                    </table>\r
-                                </div>\r
-                                    </td>\r
-                            </tr>\r
-                        </table>\r
-                    </div>\r
-                     <div id="chain_type" class="conn_type_group">\r
-                        <div class="big_second_title">\r
-                            <span>业务链结点</span>\r
-                        </div>\r
-                        <table class="conn_node_group_chain">\r
-                             <tr>\r
-                                <td>\r
-                                <select id="chain_select" class="txt2"> </select>\r
-                                <input class="btn_ add_node" id="chain_select_ok" type="button" name="name" value="添加">                             \r
-                                </td>\r
-                           </tr>\r
-                            <tr>\r
-                                <td>\r
-                                <div id="chain_node_group">\r
-                                    <table class="">\r
-                                        <tr>\r
-                                            <td><span  class="second_title">端点名称:</span></td> <td></td>\r
-                                        </tr>\r
-                                        <tr>\r
-                                            <td></td> <td></td>\r
-                                        </tr>\r
-                                    </table>\r
-                                </div>\r
-                                    </td>\r
-                            </tr>\r
-                        </table>\r
-                    </div>\r
-                    <div class="property_type">\r
-                        <div class="big_second_title">\r
-                            <span>Property</span>\r
-                        </div>\r
-                        <table>\r
-                              \r
-                            <tr>\r
-                                <td><span class="second_title">bandwidth:</span><!--img class="alert_" id="bandwidth_icon" src="#" /--></td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <input id="bandwidth" class="txt" type="text" name="name" value="kb" /><span>kbps</span>\r
-                                </td>\r
-                            </tr>\r
-                            <tr style="display: none">\r
-                                <td><span class="second_title">时延</span></td>\r
-                            </tr>\r
-                            <tr style="display: none">\r
-                                <td>\r
-                                    <input id="latency" class="txt" type="text" name="name" value="" />\r
-                                </td>\r
-                            </tr>\r
-                            <tr style="display: none">\r
-                                <td><span class="second_title">抖动</span></td>\r
-                            </tr>\r
-                            <tr style="display: none">\r
-                                <td>\r
-                                    <input id="Jitter" class="txt" type="text" name="name" value="" />\r
-                                </td>\r
-                            </tr>\r
-                        </table>\r
-                    </div>\r
-\r
-                    <input type="button" name="name" id="connection_save" class="btn_ NE_con_save net_entity_save" value="Save" />\r
-                </div>\r
-\r
-                <div class="NE_flow_show NE_close_item">\r
-                    <img class="NE_close_show" id="NE_flow_close_icon" src="src/app/nemo/images/shut.png" alt="close" />\r
-                    <table>\r
-                        <tr>\r
-                            <td><span class="second_title">flow ID:</span></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="flow_id" type="text" class="id_ long" name="name" value="" /></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td><span class="second_title">flow name:</span><img class="alert_" id="flow_icon" src="src/app/nemo/images/alert.png" /></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="flow_name" class="long" type="text" name="name" value="" /></td>\r
-                        </tr>\r
-                    </table>\r
-                    <div class="big_second_title">\r
-                        <span>Flow match item</span>\r
-                    </div>\r
-                    <table>\r
-                        <tr>\r
-                            <td><span class="second_title">eth-type:</span></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input type="text" class="long" id="eth_type"/>\r
-                            </td>\r
-                        </tr>\r
-\r
-                        <tr>\r
-                            <td><span class="second_title">src-mac:</span></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                 <input type="text" class="long" id="src_mac"/>\r
-                            </td>\r
-                        </tr>\r
-\r
-                        <tr>\r
-                            <td><span class="second_title">dst-mac:</span><!--img class="alert_" id="src_ip_icon" src="#" /--></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="dst_mac" class="long" type="text"  value="" />\r
-                            </td>\r
-                        </tr>\r
-\r
-                         <tr>\r
-                            <td><span class="second_title">proto:</span><!--img class="alert_" id="protocol_icon" src="#" /--></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="protocol" class="long" type="text" name="name" value=" " />\r
-                            </td>\r
-                        </tr>\r
-\r
-                        <tr>\r
-                            <td><span class="second_title">src-ip:</span><!--img class="alert_" id="dest_ip_icon" src="#" /--></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="src_ip" class="long" type="text" name="name" value="" />\r
-                            </td>\r
-                        </tr>\r
-\r
-                        <tr>\r
-                            <td><span class="second_title">dst-ip:</span><!--img class="alert_" id="dest_ip_icon" src="#" /--></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="dst_ip" class="long" type="text" name="name" value=" " />\r
-                            </td>\r
-                        </tr>\r
-\r
-                        <tr>\r
-                            <td><span class="second_title">src-port:</span><!--img class="alert_" id="src_port_icon" src="#" /--></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="src_port" class="long" type="text" name="name" value=" " />\r
-                            </td>\r
-                        </tr>\r
-\r
-                        <tr>\r
-                            <td><span class="second_title">dst-port:</span><!--img class="alert_" id="dest_port_icon" src="#" /--></td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td>\r
-                                <input id="dst_port" class="long" type="text" name="name" value=" " />\r
-                            </td>\r
-                        </tr>\r
-                                          \r
-                    </table>\r
-                    <input type="button" name="name" id="flow_save" class="btn_ NE_flow_save net_entity_save" value="Save" />\r
-                </div>\r
-\r
-            </div>\r
-\r
-            <div class="btn_item_show">\r
-\r
-                <div class="close_item_show">\r
-                    <img src="src/app/nemo/images/shut.png" />\r
-                </div>\r
-\r
-                <div class="SP_up">\r
-                    <div class="h3_style">\r
-                        <h3>Service Policy</h3>\r
-                    </div>\r
-                    <span class="second_title OP_serviceName">Service Name:</span>\r
-                    <select class="select_item"></select>\r
-                    <span class="second_title">Operation Entity List:</span>\r
-                    <select id="policy_name_list"></select>\r
-                    <div class="SP_btn_group">\r
-                        <input id="policy_add" class="btn_" type="button" name="name" value="Add" />\r
-                        <input id="policy_edit" class="btn_" type="button" name="name" value="Edit" />\r
-                        <input id="policy_delete" class="btn_" type="button" name="name" value="Delete" />\r
-                    </div>\r
-                </div>\r
-\r
-\r
-\r
-                <div class="SP_add_show">\r
-                    <img id="SP_close_show" src="src/app/nemo/images/shut.png" />\r
-                    <div class="SP_down">\r
-                        <table>\r
-                            <tr>\r
-                                <td><span s class="second_title">Operation ID:</span></td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <input class="id_" id="policy_id" type="text" name="name" value="" />\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td><span class="second_title">Operation name:</span><img class="alert_" id="policy_name_icon" src="src/app/nemo/images/alert.png" /></td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <input id="policy_name" class="cle" type="text" name="name" value="" />\r
-                                </td>\r
-                            </tr>\r
-                              <tr>\r
-                                <td><span class="second_title">Priority:</span><!--img class="alert_" id="policy_priority_icon" src="src/app/nemo/images/alert.png" /--></td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <input id="policy_priority" class="cle" type="text" name="name" value="0" />\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <span class="second_title">Action to Entity:</span>\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <select id="apply_entity">\r
-                                    </select>\r
-                                </td>\r
-                            </tr>\r
-                        </table>\r
-                        <div class="big_second_title">\r
-                            <span>Condition:</span>\r
-                        </div>\r
-                        <table>\r
-                            <tr>\r
-                                <td>\r
-                                    <!--div class="Con_group">\r
-                                        <span class="second_title">开始时间:</span><img class="alert_" id="start_time_icon" src="src/app/nemo/images/alert.png"/>\r
-                                        <input id="StartTime" class="cle" type="time" name="name" value="" />\r
-                                        <span class="second_title">结束时间:</span><img class="alert_" id="end_time_icon" src="src/app/nemo/images/alert.png"/>\r
-                                        <input id="EndTime" class="cle" type="time" name="name" value="" />\r
-                                    </div-->\r
-                                    <select class="con_show">\r
-                                        <option value="time">time</option>\r
-                                   </select>\r
-                                    <select class="con_show" >\r
-                                        <option value="less-than">less-than</option>\r
-                                        <option value="not-less-than">not-less-than</option>\r
-                                        <option value="equal">equal</option>\r
-                                        <option value="not-equal">not-equal</option>\r
-                                        <option value="greater-than">greater-than</option>\r
-                                        <option value="not-greater-than">not-greater-than</option>\r
-                                        <option value="between">between</option>\r
-                                        <option value="preiodical">preiodical</option>\r
-                                   </select>\r
-                                    <input class="con_show" type="text" name="name" value=" " />\r
-                                    <!--<input type="button" class="btn_ con_show" name="name" value=" 确定" />-->\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <span>relationship with prior:</span>\r
-                                    <select class="ext_con_1">\r
-                                        <option value="none">none</option>\r
-                                         <option value="and">and</option>\r
-                                         <option value="or">or</option>\r
-                                         <option value="not">not</option>\r
-                                    </select>\r
-                                    <!--<input type="button" class="btn_ ext_con_2" name="name" value=" 确定" />-->\r
-                                    </td></tr>\r
-                            <tr>\r
-                                <td>\r
-                                    <span>condition priority:</span>\r
-                                    <input class="ext_con_3" type="text" name="name" value="1" />\r
-                                    <!--<input type="button" class="btn_ ext_con_4" name="name" value=" 确定" />-->\r
-                                     <input type="button" class="btn_ con_button" name="name" value="confirm" />\r
-                                </td>\r
-                            </tr>\r
-                            <tr>\r
-                                <td>\r
-                                    Selected conditions:\r
-                                    <input type="button" name="name" class="btn_" id="con_clear" value="clear" />\r
-                                </td>  \r
-                            </tr>\r
-                             <tr>\r
-                                <td>\r
-                                    <div id="con_select"> </div>\r
-                                </td>  \r
-                            </tr>\r
-                        </table>\r
-                        <div class="big_second_title">\r
-                            <span>Action:</span>\r
-                        </div>\r
-                        <table>\r
-                            <tr>\r
-                                <td>\r
-                                    <select id="policy_action">\r
-                                        <option value="Deny">Deny</option>\r
-                                        <option value="Allow">Allow</option>\r
-                                        <option value="go-through">go-through</option>\r
-                                        <option value="qos-bandwidth">qos-bandwidth</option>\r
-                                    </select>\r
-                                </td>\r
-                            </tr>\r
-                        </table>\r
-                        <div class="big_second_title">\r
-                            <span>Constrain</span>\r
-                        </div>\r
-                        <table>\r
-                            <tr>\r
-                                <td>\r
-                                    <span class="third_title">&nbsp;Exclusive Node List:</span>\r
-\r
-                                    <div class="list_nodes">\r
-                                    </div>\r
-                                </td>\r
-                            </tr>\r
-                        </table>\r
-                        <div class="big_second_title">\r
-                            <span>Data:</span>\r
-                        </div>\r
-                        <table>\r
-                            <tr>\r
-                                <td>\r
-                                    <select id="policy_data">\r
-                                        \r
-                                    </select>\r
-                                    <!--input class="btn_ btn_edit" type="button" name="name" value="编 辑" /-->\r
-                                </td>\r
-                            </tr>\r
-                        </table>\r
-                    </div>\r
-\r
-                    <div class="SP_btn_save">\r
-                        <input class="btn_" id="sp_save" type="button" name="name" value="Save" />\r
-                    </div>\r
-                </div>\r
-            </div>\r
-\r
-\r
-            <div class="btn_item_show">\r
-                <div class="close_item_show">\r
-                    <img src="src/app/nemo/images/shut.png" />\r
-                </div>\r
-                <div class="AQ_up">\r
-                    <div class="h3_style">\r
-                        <h3>Advance Query</h3>\r
-                    </div>\r
-                </div>\r
-            </div>\r
-\r
-            <div class="btn_item_show">\r
-                <div class="close_item_show">\r
-                    <img src="src/app/nemo/images/shut.png" />\r
-                    <!--<div class="RR_top">\r
-                        <input type="file" name="fileField" class="file" id="json_select" size="28" onchange="document.getElementById('textfield').value=this.value" />\r
-                        <input type='text' name='textfield' id='textfield' class='txt' />\r
-                        <input type='button' class='btn_' value='选择文件' />\r
-                        <input type="button" name="submit" class="btn_" id="display_info" value="展示命令" />\r
-                    </div>-->\r
-                    <!--<div id="order"></div>-->\r
-\r
-                    <div class="RR_up">\r
-                    <div class="h3_style">\r
-                        <h3>Resource Mapping Info</h3>\r
-                     </div>\r
-                        <div class="que_group">\r
-                            <span></span>\r
-                            <input type="button" class="btn_" id="query_topo" value="Query Physical Topo" />\r
-                        </div>\r
-                   </div>\r
-\r
-                </div>\r
-            </div>\r
-\r
-            <div id="btn_local">\r
-                <input id="submit" class="btn_ btn_submit" type="button" value="Submit" /></div>\r
-        </div>\r
-\r
-        <div class="group_right">\r
-            <div class="up">\r
-                <div class="title">\r
-                    <h2>Service View</h2>\r
-                    <div id="right_top">\r
-                    <span>Username:</span>\r
-                    <input type="text" id="getUserName">\r
-                <input id="refresh" class='btn_' type="button" value="Refresh" onclick="analyjson_topo()">\r
-                    </div>\r
-                    <svg id="service_svg"  width="800" height="560"  viewBox="100 40 900 780" style='display:none'>\r
-                    <defs>\r
-                    <marker id="idArrow" viewBox="0 0 20 20" refX="0" refY="10" markerUnits="strokeWidth" markerWidth="6" markerHeight="15" orient="auto"><path d="M 0 0 L 20 10 L0 20 z"fill="purple"stroke="black"/> </marker>\r
-                    <marker id="idtext" viewBox="0 0 120 50" refX="0" refY="0" markerUnits="strokeWidth" markerWidth="20" markerHeight="20"  orient="auto"><text style="font-family:sans-serif; font-size:14pt;"  x="20" y="20">text</text></marker>  \r
-                    </defs>\r
-                    </svg>\r
-\r
-                    <svg id="service_svg2"  width="800" height="560"  viewBox="100 40 900 780">\r
-                    <defs>\r
-                    <marker id="idArrow2" viewBox="0 0 20 20" refX="0" refY="10" markerUnits="strokeWidth" markerWidth="6" markerHeight="15" orient="auto"><path d="M 0 0 L 20 10 L0 20 z"fill="purple"stroke="black"/> </marker>\r
-                    <marker id="idtext2" viewBox="0 0 120 50" refX="0" refY="0" markerUnits="strokeWidth" markerWidth="20" markerHeight="20"  orient="auto"><text style="font-family:sans-serif; font-size:14pt;"  x="20" y="20">text</text></marker>  \r
-                    </defs>\r
-                    </svg>\r
-                    <div id="graph"></div>\r
-                </div>\r
-\r
-            </div>\r
-\r
-            <div class="down">\r
-                <div id="tabs">\r
-                    <ul>\r
-                        <li><a href="#nemo_str_show">Service Modeling Language Description</a></li>\r
-                        <li><a href="#trans_info">History Infomation</a></li>\r
-                    </ul>\r
-    \r
-                    <div id="nemo_str_show"></div>\r
-                    <div id="trans_info"></div>\r
-                </div>\r
-            </div>\r
-\r
-        </div>\r
-\r
-        <!-- dialog start -->\r
-        <div id="dialog" title="warning">\r
-            <p>\r
-                The service name is already existing,please input another name!\r
-            </p>\r
-        </div>\r
-        <div id="policy_dialog" title="warning">\r
-            <p>\r
-                The policy name is already existing,please input another name!\r
-            </p>\r
-        </div>\r
-        <div id="flow_dialog" title="warning">\r
-            <p>\r
-                'src_ip','dest_ip','src_port','dest_port','protocol','vlanid'这些选项不能为空\r
-            </p>\r
-        </div>\r
-        <div id="del_ser_dialog" title="warning">\r
-            <p>\r
-                The entities and policies that belong to this service will also be deleted,are you sure to continue?\r
-            </p>\r
-        </div>\r
-\r
-        <div id="ser_dialoge" title="warning">\r
-            <p>\r
-                 The service name is null,please input a name!\r
-            </p>\r
-        </div>\r
-        <div id="ety_dialog" title="warning">\r
-            <p>\r
-                The entity instance name is already existing,please input another name!\r
-            </p>\r
-        </div>\r
-\r
-        <div id="adc_dialog" title="">\r
-            <h3>业 务 链 配 置</h3>\r
-            <p>结点实体列表:</p>\r
-            <select id="adc_node"></select>\r
-            <input id="add_node" class="btn_" type="button" name="name" value="添 加" />\r
-            <span>序号</span>\r
-            <select id="num">\r
-            </select>\r
-            <input id="delete_node" class="btn_" type="button" name="name" value="删 除" />\r
-            <div id="table_show">\r
-                <table id="table_tab" style="border: 2px">\r
-                    <tr>\r
-                        <th class="first_colum">序号</th>\r
-                        <th>结点ID</th>\r
-                    </tr>\r
-                    <tr>\r
-                        <td class="first_colum"></td>\r
-                        <td></td>\r
-                    </tr>\r
-                </table>\r
-            </div>\r
-        </div>\r
-\r
-        <!-- dialog end -->\r
-\r
-        <!-- show_trans_status start-->\r
-        <div id='show_status' style="background: rgba(80,80,80,0.3); width: 220px; height: 50px; z-index: 999; position: absolute; top: 15px; right: 0; margin-top: 10px;">\r
-            <p style="font-size:15px">Transaction is running...</p>\r
-            <div id='loader' style='z-index: 999; margin-left: 100px;margin-top:10px'>\r
-            </div>\r
-        </div>\r
-        <!-- show_trans_status end-->\r
-    </div>\r
-</body>\r
-</html>\r
diff --git a/nemo-ui/src/main/resources/nemo/register.html b/nemo-ui/src/main/resources/nemo/register.html
deleted file mode 100644 (file)
index 2ab17b6..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-<!DOCTYPE html>\r
-<html lang="en">\r
-<head>\r
-       <meta charset="UTF-8">\r
-       <title>nemo-register</title>\r
-       <link rel="stylesheet" href="src/app/nemo/css/register.css">\r
-        <script src="js/jquery-1.7.1.min.js"></script>\r
-       <script>\r
-       var hostname = document.location.hostname;\r
-        //var log_info=false;\r
-       function guid() {\r
-        function S4() {\r
-            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\r
-        }\r
-        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());\r
-        }\r
-         \r
-     jQuery(document).ready(function ($) {\r
-           \r
-         //var user_info=localStorage.getItem("useinfo");\r
-         //if(log_info){$("#pageContent").load('src/app/nemo/nemo.tpl.html');}\r
-        var use_name, use_pwd, user_role;\r
-        var userInfoStorage={};\r
-        if(localStorage.getItem("AllRegUserInfo") !==null)\r
-        userInfoStorage  = JSON.parse(localStorage.getItem("AllRegUserInfo")) ;\r
-        else\r
-        userInfoStorage.info=[];\r
-\r
-      function getUserId(username,userpwd){\r
-       var userid = null;\r
-        var users = localStorage.getItem("AllRegUserInfo");//localstorage data\r
-               if(users !=null && typeof(users)!="undefined")\r
-               {\r
-                var user_json= JSON.parse(users);\r
-                for(var i = 0;i<user_json.info.length;i++){\r
-                       if(username == user_json.info[i]["userName"] && userpwd==user_json.info[i]["userPassword"]){\r
-                               userid = user_json.info[i]["id"];\r
-                       }\r
-               }\r
-           }\r
-           return userid;\r
-      }\r
-//getUserId();\r
-      function getUserInfo(){\r
-       var user_data;\r
-       $.ajax({ \r
-                           url: "/restconf/config/nemo-intent:users/", \r
-                               type:"GET",\r
-                               async: false,\r
-                               dataType:"json",\r
-                               success: function(data){\r
-                                       console.log(data);      \r
-                               user_data= JSON.stringify(data);\r
-                               // user_id = data["users"]["user"][0]["user-id"];\r
-                               // use_name = data["users"]["user"][0]["user-name"];\r
-                               // use_pwd = data["users"]["user"][0]["user-password"];\r
-                               // user_role = data["users"]["user"][0]["user-role"];\r
-                               // var reg_info = user_id + "," + use_name + "," + use_pwd + "," + user_role;\r
-                               // localStorage.setItem("useinfo", reg_info);\r
-                               },\r
-                               error:function(data){\r
-                                       console.log(data);\r
-                               }\r
-                       });\r
-      }\r
-     \r
-           $("#log_ok").click(function () {\r
-               //validate all use\r
-               var userName = $("#usename").val().trim();\r
-               var userPassword = $("#usepwd").val().trim();\r
-               if (userName == "" || userPassword == "") {\r
-                   alert("User name or Password can not be empty!");\r
-                   return;\r
-               }\r
-\r
-               //var getData =JSON.parse(getUserInfo());//ajax save data\r
-\r
-               var users = localStorage.getItem("AllRegUserInfo");//localstorage data\r
-               console.log(users);\r
-               var cnt=0;\r
-               if(users !=null && typeof(users)!="undefined")\r
-               {\r
-               var user_json= JSON.parse(users);\r
-               for(var i = 0;i<user_json.info.length;i++){\r
-                       if(userName == user_json.info[i]["userName"] && userPassword==user_json.info[i]["userPassword"]){\r
-                               var user_str=user_json.info[i]["id"]+","+user_json.info[i]["userName"]+","+user_json.info[i]["userPassword"]+","+user_json.info[i]["userRole"];\r
-                               localStorage.setItem("useinfo",user_str);\r
-                               //alert("chenggong");\r
-                               $("#pageContent").empty();\r
-                    $("#pageContent").load('src/app/nemo/nemo.tpl.html');\r
-                    break;\r
-                       }\r
-                       cnt++;\r
-               }\r
-           }\r
-\r
-           if(cnt>=user_json.info.length){\r
-               alert("Login failed!Please register first and login again!");\r
-           }\r
-\r
-                //alert("User name or password error!");\r
-\r
-               // if ($("#usename").val().trim() == "" || $("#usepwd").val().trim() == "") {\r
-               //     alert("User name or Password can not be empty!");\r
-               // }\r
-               // else if ($("#usename").val().trim() != use_name || $("#usepwd").val().trim() != use_pwd) {\r
-               //     alert("User name or password error!");\r
-               // }\r
-               // else {\r
-               //     //self.location = 'src/app/nemo/nemo.tpl.html';\r
-         //            $("#pageContent").empty();\r
-         //            $("#pageContent").load('src/app/nemo/nemo.tpl.html');\r
-               // }    \r
-           });\r
-\r
-           $("#show_reg a").click(function (event) {\r
-               $("input[type=password]").val("");\r
-               event.preventDefault();\r
-               $("#log").hide();\r
-               $("#reg").show();\r
-           });\r
-\r
-   $("#reg_ok").click(function () {\r
-   \r
-       if ($("#reg_usename").val().trim() == "" || $("#reg_usepwd").val().trim() == "" || $("#reg_usepwd2").val().trim() == "")\r
-       {\r
-           alert("Please enter complete information and then click OK.");\r
-       }\r
-       else if ($("#reg_usepwd").val().trim() != $("#reg_usepwd2").val().trim())\r
-       {\r
-           alert("Two password input is not consistent!");\r
-       }\r
-       else\r
-       {\r
-           //ajax注册信息\r
-           var cur_user={};\r
-           var exitsUserId = getUserId($("#reg_usename").val().trim(),$("#reg_usepwd").val().trim());\r
-            var id_ = guid();\r
-            var exitsUser = false;\r
-\r
-           console.log(exitsUserId);\r
-\r
-           if(exitsUserId!=null){\r
-               id_ =exitsUserId;\r
-               exitsUser = true;\r
-           }\r
-          \r
-           use_name = $("#reg_usename").val().trim();\r
-           use_pwd = $("#reg_usepwd").val().trim();\r
-           user_role = $("#user_role").children("option:selected").val();\r
-           cur_user.id=id_;\r
-           cur_user.userName=use_name;\r
-           cur_user.userPassword=use_pwd;\r
-           cur_user.userRole=user_role;\r
-           var reg_str = id_ + "," + use_name + "," + use_pwd + "," + user_role;\r
-                  var user_json = '{"input":{"user-id":"'+id_+'","user-name":"'+use_name+'","user-password":"'+use_pwd+'","user-role":"'+user_role+'"}}';\r
-                   console.log("user_json:"+user_json);\r
-\r
-                   //var user_json2 = {"input":{"user-id":id_,"user-name":use_name,"user-password":use_pwd,"user-role":user_role}};\r
-                   // console.log(user_json2);\r
-                    //user_data = JSON.parse(user_json);\r
-                       \r
-                       $.ajax({\r
-                               url: "/restconf/operations/nemo-intent:register-user", \r
-                               type:"POST",\r
-                               //data:JSON.stringify(user_json2),\r
-                data:user_json,\r
-                               dataType:"json",\r
-                               contentType:"application/json",\r
-                               success: function(data){\r
-                                       console.log(data);\r
-                                       if(data["output"]["result-code"] == "ok")\r
-                                       {\r
-                                               if(exitsUser == false){\r
-                                               userInfoStorage.info.push(cur_user);\r
-                                               localStorage.setItem("AllRegUserInfo",JSON.stringify(userInfoStorage));\r
-                                           }\r
-                                               \r
-                                               localStorage.setItem("useinfo", reg_str);\r
-                                                \r
-                                               //alert("user "+use_name+" registered success!Please login!");\r
-                                               $("#log").show();\r
-                                               $("#reg").hide();\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               alert("user "+use_name+" registered fail!");\r
-                                       }\r
-                               },\r
-                               error:function(data){\r
-                     console.log(data);\r
-                                       alert("register fail!");\r
-                               },\r
-                       \r
-                       });\r
-\r
-       }\r
-       });\r
-      \r
-       });\r
-\r
-\r
-    </script>\r
-</head>\r
-<body>\r
-       <div id="logPage">\r
-   <div id="log">\r
-     <div id="log_title"><p>User Login</p></div>\r
-     <div id="log_info">\r
-               <table border="0" >\r
-                       <tr > \r
-                               <td width="90px">username:</td> \r
-                               <td > <input id="usename" type="text"></td>\r
-                       </tr>\r
-                       <tr> \r
-                               <td >password:</td> \r
-                               <td ><input id="usepwd" type="password"></td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td  colspan="2" align="center" ><button id="log_ok">ok</button> <button id="reg_cancle">cancle</button></td>                   \r
-                       </tr>\r
-                       <tr id="show_reg"> \r
-                               <td colspan="2">\r
-                                       <a href="#"><span>User Registration</span></a>\r
-                               </td>\r
-                       </tr>\r
-                       \r
-               </table>\r
-               </div>\r
-       </div>\r
-   \r
-\r
-       <div id="reg">\r
-     <div id="reg_title"><p>User Registration</p></div>\r
-     <div id="reg_info">\r
-               <table  border="0" cellspacing="1" cellpadding="0" bgcolor="">\r
-                       <tr > \r
-                               <td width="90px">username:</td> \r
-                               <td > <input id="reg_usename" type="text"></td>\r
-                       </tr>\r
-                       <tr> \r
-                               <td >password:</td> \r
-                               <td ><input id="reg_usepwd" type="password"></td>\r
-                       </tr>\r
-                       <tr> \r
-                               <td >confirm password:</td> \r
-                               <td ><input  id="reg_usepwd2" type="password"></td>\r
-                       </tr>\r
-                       <tr> \r
-                               <td >user role:</td> \r
-                               <td >\r
-                                       <select name="" id="user_role">\r
-                                               <option value="tenant">tenant</option>\r
-                                               <option value="admin">admin</option>\r
-                                       </select>\r
-                               </td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td  colspan="2" align="center"><button id="reg_ok">ok</button> <button id="reg_cancle">cancle</button></td>\r
-                               \r
-                       </tr>\r
-               </table>\r
-               </div>\r
-       </div>\r
-       </div>\r
-</body>\r
-</html>\r