You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cmda.apache.org by xi...@apache.org on 2015/10/29 23:45:56 UTC

[1/5] incubator-cmda git commit: Add KnowledgeGraph page and recommendationSummary page. Update backend models and create new APIs to support new features. Add KnowledgCard in Dataset search result page.

Repository: incubator-cmda
Updated Branches:
  refs/heads/master a9a836758 -> aa50efa2b


http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/stylesheets/vis.css
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/stylesheets/vis.css b/ApacheCMDA_Frontend_1.0/public/stylesheets/vis.css
new file mode 100644
index 0000000..23cd790
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/stylesheets/vis.css
@@ -0,0 +1,1295 @@
+.vis .overlay {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+
+  /* Must be displayed above for example selected Timeline items */
+  z-index: 10;
+}
+
+.vis-active {
+  box-shadow: 0 0 10px #86d5f8;
+}
+
+/* override some bootstrap styles screwing up the timelines css */
+
+.vis [class*="span"] {
+  min-height: 0;
+  width: auto;
+}
+
+div.vis-configuration {
+    position:relative;
+    display:block;
+    float:left;
+    font-size:12px;
+}
+
+div.vis-configuration-wrapper {
+    display:block;
+    width:700px;
+}
+
+
+div.vis-configuration.vis-config-option-container{
+    display:block;
+    width:495px;
+    background-color: #ffffff;
+    border:2px solid #f7f8fa;
+    border-radius:4px;
+    margin-top:20px;
+    left:10px;
+    padding-left:5px;
+}
+
+div.vis-configuration.vis-config-button{
+    display:block;
+    width:495px;
+    height:25px;
+    vertical-align: middle;
+    line-height:25px;
+    background-color: #f7f8fa;
+    border:2px solid #ceced0;
+    border-radius:4px;
+    margin-top:20px;
+    left:10px;
+    padding-left:5px;
+    cursor: pointer;
+    margin-bottom:30px;
+}
+
+div.vis-configuration.vis-config-button.hover{
+    background-color: #4588e6;
+    border:2px solid #214373;
+    color:#ffffff;
+}
+
+div.vis-configuration.vis-config-item{
+    display:block;
+    float:left;
+    width:495px;
+    height:25px;
+    vertical-align: middle;
+    line-height:25px;
+}
+
+
+div.vis-configuration.vis-config-item.vis-config-s2{
+    left:10px;
+    background-color: #f7f8fa;
+    padding-left:5px;
+    border-radius:3px;
+}
+div.vis-configuration.vis-config-item.vis-config-s3{
+    left:20px;
+    background-color: #e4e9f0;
+    padding-left:5px;
+    border-radius:3px;
+}
+div.vis-configuration.vis-config-item.vis-config-s4{
+    left:30px;
+    background-color: #cfd8e6;
+    padding-left:5px;
+    border-radius:3px;
+}
+
+div.vis-configuration.vis-config-header{
+    font-size:18px;
+    font-weight: bold;
+}
+
+div.vis-configuration.vis-config-label{
+    width:120px;
+    height:25px;
+    line-height: 25px;
+}
+
+div.vis-configuration.vis-config-label.vis-config-s3{
+    width:110px;
+}
+div.vis-configuration.vis-config-label.vis-config-s4{
+    width:100px;
+}
+
+div.vis-configuration.vis-config-colorBlock{
+    top:1px;
+    width:30px;
+    height:19px;
+    border:1px solid #444444;
+    border-radius:2px;
+    padding:0px;
+    margin:0px;
+    cursor:pointer;
+}
+
+input.vis-configuration.vis-config-checkbox {
+    left:-5px;
+}
+
+
+input.vis-configuration.vis-config-rangeinput{
+    position:relative;
+    top:-5px;
+    width:60px;
+    height:13px;
+    padding:1px;
+    margin:0;
+    pointer-events:none;
+}
+
+input.vis-configuration.vis-config-range{
+    /*removes default webkit styles*/
+    -webkit-appearance: none;
+
+    /*fix for FF unable to apply focus style bug */
+    border: 0px solid white;
+    background-color:rgba(0,0,0,0);
+
+    /*required for proper track sizing in FF*/
+    width: 300px;
+    height:20px;
+}
+input.vis-configuration.vis-config-range::-webkit-slider-runnable-track {
+    width: 300px;
+    height: 5px;
+    background: #dedede; /* Old browsers */
+    background: -moz-linear-gradient(top,  #dedede 0%, #c8c8c8 99%); /* FF3.6+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#dedede), color-stop(99%,#c8c8c8)); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top,  #dedede 0%,#c8c8c8 99%); /* Chrome10+,Safari5.1+ */
+    background: -o-linear-gradient(top, #dedede 0%, #c8c8c8 99%); /* Opera 11.10+ */
+    background: -ms-linear-gradient(top,  #dedede 0%,#c8c8c8 99%); /* IE10+ */
+    background: linear-gradient(to bottom,  #dedede 0%,#c8c8c8 99%); /* W3C */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8',GradientType=0 ); /* IE6-9 */
+
+    border: 1px solid #999999;
+    box-shadow: #aaaaaa 0px 0px 3px 0px;
+    border-radius: 3px;
+}
+input.vis-configuration.vis-config-range::-webkit-slider-thumb {
+    -webkit-appearance: none;
+    border: 1px solid #14334b;
+    height: 17px;
+    width: 17px;
+    border-radius: 50%;
+    background: #3876c2; /* Old browsers */
+    background: -moz-linear-gradient(top,  #3876c2 0%, #385380 100%); /* FF3.6+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#3876c2), color-stop(100%,#385380)); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top,  #3876c2 0%,#385380 100%); /* Chrome10+,Safari5.1+ */
+    background: -o-linear-gradient(top,  #3876c2 0%,#385380 100%); /* Opera 11.10+ */
+    background: -ms-linear-gradient(top,  #3876c2 0%,#385380 100%); /* IE10+ */
+    background: linear-gradient(to bottom,  #3876c2 0%,#385380 100%); /* W3C */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3876c2', endColorstr='#385380',GradientType=0 ); /* IE6-9 */
+    box-shadow: #111927 0px 0px 1px 0px;
+    margin-top: -7px;
+}
+input.vis-configuration.vis-config-range:focus {
+    outline: none;
+}
+input.vis-configuration.vis-config-range:focus::-webkit-slider-runnable-track {
+    background: #9d9d9d; /* Old browsers */
+    background: -moz-linear-gradient(top, #9d9d9d 0%, #c8c8c8 99%); /* FF3.6+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#9d9d9d), color-stop(99%,#c8c8c8)); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top,  #9d9d9d 0%,#c8c8c8 99%); /* Chrome10+,Safari5.1+ */
+    background: -o-linear-gradient(top,  #9d9d9d 0%,#c8c8c8 99%); /* Opera 11.10+ */
+    background: -ms-linear-gradient(top,  #9d9d9d 0%,#c8c8c8 99%); /* IE10+ */
+    background: linear-gradient(to bottom,  #9d9d9d 0%,#c8c8c8 99%); /* W3C */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#9d9d9d', endColorstr='#c8c8c8',GradientType=0 ); /* IE6-9 */
+}
+
+input.vis-configuration.vis-config-range::-moz-range-track {
+    width: 300px;
+    height: 10px;
+    background: #dedede; /* Old browsers */
+    background: -moz-linear-gradient(top,  #dedede 0%, #c8c8c8 99%); /* FF3.6+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#dedede), color-stop(99%,#c8c8c8)); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top,  #dedede 0%,#c8c8c8 99%); /* Chrome10+,Safari5.1+ */
+    background: -o-linear-gradient(top, #dedede 0%, #c8c8c8 99%); /* Opera 11.10+ */
+    background: -ms-linear-gradient(top,  #dedede 0%,#c8c8c8 99%); /* IE10+ */
+    background: linear-gradient(to bottom,  #dedede 0%,#c8c8c8 99%); /* W3C */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#dedede', endColorstr='#c8c8c8',GradientType=0 ); /* IE6-9 */
+
+    border: 1px solid #999999;
+    box-shadow: #aaaaaa 0px 0px 3px 0px;
+    border-radius: 3px;
+}
+input.vis-configuration.vis-config-range::-moz-range-thumb {
+    border: none;
+    height: 16px;
+    width: 16px;
+
+    border-radius: 50%;
+    background:  #385380;
+}
+
+/*hide the outline behind the border*/
+input.vis-configuration.vis-config-range:-moz-focusring{
+    outline: 1px solid white;
+    outline-offset: -1px;
+}
+
+input.vis-configuration.vis-config-range::-ms-track {
+    width: 300px;
+    height: 5px;
+
+    /*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
+    background: transparent;
+
+    /*leave room for the larger thumb to overflow with a transparent border */
+    border-color: transparent;
+    border-width: 6px 0;
+
+    /*remove default tick marks*/
+    color: transparent;
+}
+input.vis-configuration.vis-config-range::-ms-fill-lower {
+    background: #777;
+    border-radius: 10px;
+}
+input.vis-configuration.vis-config-range::-ms-fill-upper {
+    background: #ddd;
+    border-radius: 10px;
+}
+input.vis-configuration.vis-config-range::-ms-thumb {
+    border: none;
+    height: 16px;
+    width: 16px;
+    border-radius: 50%;
+    background:  #385380;
+}
+input.vis-configuration.vis-config-range:focus::-ms-fill-lower {
+    background: #888;
+}
+input.vis-configuration.vis-config-range:focus::-ms-fill-upper {
+    background: #ccc;
+}
+
+.vis-configuration-popup {
+    position: absolute;
+    background: rgba(57, 76, 89, 0.85);
+    border: 2px solid #f2faff;
+    line-height:30px;
+    height:30px;
+    width:150px;
+    text-align:center;
+    color: #ffffff;
+    font-size:14px;
+    border-radius:4px;
+    -webkit-transition: opacity 0.3s ease-in-out;
+    -moz-transition: opacity 0.3s ease-in-out;
+    transition: opacity 0.3s ease-in-out;
+}
+.vis-configuration-popup:after, .vis-configuration-popup:before {
+    left: 100%;
+    top: 50%;
+    border: solid transparent;
+    content: " ";
+    height: 0;
+    width: 0;
+    position: absolute;
+    pointer-events: none;
+}
+
+.vis-configuration-popup:after {
+    border-color: rgba(136, 183, 213, 0);
+    border-left-color: rgba(57, 76, 89, 0.85);
+    border-width: 8px;
+    margin-top: -8px;
+}
+.vis-configuration-popup:before {
+    border-color: rgba(194, 225, 245, 0);
+    border-left-color: #f2faff;
+    border-width: 12px;
+    margin-top: -12px;
+}
+
+.vis-timeline {
+  position: relative;
+  border: 1px solid #bfbfbf;
+
+  overflow: hidden;
+  padding: 0;
+  margin: 0;
+
+  box-sizing: border-box;
+}
+
+
+.vis-panel {
+  position: absolute;
+
+  padding: 0;
+  margin: 0;
+
+  box-sizing: border-box;
+}
+
+.vis-panel.vis-center,
+.vis-panel.vis-left,
+.vis-panel.vis-right,
+.vis-panel.vis-top,
+.vis-panel.vis-bottom {
+  border: 1px #bfbfbf;
+}
+
+.vis-panel.vis-center,
+.vis-panel.vis-left,
+.vis-panel.vis-right {
+  border-top-style: solid;
+  border-bottom-style: solid;
+  overflow: hidden;
+}
+
+.vis-panel.vis-center,
+.vis-panel.vis-top,
+.vis-panel.vis-bottom {
+  border-left-style: solid;
+  border-right-style: solid;
+}
+
+.vis-background {
+  overflow: hidden;
+}
+
+.vis-panel > .vis-content {
+  position: relative;
+}
+
+.vis-panel .vis-shadow {
+  position: absolute;
+  width: 100%;
+  height: 1px;
+  box-shadow: 0 0 10px rgba(0,0,0,0.8);
+  /* TODO: find a nice way to ensure vis-shadows are drawn on top of items
+  z-index: 1;
+  */
+}
+
+.vis-panel .vis-shadow.vis-top {
+  top: -1px;
+  left: 0;
+}
+
+.vis-panel .vis-shadow.vis-bottom {
+  bottom: -1px;
+  left: 0;
+}
+
+.vis-labelset {
+  position: relative;
+
+  overflow: hidden;
+
+  box-sizing: border-box;
+}
+
+.vis-labelset .vis-label {
+  position: relative;
+  left: 0;
+  top: 0;
+  width: 100%;
+  color: #4d4d4d;
+
+  box-sizing: border-box;
+}
+
+.vis-labelset .vis-label {
+  border-bottom: 1px solid #bfbfbf;
+}
+
+.vis-labelset .vis-label.draggable {
+  cursor: pointer;
+}
+
+.vis-labelset .vis-label:last-child {
+  border-bottom: none;
+}
+
+.vis-labelset .vis-label .vis-inner {
+  display: inline-block;
+  padding: 5px;
+}
+
+.vis-labelset .vis-label .vis-inner.vis-hidden {
+  padding: 0;
+}
+
+
+.vis-itemset {
+  position: relative;
+  padding: 0;
+  margin: 0;
+
+  box-sizing: border-box;
+}
+
+.vis-itemset .vis-background,
+.vis-itemset .vis-foreground {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  overflow: visible;
+}
+
+.vis-axis {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  left: 0;
+  z-index: 1;
+}
+
+.vis-foreground .vis-group {
+  position: relative;
+  box-sizing: border-box;
+  border-bottom: 1px solid #bfbfbf;
+}
+
+.vis-foreground .vis-group:last-child {
+  border-bottom: none;
+}
+
+.vis-overlay {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 10;
+}
+
+.vis-item {
+  position: absolute;
+  color: #1A1A1A;
+  border-color: #97B0F8;
+  border-width: 1px;
+  background-color: #D5DDF6;
+  display: inline-block;
+  /*overflow: hidden;*/
+}
+
+.vis-item.vis-selected {
+  border-color: #FFC200;
+  background-color: #FFF785;
+
+  /* z-index must be higher than the z-index of custom time bar and current time bar */
+  z-index: 2;
+}
+
+.vis-editable.vis-selected {
+  cursor: move;
+}
+
+.vis-item.vis-point.vis-selected {
+  background-color: #FFF785;
+}
+
+.vis-item.vis-box {
+  text-align: center;
+  border-style: solid;
+  border-radius: 2px;
+}
+
+.vis-item.vis-point {
+  background: none;
+}
+
+.vis-item.vis-dot {
+  position: absolute;
+  padding: 0;
+  border-width: 4px;
+  border-style: solid;
+  border-radius: 4px;
+}
+
+.vis-item.vis-range {
+  border-style: solid;
+  border-radius: 2px;
+  box-sizing: border-box;
+}
+
+.vis-item.vis-background {
+  border: none;
+  background-color: rgba(213, 221, 246, 0.4);
+  box-sizing: border-box;
+  padding: 0;
+  margin: 0;
+}
+
+.vis-item .vis-item-overflow {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  padding: 0;
+  margin: 0;
+  overflow: hidden;
+}
+
+.vis-item.vis-range .vis-item-content {
+  position: relative;
+  display: inline-block;
+}
+
+.vis-item.vis-background .vis-item-content {
+  position: absolute;
+  display: inline-block;
+}
+
+.vis-item.vis-line {
+  padding: 0;
+  position: absolute;
+  width: 0;
+  border-left-width: 1px;
+  border-left-style: solid;
+}
+
+.vis-item .vis-item-content {
+  white-space: nowrap;
+  box-sizing: border-box;
+  padding: 5px;
+}
+
+.vis-item .vis-delete {
+  background: url('img/timeline/delete.png') no-repeat center;
+  position: absolute;
+  width: 24px;
+  height: 24px;
+  top: -4px;
+  right: -24px;
+  cursor: pointer;
+}
+
+.vis-item.vis-range .vis-drag-left {
+  position: absolute;
+  width: 24px;
+  max-width: 20%;
+  min-width: 2px;
+  height: 100%;
+  top: 0;
+  left: -4px;
+
+  cursor: w-resize;
+}
+
+.vis-item.vis-range .vis-drag-right {
+  position: absolute;
+  width: 24px;
+  max-width: 20%;
+  min-width: 2px;
+  height: 100%;
+  top: 0;
+  right: -4px;
+
+  cursor: e-resize;
+}
+
+.vis-time-axis {
+  position: relative;
+  overflow: hidden;
+}
+
+.vis-time-axis.vis-foreground {
+  top: 0;
+  left: 0;
+  width: 100%;
+}
+
+.vis-time-axis.vis-background {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.vis-time-axis .vis-text {
+  position: absolute;
+  color: #4d4d4d;
+  padding: 3px;
+  overflow: hidden;
+  box-sizing: border-box;
+
+  white-space: nowrap;
+}
+
+.vis-time-axis .vis-text.vis-measure {
+  position: absolute;
+  padding-left: 0;
+  padding-right: 0;
+  margin-left: 0;
+  margin-right: 0;
+  visibility: hidden;
+}
+
+.vis-time-axis .vis-grid.vis-vertical {
+  position: absolute;
+  border-left: 1px solid;
+}
+
+.vis-time-axis .vis-grid.vis-minor {
+  border-color: #e5e5e5;
+}
+
+.vis-time-axis .vis-grid.vis-major {
+  border-color: #bfbfbf;
+}
+
+.vis-current-time {
+  background-color: #FF7F6E;
+  width: 2px;
+  z-index: 1;
+}
+.vis-custom-time {
+  background-color: #6E94FF;
+  width: 2px;
+  cursor: move;
+  z-index: 1;
+}
+.vis-timeline {
+  /*
+  -webkit-transition: height .4s ease-in-out;
+  transition:         height .4s ease-in-out;
+  */
+}
+
+.vis-panel {
+  /*
+  -webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
+  transition:         height .4s ease-in-out, top .4s ease-in-out;
+  */
+}
+
+.vis-axis {
+  /*
+  -webkit-transition: top .4s ease-in-out;
+  transition:         top .4s ease-in-out;
+  */
+}
+
+/* TODO: get animation working nicely
+
+.vis-item {
+  -webkit-transition: top .4s ease-in-out;
+  transition:         top .4s ease-in-out;
+}
+
+.vis-item.line {
+  -webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
+  transition:         height .4s ease-in-out, top .4s ease-in-out;
+}
+/**/
+
+.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  border-bottom: 1px solid;
+}
+
+.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor {
+  border-color: #e5e5e5;
+}
+
+.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major {
+  border-color: #bfbfbf;
+}
+
+
+.vis-data-axis .vis-y-axis.vis-major {
+  width: 100%;
+  position: absolute;
+  color: #4d4d4d;
+  white-space: nowrap;
+}
+
+.vis-data-axis .vis-y-axis.vis-major.vis-measure {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  visibility: hidden;
+  width: auto;
+}
+
+
+.vis-data-axis .vis-y-axis.vis-minor {
+  position: absolute;
+  width: 100%;
+  color: #bebebe;
+  white-space: nowrap;
+}
+
+.vis-data-axis .vis-y-axis.vis-minor.vis-measure {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  visibility: hidden;
+  width: auto;
+}
+
+.vis-data-axis .vis-y-axis.vis-title {
+  position: absolute;
+  color: #4d4d4d;
+  white-space: nowrap;
+  bottom: 20px;
+  text-align: center;
+}
+
+.vis-data-axis .vis-y-axis.vis-title.vis-measure {
+  padding: 0;
+  margin: 0;
+  visibility: hidden;
+  width: auto;
+}
+
+.vis-data-axis .vis-y-axis.vis-title.vis-left {
+  bottom: 0;
+  -webkit-transform-origin: left top;
+  -moz-transform-origin: left top;
+  -ms-transform-origin: left top;
+  -o-transform-origin: left top;
+  transform-origin: left bottom;
+  -webkit-transform: rotate(-90deg);
+  -moz-transform: rotate(-90deg);
+  -ms-transform: rotate(-90deg);
+  -o-transform: rotate(-90deg);
+  transform: rotate(-90deg);
+}
+
+.vis-data-axis .vis-y-axis.vis-title.vis-right {
+  bottom: 0;
+  -webkit-transform-origin: right bottom;
+  -moz-transform-origin: right bottom;
+  -ms-transform-origin: right bottom;
+  -o-transform-origin: right bottom;
+  transform-origin: right bottom;
+  -webkit-transform: rotate(90deg);
+  -moz-transform: rotate(90deg);
+  -ms-transform: rotate(90deg);
+  -o-transform: rotate(90deg);
+  transform: rotate(90deg);
+}
+
+.vis-legend {
+  background-color: rgba(247, 252, 255, 0.65);
+  padding: 5px;
+  border: 1px solid #b3b3b3;
+  box-shadow: 2px 2px 10px rgba(154, 154, 154, 0.55);
+}
+
+.vis-legend-text {
+  /*font-size: 10px;*/
+  white-space: nowrap;
+  display: inline-block
+}
+.vis-graph-group0 {
+    fill:#4f81bd;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #4f81bd;
+}
+
+.vis-graph-group1 {
+    fill:#f79646;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #f79646;
+}
+
+.vis-graph-group2 {
+    fill: #8c51cf;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #8c51cf;
+}
+
+.vis-graph-group3 {
+    fill: #75c841;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #75c841;
+}
+
+.vis-graph-group4 {
+    fill: #ff0100;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #ff0100;
+}
+
+.vis-graph-group5 {
+    fill: #37d8e6;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #37d8e6;
+}
+
+.vis-graph-group6 {
+    fill: #042662;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #042662;
+}
+
+.vis-graph-group7 {
+    fill:#00ff26;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #00ff26;
+}
+
+.vis-graph-group8 {
+    fill:#ff00ff;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #ff00ff;
+}
+
+.vis-graph-group9 {
+    fill: #8f3938;
+    fill-opacity:0;
+    stroke-width:2px;
+    stroke: #8f3938;
+}
+
+.vis-timeline .vis-fill {
+    fill-opacity:0.1;
+    stroke: none;
+}
+
+
+.vis-timeline .vis-bar {
+    fill-opacity:0.5;
+    stroke-width:1px;
+}
+
+.vis-timeline .vis-point {
+    stroke-width:2px;
+    fill-opacity:1.0;
+}
+
+
+.vis-timeline .vis-legend-background {
+    stroke-width:1px;
+    fill-opacity:0.9;
+    fill: #ffffff;
+    stroke: #c2c2c2;
+}
+
+
+.vis-timeline .vis-outline {
+    stroke-width:1px;
+    fill-opacity:1;
+    fill: #ffffff;
+    stroke: #e5e5e5;
+}
+
+.vis-timeline .vis-icon-fill {
+    fill-opacity:0.3;
+    stroke: none;
+}
+
+div.vis-network div.vis-manipulation {
+  border-width: 0;
+  border-bottom: 1px;
+  border-style:solid;
+  border-color: #d6d9d8;
+  background: #ffffff; /* Old browsers */
+  background: -moz-linear-gradient(top,  #ffffff 0%, #fcfcfc 48%, #fafafa 50%, #fcfcfc 100%); /* FF3.6+ */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(48%,#fcfcfc), color-stop(50%,#fafafa), color-stop(100%,#fcfcfc)); /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top,  #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Chrome10+,Safari5.1+ */
+  background: -o-linear-gradient(top,  #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Opera 11.10+ */
+  background: -ms-linear-gradient(top,  #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* IE10+ */
+  background: linear-gradient(to bottom,  #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* W3C */
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fcfcfc',GradientType=0 ); /* IE6-9 */
+
+  padding-top:4px;
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 28px;
+}
+
+div.vis-network div.vis-edit-mode {
+  position:absolute;
+  left: 0;
+  top: 5px;
+  height: 30px;
+}
+
+/* FIXME: shouldn't the vis-close button be a child of the vis-manipulation div? */
+
+div.vis-network div.vis-close {
+  position:absolute;
+  right: 0;
+  top: 0;
+  width: 30px;
+  height: 30px;
+
+  background-position: 20px 3px;
+  background-repeat: no-repeat;
+  background-image: url("img/network/cross.png");
+  cursor: pointer;
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+
+div.vis-network div.vis-close:hover {
+  opacity: 0.6;
+}
+
+div.vis-network div.vis-manipulation div.vis-button,
+div.vis-network div.vis-edit-mode div.vis-button {
+  float:left;
+  font-family: verdana;
+  font-size: 12px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+  display:inline-block;
+  background-position: 0px 0px;
+  background-repeat:no-repeat;
+  height:24px;
+  margin-left: 10px;
+  /*vertical-align:middle;*/
+  cursor: pointer;
+  padding: 0px 8px 0px 8px;
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+  -khtml-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+
+div.vis-network div.vis-manipulation div.vis-button:hover {
+  box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.20);
+}
+
+div.vis-network div.vis-manipulation div.vis-button:active {
+  box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.50);
+}
+
+div.vis-network div.vis-manipulation div.vis-button.vis-back {
+  background-image: url("img/network/backIcon.png");
+}
+
+div.vis-network div.vis-manipulation div.vis-button.vis-none:hover {
+  box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0);
+  cursor: default;
+}
+div.vis-network div.vis-manipulation div.vis-button.vis-none:active {
+  box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0);
+}
+div.vis-network div.vis-manipulation div.vis-button.vis-none {
+  padding: 0;
+}
+div.vis-network div.vis-manipulation div.notification {
+  margin: 2px;
+  font-weight: bold;
+}
+
+div.vis-network div.vis-manipulation div.vis-button.vis-add {
+  background-image: url("img/network/addNodeIcon.png");
+}
+
+div.vis-network div.vis-manipulation div.vis-button.vis-edit,
+div.vis-network div.vis-edit-mode div.vis-button.vis-edit {
+  background-image: url("img/network/editIcon.png");
+}
+
+div.vis-network div.vis-edit-mode div.vis-button.vis-edit.vis-edit-mode {
+  background-color: #fcfcfc;
+  border: 1px solid #cccccc;
+}
+
+div.vis-network div.vis-manipulation div.vis-button.vis-connect {
+  background-image: url("img/network/connectIcon.png");
+}
+
+div.vis-network div.vis-manipulation div.vis-button.vis-delete {
+  background-image: url("img/network/deleteIcon.png");
+}
+/* top right bottom left */
+div.vis-network div.vis-manipulation div.vis-label,
+div.vis-network div.vis-edit-mode div.vis-label {
+  margin: 0 0 0 23px;
+  line-height: 25px;
+}
+div.vis-network div.vis-manipulation div.vis-separator-line {
+  float:left;
+  display:inline-block;
+  width:1px;
+  height:21px;
+  background-color: #bdbdbd;
+  margin: 0px 7px 0 15px; /*top right bottom left*/
+}
+
+/* TODO: is this redundant?
+div.network-navigation_wrapper {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+}
+*/
+div.vis-network-tooltip {
+  position: absolute;
+  visibility: hidden;
+  padding: 5px;
+  white-space: nowrap;
+
+  font-family: verdana;
+  font-size:14px;
+  font-color:#000000;
+  background-color: #f5f4ed;
+
+  -moz-border-radius: 3px;
+  -webkit-border-radius: 3px;
+  border-radius: 3px;
+  border: 1px solid #808074;
+
+  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
+  pointer-events: none;
+}
+div.vis-network div.vis-navigation div.vis-button {
+    width:34px;
+    height:34px;
+    -moz-border-radius: 17px;
+    border-radius: 17px;
+    position:absolute;
+    display:inline-block;
+    background-position: 2px 2px;
+    background-repeat:no-repeat;
+    cursor: pointer;
+    -webkit-touch-callout: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+}
+
+div.vis-network div.vis-navigation div.vis-button:hover {
+    box-shadow: 0 0 3px 3px rgba(56, 207, 21, 0.30);
+}
+
+div.vis-network div.vis-navigation div.vis-button:active {
+    box-shadow: 0 0 1px 3px rgba(56, 207, 21, 0.95);
+}
+
+div.vis-network div.vis-navigation div.vis-button.vis-up {
+    background-image: url("img/network/upArrow.png");
+    bottom:50px;
+    left:55px;
+}
+div.vis-network div.vis-navigation div.vis-button.vis-down {
+    background-image: url("img/network/downArrow.png");
+    bottom:10px;
+    left:55px;
+}
+div.vis-network div.vis-navigation div.vis-button.vis-left {
+    background-image: url("img/network/leftArrow.png");
+    bottom:10px;
+    left:15px;
+}
+div.vis-network div.vis-navigation div.vis-button.vis-right {
+    background-image: url("img/network/rightArrow.png");
+    bottom:10px;
+    left:95px;
+}
+div.vis-network div.vis-navigation div.vis-button.vis-zoomIn {
+    background-image: url("img/network/plus.png");
+    bottom:10px;
+    right:15px;
+}
+div.vis-network div.vis-navigation div.vis-button.vis-zoomOut {
+    background-image: url("img/network/minus.png");
+    bottom:10px;
+    right:55px;
+}
+div.vis-network div.vis-navigation div.vis-button.vis-zoomExtends {
+    background-image: url("img/network/zoomExtends.png");
+    bottom:50px;
+    right:15px;
+}
+
+div.vis-color-picker {
+  position:absolute;
+  margin-top:-140px;
+  margin-left:30px;
+  width:293px;
+  height:425px;
+  padding: 10px;
+  border-radius:15px;
+  background-color:#ffffff;
+  display:none;
+  box-shadow: rgba(0,0,0,0.5) 0px 0px 10px 0px;
+}
+
+div.vis-color-picker div.vis-arrow {
+  position: absolute;
+  top:147px;
+  left:5px;
+}
+
+div.vis-color-picker div.vis-arrow:after,
+div.vis-color-picker div.vis-arrow:before {
+  right: 100%;
+  top: 50%;
+  border: solid transparent;
+  content: " ";
+  height: 0;
+  width: 0;
+  position: absolute;
+  pointer-events: none;
+}
+
+div.vis-color-picker div.vis-arrow:after {
+  border-color: rgba(255, 255, 255, 0);
+  border-right-color: #ffffff;
+  border-width: 30px;
+  margin-top: -30px;
+}
+
+div.vis-color-picker div.vis-color {
+  position:absolute;
+  width: 289px;
+  height: 289px;
+  cursor: pointer;
+}
+
+
+
+div.vis-color-picker div.vis-brightness {
+  position: absolute;
+  top:313px;
+}
+
+div.vis-color-picker div.vis-opacity {
+  position:absolute;
+  top:350px;
+}
+
+div.vis-color-picker div.vis-selector {
+  position:absolute;
+  top:137px;
+  left:137px;
+  width:15px;
+  height:15px;
+  border-radius:15px;
+  border:1px solid #ffffff;
+  background: #4c4c4c; /* Old browsers */
+  background: -moz-linear-gradient(top,  #4c4c4c 0%, #595959 12%, #666666 25%, #474747 39%, #2c2c2c 50%, #000000 51%, #111111 60%, #2b2b2b 76%, #1c1c1c 91%, #131313 100%); /* FF3.6+ */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#4c4c4c), color-stop(12%,#595959), color-stop(25%,#666666), color-stop(39%,#474747), color-stop(50%,#2c2c2c), color-stop(51%,#000000), color-stop(60%,#111111), color-stop(76%,#2b2b2b), color-stop(91%,#1c1c1c), color-stop(100%,#131313)); /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top,  #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* Chrome10+,Safari5.1+ */
+  background: -o-linear-gradient(top,  #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* Opera 11.10+ */
+  background: -ms-linear-gradient(top,  #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* IE10+ */
+  background: linear-gradient(to bottom,  #4c4c4c 0%,#595959 12%,#666666 25%,#474747 39%,#2c2c2c 50%,#000000 51%,#111111 60%,#2b2b2b 76%,#1c1c1c 91%,#131313 100%); /* W3C */
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#4c4c4c', endColorstr='#131313',GradientType=0 ); /* IE6-9 */
+}
+
+
+
+div.vis-color-picker div.vis-new-color {
+  position:absolute;
+  width:140px;
+  height:20px;
+  border:1px solid rgba(0,0,0,0.1);
+  border-radius:5px;
+  top:380px;
+  left:159px;
+  text-align:right;
+  padding-right:2px;
+  font-size:10px;
+  color:rgba(0,0,0,0.4);
+  vertical-align:middle;
+  line-height:20px;
+
+}
+
+div.vis-color-picker div.vis-initial-color {
+  position:absolute;
+  width:140px;
+  height:20px;
+  border:1px solid rgba(0,0,0,0.1);
+  border-radius:5px;
+  top:380px;
+  left:10px;
+  text-align:left;
+  padding-left:2px;
+  font-size:10px;
+  color:rgba(0,0,0,0.4);
+  vertical-align:middle;
+  line-height:20px;
+}
+
+div.vis-color-picker div.vis-label {
+  position:absolute;
+  width:300px;
+  left:10px;
+}
+
+div.vis-color-picker div.vis-label.vis-brightness {
+  top:300px;
+}
+
+div.vis-color-picker div.vis-label.vis-opacity {
+  top:338px;
+}
+
+div.vis-color-picker div.vis-button {
+  position:absolute;
+  width:68px;
+  height:25px;
+  border-radius:10px;
+  vertical-align: middle;
+  text-align:center;
+  line-height: 25px;
+  top:410px;
+  border:2px solid #d9d9d9;
+  background-color: #f7f7f7;
+  cursor:pointer;
+}
+
+div.vis-color-picker div.vis-button.vis-cancel {
+  /*border:2px solid #ff4e33;*/
+  /*background-color: #ff7761;*/
+  left:5px;
+}
+div.vis-color-picker div.vis-button.vis-load {
+  /*border:2px solid #a153e6;*/
+  /*background-color: #cb8dff;*/
+  left:82px;
+}
+div.vis-color-picker div.vis-button.vis-apply {
+  /*border:2px solid #4588e6;*/
+  /*background-color: #82b6ff;*/
+  left:159px;
+}
+div.vis-color-picker div.vis-button.vis-save {
+  /*border:2px solid #45e655;*/
+  /*background-color: #6dff7c;*/
+  left:236px;
+}
+
+
+div.vis-color-picker input.vis-range {
+  width: 290px;
+  height:20px;
+}
+
+/* TODO: is this redundant?
+div.vis-color-picker input.vis-range-brightness {
+  width: 289px !important;
+}
+
+
+div.vis-color-picker input.vis-saturation-range {
+  width: 289px !important;
+}*/
\ No newline at end of file


[5/5] incubator-cmda git commit: Add KnowledgeGraph page and recommendationSummary page. Update backend models and create new APIs to support new features. Add KnowledgCard in Dataset search result page.

Posted by xi...@apache.org.
Add KnowledgeGraph page and recommendationSummary page. Update backend models and create new APIs to support new features. Add KnowledgCard in Dataset search result page.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cmda/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cmda/commit/aa50efa2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cmda/tree/aa50efa2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cmda/diff/aa50efa2

Branch: refs/heads/master
Commit: aa50efa2b8ef25fb4abf3ada96bda0aa54ffaf87
Parents: a9a8367
Author: mingqi830 <mq...@andrew.cmu.edu>
Authored: Thu Oct 29 15:45:45 2015 -0700
Committer: mingqi830 <mq...@andrew.cmu.edu>
Committed: Thu Oct 29 15:45:45 2015 -0700

----------------------------------------------------------------------
 ApacheCMDA_Backend_1.0/DBDump/Dump20150414.sql  |    32 +
 .../app/controllers/AnalyticsController.java    |   128 +
 .../controllers/ClimateServiceController.java   |    19 +-
 .../app/controllers/DatasetController.java      |     2 -
 .../app/controllers/DatasetLogController.java   |     1 -
 .../ServiceExecutionLogController.java          |     4 +-
 .../app/models/ClimateServiceRepository.java    |     4 +-
 ApacheCMDA_Backend_1.0/app/models/Dataset.java  |     9 +
 .../app/models/DatasetAndUser.java              |    69 +
 .../app/models/DatasetAndUserRepository.java    |    12 +
 .../app/models/DatasetLogRepository.java        |     2 +-
 .../app/models/Instrument.java                  |     9 +
 .../app/models/ServiceExecutionLog.java         |    13 +-
 ApacheCMDA_Backend_1.0/conf/routes              |     4 +
 .../app/controllers/AnalyticsController.java    |    32 +-
 .../controllers/ClimateServiceController.java   |   482 +-
 .../app/controllers/DatasetController.java      |    68 +-
 .../app/controllers/DatasetLogController.java   |     4 +-
 .../ServiceExecutionLogController.java          |    14 +-
 ApacheCMDA_Frontend_1.0/app/models/Dataset.java |    32 +-
 .../app/models/Instrument.java                  |     9 +
 .../app/models/ServiceExecutionLog.java         |    13 +-
 .../app/utils/Constants.java                    |     5 +
 .../app/views/aboutUs.scala.html                |     6 +-
 .../app/views/allClimateServices.scala.html     |    17 +-
 .../app/views/allDatasets.scala.html            |     2 +-
 .../app/views/climateServiceList.scala.html     |    62 +
 .../app/views/dataSetList.scala.html            |    18 +-
 .../app/views/dataSetListPopular.scala.html     |    68 +
 .../app/views/header.scala.html                 |    18 +-
 .../app/views/knowledgeGraph.scala.html         |   320 +
 .../app/views/main.scala.html                   |     2 -
 .../app/views/recommendationSummary.scala.html  |   171 +
 .../app/views/searchClimateService.scala.html   |   117 +
 .../app/views/serviceLog.scala.html             |    19 +-
 ApacheCMDA_Frontend_1.0/conf/routes             |     8 +
 .../public/html/js2/.DS_Store                   |   Bin 0 -> 6148 bytes
 .../public/html/js2/common.css                  |    29 +
 .../public/html/js2/common.js                   |   548 +
 .../public/html/js2/dataList2.js                |    42 +
 .../public/html/js2/varList.js                  |    40 +
 .../public/html/serviceScatterPlot2Vars.html    |   672 +
 ApacheCMDA_Frontend_1.0/public/images/giphy.gif |   Bin 0 -> 998904 bytes
 .../public/javascripts/exampleUtil.js           |   126 +
 .../public/javascripts/googleAnalytics.js       |    12 +
 .../public/javascripts/vis.js                   | 43387 +++++++++++++++++
 .../public/stylesheets/vis.css                  |  1295 +
 47 files changed, 47686 insertions(+), 260 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/DBDump/Dump20150414.sql
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/DBDump/Dump20150414.sql b/ApacheCMDA_Backend_1.0/DBDump/Dump20150414.sql
index 48130c2..169081f 100644
--- a/ApacheCMDA_Backend_1.0/DBDump/Dump20150414.sql
+++ b/ApacheCMDA_Backend_1.0/DBDump/Dump20150414.sql
@@ -186,6 +186,7 @@ CREATE TABLE `Dataset` (
   `dataSourceNameinWebInterface` varchar(255) DEFAULT NULL,
   `startTime` datetime DEFAULT NULL,
   `endTime` datetime DEFAULT NULL,
+  `agencyURL` varchar(255) DEFAULT NULL,
   PRIMARY KEY (`id`),
   KEY `FK_9x29nf004vryd28iummv5l5r0` (`instrumentId`),
   CONSTRAINT `FK_9x29nf004vryd28iummv5l5r0` FOREIGN KEY (`instrumentId`) REFERENCES `Instrument` (`id`)
@@ -203,6 +204,35 @@ INSERT INTO `Dataset` VALUES (1,'ot','NOAA','NOAA_ARGO','3D','ARGO Ocean Tempera
 UNLOCK TABLES;
 
 --
+-- Table structure for table `DatasetAndUser`
+--
+
+DROP TABLE IF EXISTS `DatasetAndUser`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `DatasetAndUser` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `userId` bigint(20) NOT NULL,
+  `datasetId` bigint(20) NOT NULL,
+  `count` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `FK_User_DatasetAndUser` (`userId`),
+  KEY `FK_Dataset_DatasetAndUser` (`datasetId`),
+  CONSTRAINT `FK_User_DatasetAndUser` FOREIGN KEY (`userId`) REFERENCES `User` (`id`),
+  CONSTRAINT `FK_Dataset_DatasetAndUser` FOREIGN KEY (`datasetId`) REFERENCES `Dataset` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `DatasetAndUser`
+--
+
+LOCK TABLES `DatasetAndUser` WRITE;
+/*!40000 ALTER TABLE `DatasetAndUser` DISABLE KEYS */;
+/*!40000 ALTER TABLE `DatasetAndUser` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
 -- Table structure for table `DatasetAndService`
 --
 
@@ -285,6 +315,7 @@ CREATE TABLE `Instrument` (
   `description` varchar(255) DEFAULT NULL,
   `launchDate` datetime DEFAULT NULL,
   `name` varchar(255) DEFAULT NULL,
+  `instrumentURL` varchar(255) DEFAULT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1;
 /*!40101 SET character_set_client = @saved_cs_client */;
@@ -464,6 +495,7 @@ CREATE TABLE `ServiceExecutionLog` (
   `userId` bigint(20) NOT NULL,
   `datasetStudyStartTime` datetime DEFAULT NULL,
   `datasetStudyEndTime` datetime DEFAULT NULL,
+  `url` text DEFAULT NULL,
   PRIMARY KEY (`id`),
   KEY `FK_ly45hkuqs8yyw00iiuyx5hoj4` (`serviceId`),
   KEY `FK_g2n3b4rs0xys2r4r967uvi4jr` (`serviceConfigurationId`),

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/controllers/AnalyticsController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/controllers/AnalyticsController.java b/ApacheCMDA_Backend_1.0/app/controllers/AnalyticsController.java
new file mode 100644
index 0000000..feed694
--- /dev/null
+++ b/ApacheCMDA_Backend_1.0/app/controllers/AnalyticsController.java
@@ -0,0 +1,128 @@
+package controllers;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import models.DatasetAndUser;
+import models.DatasetAndUserRepository;
+import play.mvc.Controller;
+import play.mvc.Result;
+
+import com.google.gson.Gson;
+
+@Named
+@Singleton
+public class AnalyticsController extends Controller{
+	private final DatasetAndUserRepository datasetAndUserRepository;
+	@Inject
+	public AnalyticsController(DatasetAndUserRepository datasetAndUserRepository) {
+		this.datasetAndUserRepository = datasetAndUserRepository;
+	}
+	
+	public Result getAllDatasetAndUserWithCount(String format) {
+
+		try {
+			Iterable<DatasetAndUser> datasetAndUsers = datasetAndUserRepository.findAll();
+
+			if (datasetAndUsers == null) {
+				System.out.println("User and Dataset: cannot be found!");
+				return notFound("User and Dataset: cannot be found!");
+			}  
+
+			Map<String, Object> map = jsonFormat(datasetAndUsers);
+
+			String result = new String();
+			if (format.equals("json")) {
+				result = new Gson().toJson(map);
+			}
+
+			return ok(result);
+		} catch (Exception e) {
+			return badRequest("DatasetLog not found");
+		}
+	}
+
+	private Map<String, Object> jsonFormat(Iterable<DatasetAndUser> userDatasets) {
+
+		List<Map<String, Object>> nodes = new ArrayList<Map<String, Object>>();
+		List<Map<String, Object>> rels = new ArrayList<Map<String, Object>>();
+
+		int i = 1;
+		for (DatasetAndUser userDataset : userDatasets) {
+			int source = 0;
+			int target = 0;
+			// Check whether the current user has already existed
+			for (int j = 0; j < nodes.size(); j++) {
+				if (nodes.get(j).get("title")
+						.equals(userDataset.getUser().getUserName())) {
+					source = (int) nodes.get(j).get("id");
+					break;
+				}
+			}
+			if (source == 0) {
+				nodes.add(map6("id", i, "title", userDataset.getUser()
+						.getUserName(), "label", "user", "cluster", "1",
+						"value", 1, "group", "user"));
+				source = i;
+				i++;
+			}
+			// Check whether the current dataset has already existed
+			for (int j = 0; j < nodes.size(); j++) {
+				if (nodes.get(j).get("title")
+						.equals(userDataset.getDataset().getName())) {
+					target = (int) nodes.get(j).get("id");
+					break;
+				}
+			}
+			if (target == 0) {
+				nodes.add(map6("id", i, "title", userDataset.getDataset()
+						.getName(), "label", "dataset", "cluster", "2",
+						"value", 2, "group", "dataset"));
+				target = i;
+				i++;
+			}
+
+			rels.add(map3("from", source, "to", target, "title", "USE"));
+
+		}
+
+		return map("nodes", nodes, "edges", rels);
+	}
+
+	private Map<String, Object> map(String key1, Object value1, String key2,
+			Object value2) {
+		Map<String, Object> result = new HashMap<String, Object>(2);
+		result.put(key1, value1);
+		result.put(key2, value2);
+		return result;
+	}
+
+	private Map<String, Object> map3(String key1, Object value1, String key2,
+			Object value2, String key3, Object value3) {
+		Map<String, Object> result = new HashMap<String, Object>(3);
+		result.put(key1, value1);
+		result.put(key2, value2);
+		result.put(key3, value3);
+		return result;
+	}
+
+	private Map<String, Object> map6(String key1, Object value1, String key2,
+			Object value2, String key3, Object value3, String key4,
+			Object value4, String key5, Object value5, String key6,
+			Object value6) {
+		Map<String, Object> result = new HashMap<String, Object>(6);
+		result.put(key1, value1);
+		result.put(key2, value2);
+		result.put(key3, value3);
+		result.put(key4, value4);
+		result.put(key5, value5);
+		result.put(key6, value6);
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/controllers/ClimateServiceController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/controllers/ClimateServiceController.java b/ApacheCMDA_Backend_1.0/app/controllers/ClimateServiceController.java
index 73722b3..700ad68 100644
--- a/ApacheCMDA_Backend_1.0/app/controllers/ClimateServiceController.java
+++ b/ApacheCMDA_Backend_1.0/app/controllers/ClimateServiceController.java
@@ -472,5 +472,22 @@ public class ClimateServiceController extends Controller {
         return ok(result);
 
     }
-
+    
+    public Result getTopKUsedClimateServicesByDatasetId(long id, String format) {
+    	if (id < 0) {
+			System.out.println("id is negative!");
+			return badRequest("id is negative!");
+		}
+    	String result = new String();
+    	try {
+    		//Parse JSON file
+    		List<ClimateService> climateService;
+    		climateService = climateServiceRepository.getClimateServiceByDatasetId(5, id);
+    		result = new Gson().toJson(climateService);
+    	} catch (Exception e) {
+    		System.out.println("ServiceExecutionLog cannot be queried, query is corrupt");
+    		return badRequest("ServiceExecutionLog cannot be queried, query is corrupt");
+    	}
+    	return ok(result);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/controllers/DatasetController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/controllers/DatasetController.java b/ApacheCMDA_Backend_1.0/app/controllers/DatasetController.java
index 295c0a2..23822b4 100644
--- a/ApacheCMDA_Backend_1.0/app/controllers/DatasetController.java
+++ b/ApacheCMDA_Backend_1.0/app/controllers/DatasetController.java
@@ -366,8 +366,6 @@ public class DatasetController extends Controller {
     		System.out.println("ServiceExecutionLog cannot be queried, query is corrupt");
     		return badRequest("ServiceExecutionLog cannot be queried, query is corrupt");
     	}
-    	System.out.println("************" + result);
-
     	return ok(result);
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/controllers/DatasetLogController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/controllers/DatasetLogController.java b/ApacheCMDA_Backend_1.0/app/controllers/DatasetLogController.java
index 432cf16..f92b68e 100644
--- a/ApacheCMDA_Backend_1.0/app/controllers/DatasetLogController.java
+++ b/ApacheCMDA_Backend_1.0/app/controllers/DatasetLogController.java
@@ -3,7 +3,6 @@ package controllers;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
-
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/controllers/ServiceExecutionLogController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/controllers/ServiceExecutionLogController.java b/ApacheCMDA_Backend_1.0/app/controllers/ServiceExecutionLogController.java
index 507d549..e4594a8 100644
--- a/ApacheCMDA_Backend_1.0/app/controllers/ServiceExecutionLogController.java
+++ b/ApacheCMDA_Backend_1.0/app/controllers/ServiceExecutionLogController.java
@@ -342,8 +342,8 @@ public class ServiceExecutionLogController extends Controller {
 		String purpose = json.findPath("purpose").asText();
 		String plotUrl = json.findPath("url").asText();
 		String dataUrl = json.findPath("dataUrl").asText();
+		String url = json.findPath("urlLink").asText();
 		JsonNode datasetArray = json.get("datasets");
-		System.out.println(datasetArray);
 
 		SimpleDateFormat formatter = new SimpleDateFormat(util.Common.DATE_PATTERN);
 		formatter.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
@@ -415,7 +415,7 @@ public class ServiceExecutionLogController extends Controller {
 			ServiceExecutionLog serviceExecutionLog = new ServiceExecutionLog(
 					climateService, user, serviceConfiguration, purpose,
 					executionStartTime, executionEndTime, dataUrl, plotUrl,
-					datasetStudyStartTime, datasetStudyEndTime);
+					datasetStudyStartTime, datasetStudyEndTime, url);
 			ServiceExecutionLog savedServiceExecutionLog = serviceExecutionLogRepository
 					.save(serviceExecutionLog);
 			ServiceConfiguration savedServiceConfiguration = savedServiceExecutionLog

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/models/ClimateServiceRepository.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/models/ClimateServiceRepository.java b/ApacheCMDA_Backend_1.0/app/models/ClimateServiceRepository.java
index 53a303f..2f70c53 100644
--- a/ApacheCMDA_Backend_1.0/app/models/ClimateServiceRepository.java
+++ b/ApacheCMDA_Backend_1.0/app/models/ClimateServiceRepository.java
@@ -21,5 +21,7 @@ public interface ClimateServiceRepository extends CrudRepository<ClimateService,
 
 	@Query(value = "select c.* from ClimateService c, ServiceEntry s where c.id=s.serviceId group by s.serviceId order by s.latestAccessTimeStamp desc", nativeQuery = true)
 	List<ClimateService> getClimateServiceOrderByLatestAccessTime();
-
+	
+	@Query(value = "select * from ClimateService where id in (select serviceId from ServiceEntry s where serviceId in (select climateServiceId from DatasetAndService where datasetId=?2) group by s.serviceId order by s.latestAccessTimeStamp desc) limit ?1", nativeQuery = true)
+	List<ClimateService> getClimateServiceByDatasetId(int k, long id);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/models/Dataset.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/models/Dataset.java b/ApacheCMDA_Backend_1.0/app/models/Dataset.java
index 884a957..0d4fc3c 100644
--- a/ApacheCMDA_Backend_1.0/app/models/Dataset.java
+++ b/ApacheCMDA_Backend_1.0/app/models/Dataset.java
@@ -45,6 +45,7 @@ public class Dataset {
 	private String comment;
 	private Date startTime;
 	private Date endTime;
+	private String agencyURL;
 	
 
 	public Dataset() {
@@ -82,6 +83,14 @@ public class Dataset {
 		this.endTime = endTime;
 	}
 
+	public String getAgencyURL() {
+		return agencyURL;
+	}
+
+	public void setAgencyURL(String agencyURL) {
+		this.agencyURL = agencyURL;
+	}
+
 	public long getId() {
 		return id;
 	}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/models/DatasetAndUser.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/models/DatasetAndUser.java b/ApacheCMDA_Backend_1.0/app/models/DatasetAndUser.java
new file mode 100644
index 0000000..53665b3
--- /dev/null
+++ b/ApacheCMDA_Backend_1.0/app/models/DatasetAndUser.java
@@ -0,0 +1,69 @@
+package models;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+@Entity
+public class DatasetAndUser {
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.AUTO)
+	private long id;
+	@ManyToOne(optional = false)
+	@JoinColumn(name = "userId", referencedColumnName = "id")
+	private User user;
+	@ManyToOne(optional = false)
+	@JoinColumn(name = "datasetId", referencedColumnName = "id")
+	private Dataset dataset;
+	private long count;
+	
+	public DatasetAndUser() {
+	}
+	
+	public DatasetAndUser(User user, Dataset dataset, long count) {
+		this.user = user;
+		this.dataset = dataset;
+		this.count = count;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
+	public User getUser() {
+		return user;
+	}
+
+	public void setUser(User user) {
+		this.user = user;
+	}
+
+	public Dataset getDataset() {
+		return dataset;
+	}
+
+	public void setDataset(Dataset dataset) {
+		this.dataset = dataset;
+	}
+
+	public long getCount() {
+		return count;
+	}
+	public void setCount(long count) {
+		this.count = count;
+	}
+	
+	@Override
+	public String toString() {
+		return "DatasetAndUser[id=" + id + ", user=" + user.toString()
+				+ ", dataset=" + dataset.toString() + ", count=" + count + "]";
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/models/DatasetAndUserRepository.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/models/DatasetAndUserRepository.java b/ApacheCMDA_Backend_1.0/app/models/DatasetAndUserRepository.java
new file mode 100644
index 0000000..ce6b046
--- /dev/null
+++ b/ApacheCMDA_Backend_1.0/app/models/DatasetAndUserRepository.java
@@ -0,0 +1,12 @@
+package models;
+
+import org.springframework.data.repository.CrudRepository;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+@Named
+@Singleton
+public interface DatasetAndUserRepository extends CrudRepository<DatasetAndUser, Long> {
+		
+}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/models/DatasetLogRepository.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/models/DatasetLogRepository.java b/ApacheCMDA_Backend_1.0/app/models/DatasetLogRepository.java
index 3381b4e..de4ce6c 100644
--- a/ApacheCMDA_Backend_1.0/app/models/DatasetLogRepository.java
+++ b/ApacheCMDA_Backend_1.0/app/models/DatasetLogRepository.java
@@ -8,5 +8,5 @@ import javax.inject.Singleton;
 @Named
 @Singleton
 public interface DatasetLogRepository extends CrudRepository<DatasetLog, Long> {
-
+	
 }

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/models/Instrument.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/models/Instrument.java b/ApacheCMDA_Backend_1.0/app/models/Instrument.java
index 71a0094..45aed25 100644
--- a/ApacheCMDA_Backend_1.0/app/models/Instrument.java
+++ b/ApacheCMDA_Backend_1.0/app/models/Instrument.java
@@ -15,6 +15,7 @@ public class Instrument {
 	private String name;
 	private String description;
 	private Date launchDate;
+	private String instrumentURL;
 	
 	public Instrument() {
 	}
@@ -26,6 +27,14 @@ public class Instrument {
 		this.launchDate = launchDate;
 	}
 
+	public String getInstrumentURL() {
+		return instrumentURL;
+	}
+
+	public void setInstrumentURL(String instrumentURL) {
+		this.instrumentURL = instrumentURL;
+	}
+
 	public long getId() {
 		return id;
 	}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/app/models/ServiceExecutionLog.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/app/models/ServiceExecutionLog.java b/ApacheCMDA_Backend_1.0/app/models/ServiceExecutionLog.java
index c35c6c4..86351dc 100644
--- a/ApacheCMDA_Backend_1.0/app/models/ServiceExecutionLog.java
+++ b/ApacheCMDA_Backend_1.0/app/models/ServiceExecutionLog.java
@@ -40,6 +40,7 @@ public class ServiceExecutionLog {
 	private String dataUrl;
 	private Date datasetStudyStartTime;
 	private Date datasetStudyEndTime;
+	private String url;
 	
 
 	public ServiceExecutionLog(
@@ -47,7 +48,7 @@ public class ServiceExecutionLog {
 			ServiceConfiguration serviceConfiguration, // DatasetLog datasetLog,
 			String purpose, Date executionStartTime, Date executionEndTime,
 			String dataUrl, String plotUrl,
-			Date datasetStudyStartTime, Date datasetStudyEndTime) {
+			Date datasetStudyStartTime, Date datasetStudyEndTime, String url) {
 	this.climateService = climateService;
 		this.user = user;
 		this.serviceConfiguration = serviceConfiguration;
@@ -59,6 +60,7 @@ public class ServiceExecutionLog {
 		this.dataUrl = dataUrl;
 		this.datasetStudyStartTime = datasetStudyStartTime;
 		this.datasetStudyEndTime = datasetStudyEndTime;
+		this.url = url;
 	}
 	
 	public ServiceExecutionLog() {
@@ -111,6 +113,10 @@ public class ServiceExecutionLog {
 	
 	public Date getDatasetStudyEndTime() {
 		return datasetStudyEndTime;
+	}	
+
+	public String getUrl() {
+		return url;
 	}
 	
 	public void setId(long id) {
@@ -161,6 +167,10 @@ public class ServiceExecutionLog {
 		this.datasetStudyEndTime  = datasetStudyEndTime;
 	}
 
+	public void setUrl(String url) {
+		this.url = url;
+	}
+
 	@Override
 	public String toString() {
 		return "ServiceExecutionLog [id=" + id + ", climateService="
@@ -171,6 +181,7 @@ public class ServiceExecutionLog {
 				+ plotUrl + ", dataUrl=" + dataUrl 
 				+ ", datasetStudyStartTime=" + datasetStudyStartTime
 				+ ", datasetStudyEndTime=" + datasetStudyEndTime
+				+ ", url=" + url
 				+ "]";
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Backend_1.0/conf/routes
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Backend_1.0/conf/routes b/ApacheCMDA_Backend_1.0/conf/routes
index ff3d46c..b59bff7 100644
--- a/ApacheCMDA_Backend_1.0/conf/routes
+++ b/ApacheCMDA_Backend_1.0/conf/routes
@@ -13,6 +13,7 @@ GET           /climateService/getAllClimateServices/json
 GET           /climateService/getAllMostRecentClimateServicesByCreateTime/json                          @controllers.ClimateServiceController.getAllClimateServicesOrderByCreateTime(format: String="json")
 GET           /climateService/getAllMostRecentClimateServicesByLatestAccessTime/json                    @controllers.ClimateServiceController.getAllClimateServicesOrderByLatestAccessTime(format: String="json")
 GET           /climateService/getAllMostUsedClimateServices/json                                        @controllers.ClimateServiceController.getAllClimateServicesOrderByCount(format: String="json")
+GET			  /climateService/getTopKUsedClimateServicesByDatasetId/:id									@controllers.ClimateServiceController.getTopKUsedClimateServicesByDatasetId(id: Long, format: String="json")
 POST          /climateService/addClimateService                                                         @controllers.ClimateServiceController.addClimateService
 GET           /climateService/getAllServiceEntries/json                                                 @controllers.ClimateServiceController.getAllServiceEntries(format: String="json")
 POST          /climateService/addServiceEntry                                                           @controllers.ClimateServiceController.addServiceEntry
@@ -136,5 +137,8 @@ POST		  /users/isUserValid																		@controllers.UserController.isUserVa
 POST		  /users/isEmailExisted																		@controllers.UserController.isEmailExisted
 DELETE		  /users/delete/userName/:userName/password/:password										@controllers.UserController.deleteUserByUserNameandPassword(userName: String, password: String)
 
+# Analytics
+GET			  /analytics/getAllDatasetAndUserWithCount/json											@controllers.AnalyticsController.getAllDatasetAndUserWithCount(format: String="json")
+
 # Map static resources from the /public folder to the /assets URL path
 GET           /assets/*file                                                                             controllers.Assets.at(path="/public", file)

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/controllers/AnalyticsController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/controllers/AnalyticsController.java b/ApacheCMDA_Frontend_1.0/app/controllers/AnalyticsController.java
index 873ecfa..75d7881 100644
--- a/ApacheCMDA_Frontend_1.0/app/controllers/AnalyticsController.java
+++ b/ApacheCMDA_Frontend_1.0/app/controllers/AnalyticsController.java
@@ -1,39 +1,14 @@
 package controllers;
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map.Entry;
-
-import org.apache.commons.lang3.StringEscapeUtils;
-
-import models.ClimateService;
 import models.ServiceExecutionLog;
-import play.Logger;
-import play.data.DynamicForm;
 import play.data.Form;
-import play.libs.Json;
 import play.mvc.Controller;
 import play.mvc.Result;
 import utils.Constants;
 import utils.RESTfulCalls;
-import utils.RESTfulCalls.ResponseType;
 import views.html.*;
-import models.*;
-import views.*;
 
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 
 public class AnalyticsController extends Controller{
 
@@ -41,6 +16,13 @@ public class AnalyticsController extends Controller{
 			.form(ServiceExecutionLog.class);
 	
 	
+	public static Result getKnowledgeGraph() {
+		JsonNode response = RESTfulCalls.getAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT + Constants.GET_DATASET_AND_USER);
+		String resStr = response.toString();
+		return ok(knowledgeGraph.render(resStr));
+	}
+	
 	public static Result getRecommend() {
 		JsonNode response = RESTfulCalls.getAPI("http://einstein.sv.cmu.edu:9026/api/sgraph");
 		String resStr = response.toString();

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/controllers/ClimateServiceController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/controllers/ClimateServiceController.java b/ApacheCMDA_Frontend_1.0/app/controllers/ClimateServiceController.java
index f103643..e0c0739 100644
--- a/ApacheCMDA_Frontend_1.0/app/controllers/ClimateServiceController.java
+++ b/ApacheCMDA_Frontend_1.0/app/controllers/ClimateServiceController.java
@@ -12,6 +12,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.text.DateFormat;
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
@@ -24,6 +25,7 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 import org.apache.commons.lang3.StringEscapeUtils;
 
 import models.ClimateService;
+import models.Dataset;
 import models.ServiceConfigurationItem;
 import models.User;
 import play.Logger;
@@ -38,13 +40,14 @@ import utils.RESTfulCalls.ResponseType;
 import views.html.*;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 public class ClimateServiceController extends Controller {
 
 	final static Form<ClimateService> climateServiceForm = Form
-			.form(ClimateService.class); 
-	
+			.form(ClimateService.class);
+
 	public static Result addAClimateService() {
 		return ok(registerAClimateService.render(climateServiceForm));
 	}
@@ -54,32 +57,17 @@ public class ClimateServiceController extends Controller {
 		JsonNode climateServicesNode = RESTfulCalls.getAPI(Constants.URL_HOST
 				+ Constants.CMU_BACKEND_PORT
 				+ Constants.GET_ALL_CLIMATE_SERVICES);
-		System.out.println("GET API: " + Constants.URL_HOST
-				+ Constants.CMU_BACKEND_PORT
-				+ Constants.GET_ALL_CLIMATE_SERVICES);
 		// if no value is returned or error or is not json array
 		if (climateServicesNode == null || climateServicesNode.has("error")
 				|| !climateServicesNode.isArray()) {
 			return ok(allClimateServices.render(climateServicesList,
-				climateServiceForm));
+					climateServiceForm));
 		}
-	
+
 		// parse the json string into object
 		for (int i = 0; i < climateServicesNode.size(); i++) {
 			JsonNode json = climateServicesNode.path(i);
-			ClimateService oneService = new ClimateService();
-			oneService.setName(json.path("name").asText());
-			System.out.println("****************"+json.path("name").asText());
-			oneService.setPurpose(json.path("purpose").asText());
-			// URL here is the dynamic page url
-			String name = json.path("name").asText();
-			String pageUrl = Constants.URL_SERVER + Constants.LOCAL_HOST_PORT + "/assets/html/service" + 
-					name.substring(0, 1).toUpperCase() + name.substring(1) + ".html";
-			oneService.setUrl(pageUrl);
-			// newService.setCreateTime(json.path("createTime").asText());
-			oneService.setScenario(json.path("scenario").asText());
-			oneService.setVersionNo(json.path("versionNo").asText());
-			oneService.setRootServiceId(json.path("rootServiceId").asLong());
+			ClimateService oneService = deserializeJsonToClimateService(json);
 			climateServicesList.add(oneService);
 		}
 
@@ -88,7 +76,7 @@ public class ClimateServiceController extends Controller {
 	}
 
 	public static Result addClimateService() {
-//		Form<ClimateService> cs = climateServiceForm.bindFromRequest();
+		// Form<ClimateService> cs = climateServiceForm.bindFromRequest();
 		JsonNode json = request().body().asJson();
 		String name = json.path("name").asText();
 		String purpose = json.path("purpose").asText();
@@ -96,7 +84,7 @@ public class ClimateServiceController extends Controller {
 		String scenario = json.path("scenario").asText();
 		String versionNo = json.path("version").asText();
 		String rootServiceId = json.path("rootServiceId").asText();
-		
+
 		JsonNode response = null;
 		ObjectNode jsonData = Json.newObject();
 		try {
@@ -115,21 +103,22 @@ public class ClimateServiceController extends Controller {
 											// default val
 			jsonData.put("purpose", purpose);
 			jsonData.put("url", url);
-			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");
+			DateFormat dateFormat = new SimpleDateFormat(
+					"yyyy-MM-dd'T'HH:mm:ssz");
 			// get current date time with Date()
 			Date date = new Date();
 			jsonData.put("createTime", dateFormat.format(date));
 			jsonData.put("scenario", scenario);
 			jsonData.put("versionNo", versionNo);
 			jsonData.put("rootServiceId", rootServiceId);
-			
 
 			// POST Climate Service JSON data
-			response = RESTfulCalls.postAPI(Constants.URL_HOST + Constants.CMU_BACKEND_PORT 
+			response = RESTfulCalls.postAPI(Constants.URL_HOST
+					+ Constants.CMU_BACKEND_PORT
 					+ Constants.ADD_CLIMATE_SERVICE, jsonData);
 
 			// flash the response message
-			System.out.println("***************"+response);
+			System.out.println("***************" + response);
 			Application.flashMsg(response);
 		} catch (IllegalStateException e) {
 			e.printStackTrace();
@@ -148,7 +137,7 @@ public class ClimateServiceController extends Controller {
 		System.out.println("JSON data: " + jsonData);
 		String url = jsonData.get("climateServiceCallUrl").toString();
 		System.out.println("JPL climate service model call url: " + url);
-		
+
 		// transfer JsonNode to Object
 		ObjectNode object = (ObjectNode) jsonData;
 		object.remove("climateServiceCallUrl");
@@ -162,7 +151,8 @@ public class ClimateServiceController extends Controller {
 
 		// flash the response message
 		Application.flashMsg(response);
-		System.out	.println(ok("Climate Service model has been called successfully!"));
+		System.out
+				.println(ok("Climate Service model has been called successfully!"));
 		// return jsonData
 		return ok(response);
 	}
@@ -173,9 +163,11 @@ public class ClimateServiceController extends Controller {
 		String name = request().body().asJson().get("name").toString();
 		String purpose = request().body().asJson().get("purpose").toString();
 		String url = request().body().asJson().get("url").toString();
-		String outputButton = request().body().asJson().get("pageOutput").toString();
-		String dataListContent = request().body().asJson().get("dataListContent").toString();
-		
+		String outputButton = request().body().asJson().get("pageOutput")
+				.toString();
+		String dataListContent = request().body().asJson()
+				.get("dataListContent").toString();
+
 		System.out.println("page string: " + str);
 		System.out.println("climate service name: " + name);
 
@@ -187,8 +179,7 @@ public class ClimateServiceController extends Controller {
 		JsonNode response = RESTfulCalls.postAPI(Constants.URL_HOST
 				+ Constants.CMU_BACKEND_PORT
 				+ Constants.SAVE_CLIMATE_SERVICE_PAGE, jsonData);
-		
-		
+
 		System.out.println("WARNING!!!!!!");
 		// save page in front-end
 		savePage(str, name, purpose, url, outputButton, dataListContent);
@@ -200,32 +191,31 @@ public class ClimateServiceController extends Controller {
 
 	public static Result ruleEngineData() {
 		JsonNode result = request().body().asJson();
-		//System.out.println("ticking!");  
- 		System.out.println(result);		
-		
-		return ok("good");	
+		// System.out.println("ticking!");
+		System.out.println(result);
+
+		return ok("good");
 	}
-	
-	
+
 	public static Result addAllParameters() {
 		JsonNode result = request().body().asJson();
 		System.out.println(result);
 		System.out.println("--------------------------");
 		Iterator<JsonNode> ite = result.iterator();
-		
-		while(ite.hasNext()) {
-			
+
+		while (ite.hasNext()) {
+
 			JsonNode tmp = ite.next();
 			System.out.println(tmp);
-			JsonNode response = RESTfulCalls.postAPI(Constants.URL_HOST
-					+ Constants.CMU_BACKEND_PORT
-					+ Constants.ADD_ALL_PARAMETERS, tmp);
+			JsonNode response = RESTfulCalls.postAPI(
+					Constants.URL_HOST + Constants.CMU_BACKEND_PORT
+							+ Constants.ADD_ALL_PARAMETERS, tmp);
 			System.out.println("=========" + response);
 		}
-		
-		return ok("good");	
+
+		return ok("good");
 	}
-	
+
 	public static void savePage(String str, String name, String purpose,
 			String url, String outputButton, String dataListContent) {
 		System.out.println("output button test: " + outputButton);
@@ -234,24 +224,25 @@ public class ClimateServiceController extends Controller {
 				.replaceAll(
 						"<td><button type=\\\\\"button\\\\\" class=\\\\\"btn btn-danger\\\\\" onclick=\\\\\"Javascript:deleteRow\\(this,\\d+\\)\\\\\">delete</button></td>",
 						"");
-		
+
 		dataListContent = StringEscapeUtils.unescapeJava(dataListContent);
 		result = StringEscapeUtils.unescapeJava(result);
 		outputButton = StringEscapeUtils.unescapeJava(outputButton);
 		System.out.println("output button test: " + outputButton);
-		
+
 		// remove the first char " and the last char " of result, name and
 		// purpose
-		dataListContent = dataListContent.substring(1, dataListContent.length() - 1);
+		dataListContent = dataListContent.substring(1,
+				dataListContent.length() - 1);
 		result = result.substring(1, result.length() - 1);
 		outputButton = outputButton.substring(1, outputButton.length() - 1);
-		
+
 		name = name.substring(1, name.length() - 1);
 		purpose = purpose.substring(1, purpose.length() - 1);
-		
+
 		String putVarAndDataList = Constants.putVar + dataListContent;
 		System.out.println("putVarAndDataList: " + putVarAndDataList);
-		
+
 		String str11 = Constants.htmlHead1;
 		// System.out.println("head1: " + str11);
 		String str12 = Constants.htmlHead2;
@@ -264,8 +255,9 @@ public class ClimateServiceController extends Controller {
 		String str22 = Constants.htmlTail2;
 		String str23 = Constants.htmlTail3;
 
-		result = str11 +putVarAndDataList+ str12 + name + str13 + purpose + str14 + result + str21
-				+ url.substring(1, url.length() - 1) + str22 + outputButton + str23;
+		result = str11 + putVarAndDataList + str12 + name + str13 + purpose
+				+ str14 + result + str21 + url.substring(1, url.length() - 1)
+				+ str22 + outputButton + str23;
 
 		name = name.replace(" ", "");
 
@@ -275,7 +267,7 @@ public class ClimateServiceController extends Controller {
 				+ ".html";
 
 		File theDir = new File("public/html");
-		
+
 		// if the directory does not exist, create it
 		if (!theDir.exists()) {
 			System.out.println("creating directory: public/html");
@@ -305,6 +297,7 @@ public class ClimateServiceController extends Controller {
 			e.printStackTrace();
 		}
 	}
+
 	public static void flashMsg(JsonNode jsonNode) {
 		Iterator<Entry<String, JsonNode>> it = jsonNode.fields();
 		while (it.hasNext()) {
@@ -312,15 +305,14 @@ public class ClimateServiceController extends Controller {
 			flash(field.getKey(), field.getValue().asText());
 		}
 	}
-	
+
 	public static Result mostRecentlyAddedClimateServices() {
-		
+
 		List<ClimateService> climateServices = new ArrayList<ClimateService>();
 
-		JsonNode climateServicesNode = RESTfulCalls
-				.getAPI(Constants.URL_HOST
-						+ Constants.CMU_BACKEND_PORT
-						+ Constants.GET_MOST_RECENTLY_ADDED_CLIMATE_SERVICES_CALL);
+		JsonNode climateServicesNode = RESTfulCalls.getAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT
+				+ Constants.GET_MOST_RECENTLY_ADDED_CLIMATE_SERVICES_CALL);
 
 		// if no value is returned or error or is not json array
 		if (climateServicesNode == null || climateServicesNode.has("error")
@@ -331,33 +323,19 @@ public class ClimateServiceController extends Controller {
 		// parse the json string into object
 		for (int i = 0; i < climateServicesNode.size(); i++) {
 			JsonNode json = climateServicesNode.path(i);
-			ClimateService newService = new ClimateService();
-			newService.setId(json.get("id").asLong());
-			newService.setName(json.get("name").asText());
-			newService.setPurpose(json.findPath("purpose").asText());
-			//newService.setUrl(json.findPath("url").asText());
-			String name = json.path("name").asText();
-			String pageUrl = Constants.URL_SERVER + Constants.LOCAL_HOST_PORT + "/assets/html/service" + 
-					name.substring(0, 1).toUpperCase() + name.substring(1) + ".html";
-			newService.setUrl(pageUrl);
-			//newService.setCreateTime(json.findPath("createTime").asText());
-			newService.setScenario(json.findPath("scenario").asText());
-			newService.setVersionNo(json.findPath("versionNo").asText());
-			newService.setRootServiceId(json.findPath("rootServiceId").asLong());
+			ClimateService newService = deserializeJsonToClimateService(json);
 			climateServices.add(newService);
 		}
-		
+
 		return ok(mostRecentlyAddedServices.render(climateServices));
 	}
-	
-	
-	
-	
+
 	public static Result mostPopularServices() {
 		List<ClimateService> climateServices = new ArrayList<ClimateService>();
 
-		JsonNode climateServicesNode = RESTfulCalls
-				.getAPI(Constants.URL_HOST + Constants.CMU_BACKEND_PORT + Constants.GET_MOST_POPULAR_CLIMATE_SERVICES_CALL);
+		JsonNode climateServicesNode = RESTfulCalls.getAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT
+				+ Constants.GET_MOST_POPULAR_CLIMATE_SERVICES_CALL);
 
 		// if no value is returned or error or is not json array
 		if (climateServicesNode == null || climateServicesNode.has("error")
@@ -368,33 +346,101 @@ public class ClimateServiceController extends Controller {
 		// parse the json string into object
 		for (int i = 0; i < climateServicesNode.size(); i++) {
 			JsonNode json = climateServicesNode.path(i);
-			ClimateService newService = new ClimateService();
-			newService.setId(json.get("id").asLong());
-			newService.setName(json.get("name").asText());
-			newService.setPurpose(json.findPath("purpose").asText());
-			//newService.setUrl(json.findPath("url").asText());
-			String name = json.path("name").asText();
-			String pageUrl = Constants.URL_SERVER + Constants.LOCAL_HOST_PORT + "/assets/html/service" + 
-					name.substring(0, 1).toUpperCase() + name.substring(1) + ".html";
-			newService.setUrl(pageUrl);
-			//newService.setCreateTime(json.findPath("createTime").asText());
-			newService.setScenario(json.findPath("scenario").asText());
-			newService.setVersionNo(json.findPath("versionNo").asText());
-			newService.setRootServiceId(json.findPath("rootServiceId").asLong());
+			ClimateService newService = deserializeJsonToClimateService(json);
 			climateServices.add(newService);
 		}
-		
+
 		return ok(mostPopularServices.render(climateServices));
 	}
 	
-	public static Result mostRecentlyUsedClimateServices() {
+	public static Result recommendationSummary() {
+		List<ClimateService> climateServices = new ArrayList<ClimateService>();
 		
+		List<Dataset> dataSetsList = new ArrayList<Dataset>();
+		
+		List<User> usersList = new ArrayList<User>();
+		
+		JsonNode usersNode = RESTfulCalls.getAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT
+				+ Constants.GET_ALL_USERS);
+		
+		// if no value is returned or error or is not json array
+		if (usersNode == null || usersNode.has("error")
+				|| !usersNode.isArray()) {
+			return ok(recommendationSummary.render(climateServices, dataSetsList, usersList));
+		}
+
+		
+//		JsonNode dataSetsNode = RESTfulCalls.getAPI(Constants.URL_HOST
+//				+ Constants.CMU_BACKEND_PORT
+//				+ Constants.GET_ALL_DATASETS);
+//		
+//		System.out.println("GET API: " + Constants.URL_HOST
+//				+ Constants.CMU_BACKEND_PORT
+//				+ Constants.GET_ALL_DATASETS);
+
+		JsonNode climateServicesNode = RESTfulCalls.getAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT
+				+ Constants.GET_MOST_POPULAR_CLIMATE_SERVICES_CALL);
+
+		// if no value is returned or error or is not json array
+		if (climateServicesNode == null || climateServicesNode.has("error")
+				|| !climateServicesNode.isArray()) {
+			return ok(recommendationSummary.render(climateServices, dataSetsList, usersList));
+		}
+		
+//		// if no value is returned or error or is not json array
+//		if (dataSetsNode == null || dataSetsNode.has("error")
+//				|| !dataSetsNode.isArray()) {
+//			System.out.println("All oneDatasets format has error!");
+//			return ok(recommendationSummary.render(climateServices, dataSetsList));
+//		}
+
+		// parse the json string into object
+		for (int i = 0; i < climateServicesNode.size(); i++) {
+			JsonNode json = climateServicesNode.path(i);
+			ClimateService newService = deserializeJsonToClimateService(json);
+			climateServices.add(newService);
+		}		
+
+//		// parse the json string into object
+//		for (int i = 0; i < dataSetsNode.size(); i++) {
+//			JsonNode json = dataSetsNode.path(i);
+//			Dataset oneDataset = DatasetController.deserializeJsonToDataSet(json);
+//			dataSetsList.add(oneDataset);
+//		}
+		
+		
+		// parse the json string into object
+		for (int i = 0; i < usersNode.size(); i++) {
+			JsonNode json = usersNode.path(i);
+			User oneUser = new User();
+			oneUser.setId(json.findPath("id").asLong());
+			oneUser.setUserName(json.findPath("userName").asText());
+			oneUser.setPassword(json.findPath("password").asText());
+			oneUser.setFirstName(json.findPath("firstName").asText());
+			oneUser.setMiddleInitial(json.findPath("middleInitial").asText());
+			oneUser.setLastName(json.findPath("lastName").asText());
+			oneUser.setAffiliation(json.findPath("affiliation").asText());
+			oneUser.setEmail(json.findPath("email").asText());
+			oneUser.setResearchFields(json.findPath("researchFields").asText());
+			
+			usersList.add(oneUser);
+		}
+
+		int k = Integer.MAX_VALUE; // Set the first popular K datasets
+		dataSetsList = DatasetController.queryFirstKDatasetsWithoutClimateService("", "", "", "", "", new Date(0), new Date(), k);
+		return ok(recommendationSummary.render(climateServices, dataSetsList, usersList));
+	}
+
+	public static Result mostRecentlyUsedClimateServices() {
+
 		List<ClimateService> climateServices = new ArrayList<ClimateService>();
 
 		JsonNode climateServicesNode = RESTfulCalls.getAPI(Constants.URL_HOST
 				+ Constants.CMU_BACKEND_PORT
 				+ Constants.GET_MOST_RECENTLY_USED_CLIMATE_SERVICES_CALL);
-		
+
 		// if no value is returned or error or is not json array
 		if (climateServicesNode == null || climateServicesNode.has("error")
 				|| !climateServicesNode.isArray()) {
@@ -404,110 +450,182 @@ public class ClimateServiceController extends Controller {
 		// parse the json string into object
 		for (int i = 0; i < climateServicesNode.size(); i++) {
 			JsonNode json = climateServicesNode.path(i);
-			ClimateService newService = new ClimateService();
-			newService.setId(json.get("id").asLong());
-			newService.setName(json.get("name").asText());
-			newService.setPurpose(json.findPath("purpose").asText());
-			
-			String name = json.path("name").asText();
-			String pageUrl = Constants.URL_SERVER + Constants.LOCAL_HOST_PORT + "/assets/html/service" + 
-					name.substring(0, 1).toUpperCase() + name.substring(1) + ".html";
-			newService.setUrl(pageUrl);
-			
-			newService.setScenario(json.findPath("scenario").asText());
-			newService.setVersionNo(json.findPath("versionNo").asText());
-			newService.setRootServiceId(json.findPath("rootServiceId").asLong());
+			ClimateService newService = deserializeJsonToClimateService(json);
 			climateServices.add(newService);
 		}
-		
+
 		return ok(mostRecentlyUsedServices.render(climateServices));
 	}
-	
+
 	public static Result replaceFile() {
-	  	File result =  request().body().asRaw().asFile();
-	  	System.out.println("result: " + request().body().asRaw().asFile());
-	  	
-//	  	String content = readFile(result.getName(), StandardCharsets.UTF_8);
-	  	System.out.println("result body: "+result.toString());
-	  	
-	  	String line = "";
-	    try {
-	    	BufferedReader br = new BufferedReader(new FileReader(result.getAbsolutePath()));
-	        StringBuilder sb = new StringBuilder();
-	        line = br.readLine();
-	        int count = 0;
-	        while (line != null && count < 22) {
-	            sb.append(line);
-	            sb.append("\n");
-	            line = br.readLine();	          
-	            count++;
-	        }
-	        br.close();
-	    } catch (FileNotFoundException e) {
+		File result = request().body().asRaw().asFile();
+		System.out.println("result: " + request().body().asRaw().asFile());
+
+		// String content = readFile(result.getName(), StandardCharsets.UTF_8);
+		System.out.println("result body: " + result.toString());
+
+		String line = "";
+		try {
+			BufferedReader br = new BufferedReader(new FileReader(
+					result.getAbsolutePath()));
+			StringBuilder sb = new StringBuilder();
+			line = br.readLine();
+			int count = 0;
+			while (line != null && count < 22) {
+				sb.append(line);
+				sb.append("\n");
+				line = br.readLine();
+				count++;
+			}
+			br.close();
+		} catch (FileNotFoundException e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
 		} catch (IOException e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
-		} 
-	    
-	    //TEMPOARY SOLUTION : get the fileName from the html page
-	    String tempName = line.substring(24, line.length()-5);		  
-	    String fileName = "public/html/service" + tempName.substring(0, 1).toUpperCase() + tempName.substring(1)+ ".html";
-	    System.out.println("fileName: " + fileName);
-	  	
-	  	//replace the page in the frontend Server
-	  	try {		  		
-		  	Path newPath = Paths.get(fileName);
-		  	Files.move(result.toPath(), newPath, REPLACE_EXISTING);
-	  	} catch (FileNotFoundException e) {
+		}
+
+		// TEMPOARY SOLUTION : get the fileName from the html page
+		String tempName = line.substring(24, line.length() - 5);
+		String fileName = "public/html/service"
+				+ tempName.substring(0, 1).toUpperCase()
+				+ tempName.substring(1) + ".html";
+		System.out.println("fileName: " + fileName);
+
+		// replace the page in the frontend Server
+		try {
+			Path newPath = Paths.get(fileName);
+			Files.move(result.toPath(), newPath, REPLACE_EXISTING);
+		} catch (FileNotFoundException e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
 		} catch (IOException e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
-		} 
-	  	//executeReplace(result);		
-		
-	  	
-	  	return ok("File uploaded");
+		}
+		// executeReplace(result);
+
+		return ok("File uploaded");
 	}
 
-public static void executeReplace(String result) {
-	
-	try {
-		String path = "public/html/se.html";			
-		File theDir = new File("public/html");		
-		
-		// if the directory does not exist, create it
-		if (!theDir.exists()) {
-			System.out.println("creating directory: public/html");
-			boolean create = false;
+	public static void executeReplace(String result) {
 
-			try {
-				theDir.mkdir();
-				create = true;
-			} catch (SecurityException se) {
-				// handle it
-			}
-			if (create) {
-				System.out.println("DIR created");
+		try {
+			String path = "public/html/se.html";
+			File theDir = new File("public/html");
+
+			// if the directory does not exist, create it
+			if (!theDir.exists()) {
+				System.out.println("creating directory: public/html");
+				boolean create = false;
+
+				try {
+					theDir.mkdir();
+					create = true;
+				} catch (SecurityException se) {
+					// handle it
+				}
+				if (create) {
+					System.out.println("DIR created");
+				}
 			}
+
+			File file = new File(path);
+			BufferedWriter output = new BufferedWriter(new FileWriter(file));
+			output.write(result);
+			output.close();
+			System.out.println("Beeping!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+		} catch (FileNotFoundException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
 		}
+	}
+	
+	public static ClimateService deserializeJsonToClimateService(JsonNode json) {
 		
+		ClimateService oneService = new ClimateService();
+		oneService.setName(json.path("name").asText());
+		oneService.setPurpose(json.path("purpose").asText());
+		// URL here is the dynamic page url
+		String name = json.path("name").asText();
+		String url = json.path("url").asText();
+		// Parse NASA URL
+		if (url.contains("/cmac/web")) {
+			oneService.setUrl(url);
+		} else {
+			String pageUrl = Constants.URL_SERVER
+					+ Constants.LOCAL_HOST_PORT + "/assets/html/service"
+					+ name.substring(0, 1).toUpperCase()
+					+ name.substring(1) + ".html";
+			oneService.setUrl(pageUrl);
+		}
+		// newService.setCreateTime(json.path("createTime").asText());
+		oneService.setScenario(json.path("scenario").asText());
+		oneService.setVersionNo(json.path("versionNo").asText());
+		oneService.setRootServiceId(json.path("rootServiceId").asLong());
 		
-		File file = new File(path);
-		BufferedWriter output = new BufferedWriter(new FileWriter(file));			
-		output.write(result);			
-		output.close();
-		System.out.println("Beeping!!!!!!!!!!!!!!!!!!!!!!!!!!!");
-	} catch (FileNotFoundException e) {
-		// TODO Auto-generated catch block
-		e.printStackTrace();
-	} catch (IOException e) {
-		// TODO Auto-generated catch block
-		e.printStackTrace();
-	} 
-}
+		return oneService;
+	}
 	
+	// Get all climate Services
+	public static Result searchClimateServices() {
+		return ok(searchClimateService.render(climateServiceForm));
+	}
+
+
+	public static Result getSearchResult(){
+		Form<ClimateService> cs = climateServiceForm.bindFromRequest();
+		ObjectNode jsonData = Json.newObject();
+		
+		String name = "";
+		String purpose = "";
+		String scenario = "";
+		String url = "";
+		String versionNo = "";
+		
+		try {
+			name = cs.field("Climate Service Name").value();
+			purpose = cs.field("Purpose").value();
+			url = cs.field("Url").value();
+			scenario = cs.field("Scenario").value();
+			versionNo = cs.field("Version Number").value();
+		
+		} catch (IllegalStateException e) {
+			e.printStackTrace();
+			Application.flashMsg(RESTfulCalls
+					.createResponse(ResponseType.CONVERSIONERROR));
+		} catch (Exception e) {
+			e.printStackTrace();
+			Application.flashMsg(RESTfulCalls.createResponse(ResponseType.UNKNOWN));
+		}
+
+		List<ClimateService> response = queryClimateService(name, purpose, url, scenario, versionNo);
+		return ok(climateServiceList.render(response));
+	}
+	
+public static List<ClimateService> queryClimateService(String name, String purpose, String url, String scenario, String versionNo) {
+		
+		List<ClimateService> climateService = new ArrayList<ClimateService>();
+		ObjectMapper mapper = new ObjectMapper();
+		ObjectNode queryJson = mapper.createObjectNode();
+		queryJson.put("name", name);
+		queryJson.put("purpose", purpose);
+		queryJson.put("url", url);
+		queryJson.put("scenario", scenario);
+		queryJson.put("versionNo", versionNo);
+		
+		JsonNode climateServiceNode = RESTfulCalls.postAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT + Constants.QUERY_CLIMATE_SERVICE, queryJson);
+		// parse the json string into object
+		for (int i = 0; i < climateServiceNode.size(); i++) {
+			JsonNode json = climateServiceNode.path(i);
+			ClimateService newClimateService = deserializeJsonToClimateService(json);
+			climateService.add(newClimateService);
+		}
+		return climateService;
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/controllers/DatasetController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/controllers/DatasetController.java b/ApacheCMDA_Frontend_1.0/app/controllers/DatasetController.java
index 6f9d711..9a0d6dd 100644
--- a/ApacheCMDA_Frontend_1.0/app/controllers/DatasetController.java
+++ b/ApacheCMDA_Frontend_1.0/app/controllers/DatasetController.java
@@ -7,6 +7,7 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
+import models.ClimateService;
 import models.Dataset;
 
 import org.joda.time.DateTime;
@@ -36,14 +37,16 @@ public class DatasetController extends Controller {
 		return ok(searchDataSet.render(dataSetForm));
 	}
 	
+	public static Result mostPopularDatasets() {
+		List<Dataset> datasets = queryFirstKDatasetsWithoutClimateService("", "", "", "", "", new Date(0), new Date(), Integer.MAX_VALUE);
+		return ok(dataSetListPopular.render(dataSetForm, datasets));
+	}
+	
 	public static Result showAllDatasets() {
 		List<Dataset> dataSetsList = new ArrayList<Dataset>();
 		JsonNode dataSetsNode = RESTfulCalls.getAPI(Constants.URL_HOST
 				+ Constants.CMU_BACKEND_PORT
 				+ Constants.GET_ALL_DATASETS);
-		System.out.println("GET API: " + Constants.URL_HOST
-				+ Constants.CMU_BACKEND_PORT
-				+ Constants.GET_ALL_DATASETS);
 		// if no value is returned or error or is not json array
 		if (dataSetsNode == null || dataSetsNode.has("error")
 				|| !dataSetsNode.isArray()) {
@@ -129,7 +132,7 @@ public class DatasetController extends Controller {
 		}
 
 		List<Dataset> response = queryDataSet(dataSetName, agency, instrument, physicalVariable, gridDimension, dataSetStartTime, dataSetEndTime);
-		int k = 5;
+		int k = 5; // Set the first popular K datasets
 		List<Dataset> datasetsTopK = queryFirstKDatasets(dataSetName, agency, instrument, physicalVariable, gridDimension, dataSetStartTime, dataSetEndTime, k);
 		return ok(dataSetList.render(response, dataSetForm, datasetsTopK));
 	}
@@ -194,12 +197,55 @@ public static List<Dataset> queryFirstKDatasets(String dataSetName, String agenc
 	for (int i = 0; i < dataSetNode.size(); i++) {
 		JsonNode json = dataSetNode.path(i);
 		Dataset newDataSet = deserializeJsonToDataSet(json);
+		long id = newDataSet.getId();
+		JsonNode climateSetNode = RESTfulCalls.getAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT + Constants.GET_TOP_K_USED_CLIMATE_SERVICES_BY_DATASET_ID + "/" + id);
+		List<ClimateService> climateServices = new ArrayList<ClimateService>();
+		for (int j = 0; j < climateSetNode.size(); j++) {
+			JsonNode json1 = climateSetNode.path(j);
+			ClimateService oneService = ClimateServiceController.deserializeJsonToClimateService(json1);
+			climateServices.add(oneService);
+		}
+		newDataSet.setClimateServices(climateServices);
 		dataset.add(newDataSet);
 	}
 	return dataset;
 }
+	
+	public static List<Dataset> queryFirstKDatasetsWithoutClimateService(String dataSetName, String agency, String instrument, String physicalVariable, String gridDimension, Date dataSetStartTime, Date dataSetEndTime, int k) {
+		
+		List<Dataset> dataset = new ArrayList<Dataset>();
+		ObjectMapper mapper = new ObjectMapper();
+		ObjectNode queryJson = mapper.createObjectNode();
+		queryJson.put("name", dataSetName);
+		queryJson.put("agencyId", agency);
+		queryJson.put("instrument", instrument);
+		queryJson.put("physicalVariable", physicalVariable);
+		queryJson.put("gridDimension", gridDimension);
+		queryJson.put("k", k);
+		if (dataSetEndTime != null) {
+			queryJson.put("dataSetEndTime", dataSetEndTime.getTime());
+		}
+		if (dataSetStartTime != null) {
+			queryJson.put("dataSetStartTime", dataSetStartTime.getTime());
+		}
+		JsonNode dataSetNode = RESTfulCalls.postAPI(Constants.URL_HOST
+				+ Constants.CMU_BACKEND_PORT + Constants.GET_MOST_K_POPULAR_DATASETS_CALL, queryJson);
+		if (dataSetNode == null || dataSetNode.has("error")
+				|| !dataSetNode.isArray()) {
+			return dataset;
+		}
+	
+		// parse the json string into object
+		for (int i = 0; i < dataSetNode.size(); i++) {
+			JsonNode json = dataSetNode.path(i);
+			Dataset newDataSet = deserializeJsonToDataSet(json);
+			dataset.add(newDataSet);
+		}
+		return dataset;
+	}
 
-	private static Dataset deserializeJsonToDataSet(JsonNode json) {
+	public static Dataset deserializeJsonToDataSet(JsonNode json) {
 		Dataset newDataSet = new Dataset();
 		newDataSet.setId(json.get("id").asLong());
 		newDataSet.setName(json.get("name").asText());
@@ -212,14 +258,14 @@ public static List<Dataset> queryFirstKDatasets(String dataSetName, String agenc
 		newDataSet.setSource(json.get("source").asText());
 		newDataSet.setStatus(json.get("status").asText());
 		newDataSet.setResponsiblePerson(json.get("responsiblePerson").asText());
-	//	dataset.setComments(json.get(""));
 		newDataSet.setDataSourceNameinWebInterface(json.get("dataSourceNameinWebInterface").asText());
-	//	Console.print("aaa"+dataset.getDataSourceName());
 		newDataSet.setVariableNameInWebInterface(json.get("variableNameInWebInterface").asText());
 		newDataSet.setDataSourceInputParameterToCallScienceApplicationCode(json.get("dataSourceInputParameterToCallScienceApplicationCode").asText());
 		newDataSet.setVariableNameInputParameterToCallScienceApplicationCode(json.get("variableNameInputParameterToCallScienceApplicationCode").asText());
-		String startTime = json.findPath("startTime").asText();
-		String endTime = json.findPath("endTime").asText();
+		newDataSet.setAgencyURL(json.findPath("agencyURL").asText());
+		newDataSet.setInstrumentURL(json.findPath("instrument").findPath("instrumentURL").asText());
+		String startTime = json.get("startTime").asText();
+		String endTime = json.get("endTime").asText();
 		Date tmpStartTime = null;
 		Date tmpEndTime = null;
 		
@@ -230,6 +276,7 @@ public static List<Dataset> queryFirstKDatasets(String dataSetName, String agenc
 				newDataSet.setStartTime(new SimpleDateFormat("YYYY-MM").format(tmpStartTime));
 			}
 	    } catch (ParseException e){	    
+	    	System.out.println(e);
 	    }
 		
 		try {
@@ -239,7 +286,7 @@ public static List<Dataset> queryFirstKDatasets(String dataSetName, String agenc
 				newDataSet.setEndTime(new SimpleDateFormat("YYYY-MM").format(tmpEndTime));
 			}
 	    } catch (ParseException e){	    
-	    	
+	    	System.out.println(e);
 	    }
 		
 		DateTime dateTimeFrom = new DateTime(tmpStartTime);  
@@ -255,4 +302,5 @@ public static List<Dataset> queryFirstKDatasets(String dataSetName, String agenc
 		
 		return newDataSet;
 	}
+	
 }

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/controllers/DatasetLogController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/controllers/DatasetLogController.java b/ApacheCMDA_Frontend_1.0/app/controllers/DatasetLogController.java
index 7906d85..4839883 100644
--- a/ApacheCMDA_Frontend_1.0/app/controllers/DatasetLogController.java
+++ b/ApacheCMDA_Frontend_1.0/app/controllers/DatasetLogController.java
@@ -59,7 +59,7 @@ public class DatasetLogController extends Controller {
 			tmpTime = (new SimpleDateFormat("MMM dd, yyyy hh:mm:ss a")).parse(datasetStudyStartTime);
 			
 			if (tmpTime != null) {
-				newDatasetLog.setDatasetStudyStartTime(new SimpleDateFormat("YYYYMM").format(tmpTime));
+				newDatasetLog.setDatasetStudyStartTime(new SimpleDateFormat("YYYY-MM").format(tmpTime));
 			}
 	    } catch (ParseException e){	    
 //	    	e.printStackTrace();
@@ -69,7 +69,7 @@ public class DatasetLogController extends Controller {
 			tmpTime = (new SimpleDateFormat("MMM dd, yyyy hh:mm:ss a")).parse(datasetStudyEndTime);
 			
 			if (tmpTime != null) {
-				newDatasetLog.setDatasetStudyEndTime(new SimpleDateFormat("YYYYMM").format(tmpTime));
+				newDatasetLog.setDatasetStudyEndTime(new SimpleDateFormat("YYYY-MM").format(tmpTime));
 			}
 	    } catch (ParseException e){	    
 //	    	e.printStackTrace();

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/controllers/ServiceExecutionLogController.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/controllers/ServiceExecutionLogController.java b/ApacheCMDA_Frontend_1.0/app/controllers/ServiceExecutionLogController.java
index 847b0f9..163146f 100644
--- a/ApacheCMDA_Frontend_1.0/app/controllers/ServiceExecutionLogController.java
+++ b/ApacheCMDA_Frontend_1.0/app/controllers/ServiceExecutionLogController.java
@@ -374,7 +374,8 @@ public class ServiceExecutionLogController extends Controller {
 		ServiceExecutionLog newServiceLog = new ServiceExecutionLog();
 		newServiceLog.setId(json.get("id").asLong());
 		newServiceLog.setServiceId(json.get("climateService").get("id").asLong());
-		newServiceLog.setServiceName(json.get("climateService").get("name").asText());
+		String serviceName = json.get("climateService").get("name").asText();
+		newServiceLog.setServiceName(serviceName);
 		newServiceLog.setPurpose(json.get("purpose").asText());
 		newServiceLog.setUserName(json.get("user").get("firstName").asText()
 				+ " " + json.get("user").get("lastName").asText());
@@ -407,7 +408,7 @@ public class ServiceExecutionLogController extends Controller {
 			tmpTime = (new SimpleDateFormat("MMM dd, yyyy hh:mm:ss a")).parse(datasetStudyStartTime);
 			
 			if (tmpTime != null) {
-				newServiceLog.setDataSetStartTime(new SimpleDateFormat("YYYYMM").format(tmpTime));
+				newServiceLog.setDataSetStartTime(new SimpleDateFormat("YYYY-MM").format(tmpTime));
 			}
 	    } catch (ParseException e){	    
 //	    	e.printStackTrace();
@@ -417,13 +418,20 @@ public class ServiceExecutionLogController extends Controller {
 			tmpTime = (new SimpleDateFormat("MMM dd, yyyy hh:mm:ss a")).parse(datasetStudyEndTime);
 			
 			if (tmpTime != null) {
-				newServiceLog.setDataSetEndTime(new SimpleDateFormat("YYYYMM").format(tmpTime));
+				newServiceLog.setDataSetEndTime(new SimpleDateFormat("YYYY-MM").format(tmpTime));
 			}
 	    } catch (ParseException e){	    
 //	    	e.printStackTrace();
 	    }
 		
 		newServiceLog.setDatasetLogId(json.findPath("datasetLogId").asText());
+		if(json.get("url") != null) {
+			String pageUrl = Constants.URL_SERVER
+					+ Constants.LOCAL_HOST_PORT + "/assets/html/service"
+					+ serviceName.substring(0, 1).toUpperCase()
+					+ serviceName.substring(1) + ".html" + json.get("url").asText();
+			newServiceLog.setUrl(pageUrl);
+		}
 		
 		return newServiceLog;
 	}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/models/Dataset.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/models/Dataset.java b/ApacheCMDA_Frontend_1.0/app/models/Dataset.java
index f8f4482..d72cfc3 100644
--- a/ApacheCMDA_Frontend_1.0/app/models/Dataset.java
+++ b/ApacheCMDA_Frontend_1.0/app/models/Dataset.java
@@ -44,6 +44,9 @@ public class Dataset {
 	private String startTime;
 	private String endTime;
 	private String duration;
+	private String agencyURL;
+	private String instrumentURL;
+	private List<ClimateService> climateServices;
 
 	public Dataset() {
 	}
@@ -56,7 +59,7 @@ public class Dataset {
 			String responsiblePerson, String variableNameInWebInterface,
 			String dataSourceInputParameterToCallScienceApplicationCode,
 			String variableNameInputParameterToCallScienceApplicationCode,
-			String comment, String duration) {
+			String comment, String duration, String agencyURL, String instrumentURL, List<ClimateService> climateServices) {
 		super();
 		this.name = name;
 		this.dataSourceNameinWebInterface = dataSourceNameinWebInterface;
@@ -77,6 +80,33 @@ public class Dataset {
 		this.variableNameInputParameterToCallScienceApplicationCode = variableNameInputParameterToCallScienceApplicationCode;
 		this.comment = comment;
 		this.duration = duration;
+		this.agencyURL = agencyURL;
+		this.instrumentURL = instrumentURL;
+		this.climateServices = climateServices;
+	}
+
+	public List<ClimateService> getClimateServices() {
+		return climateServices;
+	}
+
+	public void setClimateServices(List<ClimateService> climateServices) {
+		this.climateServices = climateServices;
+	}
+
+	public String getInstrumentURL() {
+		return instrumentURL;
+	}
+
+	public void setInstrumentURL(String instrumentURL) {
+		this.instrumentURL = instrumentURL;
+	}
+
+	public String getAgencyURL() {
+		return agencyURL;
+	}
+
+	public void setAgencyURL(String agencyURL) {
+		this.agencyURL = agencyURL;
 	}
 
 	public String getDuration() {

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/models/Instrument.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/models/Instrument.java b/ApacheCMDA_Frontend_1.0/app/models/Instrument.java
index 71a0094..90ac4c1 100644
--- a/ApacheCMDA_Frontend_1.0/app/models/Instrument.java
+++ b/ApacheCMDA_Frontend_1.0/app/models/Instrument.java
@@ -15,6 +15,7 @@ public class Instrument {
 	private String name;
 	private String description;
 	private Date launchDate;
+	private String instrumentURL;
 	
 	public Instrument() {
 	}
@@ -25,6 +26,14 @@ public class Instrument {
 		this.description = description;
 		this.launchDate = launchDate;
 	}
+	
+	public String getInstrumentURL() {
+		return instrumentURL;
+	}
+
+	public void setInstrumentURL(String instrumentURL) {
+		this.instrumentURL = instrumentURL;
+	}
 
 	public long getId() {
 		return id;

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/models/ServiceExecutionLog.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/models/ServiceExecutionLog.java b/ApacheCMDA_Frontend_1.0/app/models/ServiceExecutionLog.java
index aff9e87..fa08477 100644
--- a/ApacheCMDA_Frontend_1.0/app/models/ServiceExecutionLog.java
+++ b/ApacheCMDA_Frontend_1.0/app/models/ServiceExecutionLog.java
@@ -15,6 +15,8 @@ public class ServiceExecutionLog {
 	private String serviceName;
 	private String dataSetStartTime;
 	private String dataSetEndTime;
+	private String url;
+
 
 	public long getId() {
 		return id;
@@ -55,6 +57,10 @@ public class ServiceExecutionLog {
 	public String getDataUrl() {
 		return dataUrl;
 	}
+	
+	public String getUrl() {
+		return url;
+	}
 
 	public void setId(long id) {
 		this.id = id;
@@ -120,6 +126,10 @@ public class ServiceExecutionLog {
 		this.dataSetEndTime = dataSetEndTime;
 	}
 	
+	public void setUrl(String url) {
+		this.url = url;
+	}
+	
 	@Override
 	public String toString() {
 		return "ServiceExecutionLog [id=" + id + ", serviceId="
@@ -127,6 +137,7 @@ public class ServiceExecutionLog {
 				+ serviceConfigurationId + ", purpose=" + purpose
 				+ ", executionStartTime=" + executionStartTime
 				+ ", executionEndTime=" + executionEndTime + ", plotUrl="
-				+ plotUrl + ", dataUrl=" + dataUrl + "]";
+				+ plotUrl + ", dataUrl=" + dataUrl + ", url=" + url 
+				+ "]";
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/utils/Constants.java
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/utils/Constants.java b/ApacheCMDA_Frontend_1.0/app/utils/Constants.java
index 2ed9d92..2a36d81 100644
--- a/ApacheCMDA_Frontend_1.0/app/utils/Constants.java
+++ b/ApacheCMDA_Frontend_1.0/app/utils/Constants.java
@@ -25,9 +25,11 @@ public class Constants {
 	
 	public static final String GET_MOST_RECENTLY_USED_CLIMATE_SERVICES_CALL = "/climateService/getAllMostRecentClimateServicesByLatestAccessTime/json";
 	public static final String GET_CLIMATE_SERVICES_CALL = "/climateService/getAllClimateServices/json";
+	public static final String GET_TOP_K_USED_CLIMATE_SERVICES_BY_DATASET_ID = "/climateService/getTopKUsedClimateServicesByDatasetId";
 	
 	// climate service page
 	public static final String SAVE_CLIMATE_SERVICE_PAGE = "/climateService/savePage";
+	public static final String QUERY_CLIMATE_SERVICE = "/climateService/queryClimateService";
 	
 	// user
 	public static final String IS_USER_VALID = "/users/isUserValid";
@@ -79,5 +81,8 @@ public class Constants {
 	public static final String CONFIG_ITEM =	"/serviceConfigurationItem";
 	public static final String GET_CONFIG_ITEMS_BY_CONFIG= "/serviceConfigurationItemByServiceConfig";
 	
+	//Analytics
+	public static final String GET_DATASET_AND_USER = "/analytics/getAllDatasetAndUserWithCount/json";
+	
 	
 }

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/aboutUs.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/aboutUs.scala.html b/ApacheCMDA_Frontend_1.0/app/views/aboutUs.scala.html
index ba88ee2..320844a 100644
--- a/ApacheCMDA_Frontend_1.0/app/views/aboutUs.scala.html
+++ b/ApacheCMDA_Frontend_1.0/app/views/aboutUs.scala.html
@@ -11,8 +11,11 @@
    <p>Seungwon Lee</p>
    <p>Lei Pan</p>
    <h3><strong>Current Contributors</strong></h3>
-   <p>Xing Wei</p>
    <p>Wei Wang</p>
+   <p>Qihao Bao</p>
+   <p>Ruoxiao Wang</p>
+   <p>Ming Qi</p>
+   <p>Xing Wei</p>
    <p>Chris Lee</p>
    <p>Rao Li</p>
    <p>Chenran Gong</p>
@@ -21,7 +24,6 @@
    <p>Yichen Liu</p>
    <p>Edward Huang</p>
    <p>Zhiyu Lin</p>
-   <p>Ming Qi</p>
    <p>Jian Jiao</p>
    <p>Juanchen Li</p>
    <h3><strong>Former Contributors</strong></h3>

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/allClimateServices.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/allClimateServices.scala.html b/ApacheCMDA_Frontend_1.0/app/views/allClimateServices.scala.html
index 547e8d1..6dabf7f 100644
--- a/ApacheCMDA_Frontend_1.0/app/views/allClimateServices.scala.html
+++ b/ApacheCMDA_Frontend_1.0/app/views/allClimateServices.scala.html
@@ -11,10 +11,10 @@
 		<th style = "vertical-align: middle;" class="col-md-4">Purpose</th>
 		<th style = "vertical-align: middle;" class="col-md-4">URL</th>
 		<th style = "vertical-align: middle;" class="col-md-3">Scenario</th>
-		<th style = "vertical-align: middle;" class="col-md-3">Version_No</th>
+		<th style = "vertical-align: middle;" class="col-md-3">Version No</th>
 		<th style = "vertical-align: middle;" class="col-md-3">Root Service_Id</th>
 		 @if(true){
-			<th style = "vertical-align: middle;" class="col-md-3">Operation</th> 
+			<th style = "vertical-align: middle;" class="col-md-2">Operation</th> 
 	     } 
 	     <th style = "vertical-align: middle;" class="col-md-2">Operation</th>
 	</tr>
@@ -27,14 +27,21 @@
 		<td><span class="@climateService.getName() editable" data-name='purpose'>
 				@{
 					if (climateService.getPurpose().length > 5 ) {
-						climateService.getPurpose().substring(0,5);
+						climateService.getPurpose().substring(0,5) + "...";
 					}else {
 						climateService.getPurpose();
 					}
-				} ... </span></td>
+				}  </span></td>
 		
 		<td><span class="@climateService.getName() editable" id = "url" data-name='url'>
-				<a href = "@climateService.getUrl()">@climateService.getUrl()</a></span></td>
+				<a href = "@climateService.getUrl()">
+				@{
+					if (climateService.getUrl().length > 5 ) {
+						"..." + climateService.getUrl().substring(31);
+					}else {
+						climateService.getUrl();
+					}
+				}</a></span></td>
 				
 		<td><span class="@climateService.getName() editable" data-name='scenario'>
 				@climateService.getScenario() </span></td>

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/allDatasets.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/allDatasets.scala.html b/ApacheCMDA_Frontend_1.0/app/views/allDatasets.scala.html
index 8976c6b..50649d4 100644
--- a/ApacheCMDA_Frontend_1.0/app/views/allDatasets.scala.html
+++ b/ApacheCMDA_Frontend_1.0/app/views/allDatasets.scala.html
@@ -12,7 +12,7 @@
 		-->
 		<th style = "vertical-align: top;" class="col-md-2">Dataset Name</th>
 		<th style = "vertical-align: top;" class="col-md-1">Agency</th>
-		<th style = "vertical-align: top;" class="col-md-1">Instrument</th>
+		<th style = "vertical-align: top;" class="col-md-1">Instrument/Model Experiment</th>
 		<th style = "vertical-align: top;" class="col-md-2">Physical variable</th>
 		<th style = "vertical-align: top;" class="col-md-1">Variable short name</th>
 		<th style = "vertical-align: top;" class="col-md-1">Units</th>

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/climateServiceList.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/climateServiceList.scala.html b/ApacheCMDA_Frontend_1.0/app/views/climateServiceList.scala.html
new file mode 100644
index 0000000..f871090
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/app/views/climateServiceList.scala.html
@@ -0,0 +1,62 @@
+@(climateServices: List[ClimateService])
+@import helper._
+
+@main("All Climate Services") {
+
+    <h1>@climateServices.size() Climate Services</h1>
+		<table class="table table-striped table-bordered table-condensed ex2 tablesorter" id = "csTable">
+	<thead>
+	<tr class="text-center">
+		<th style = "vertical-align: middle;" class="col-md-2">Climate Service Name</th>
+		<th style = "vertical-align: middle;" class="col-md-4">Purpose</th>
+		<th style = "vertical-align: middle;" class="col-md-4">URL</th>
+		<th style = "vertical-align: middle;" class="col-md-3">Scenario</th>
+		<th style = "vertical-align: middle;" class="col-md-3">Version No</th>
+		<th style = "vertical-align: middle;" class="col-md-3">Root Service_Id</th>
+		 @if(true){
+			<th style = "vertical-align: middle;" class="col-md-2">Operation</th> 
+	     } 
+	     <th style = "vertical-align: middle;" class="col-md-2">Operation</th>
+	</tr>
+	</thead>
+	<tbody>
+	@for(climateService <- climateServices) {
+	<tr>
+		<td><a href = "@climateService.getUrl()">@climateService.getName()</a></td>
+
+		<td><span class="@climateService.getName() editable" data-name='purpose'>
+				@{
+					if (climateService.getPurpose().length > 5 ) {
+						climateService.getPurpose().substring(0,5) + "...";
+					}else {
+						climateService.getPurpose();
+					}
+				}  </span></td>
+		
+		<td><span class="@climateService.getName() editable" id = "url" data-name='url'>
+				<a href = "@climateService.getUrl()">
+				@{
+					if (climateService.getUrl().length > 5 ) {
+						"..." + climateService.getUrl().substring(31);
+					}else {
+						climateService.getUrl();
+					}
+				}</a></span></td>
+				
+		<td><span class="@climateService.getName() editable" data-name='scenario'>
+				@climateService.getScenario() </span></td>
+				
+		<td><span class="@climateService.getName() editable" data-name='versionNo'>
+				@climateService.getVersionNo() </span></td>
+				
+		<td><span class="@climateService.getName() editable" data-name='rootServiceId'>
+				@climateService.getRootServiceId() </span></td>
+				
+		<td><input type="file" class="btn btn-info" id ="upload @climateService.getName()" ></button></td>
+		<td><button type="button" class="btn btn-danger" id ="doReplace"  onclick="Javascript:replaceFile('upload '+'@climateService.getName()')" >Execute</button></td>
+	
+	</tr>
+	}
+	</tbody>
+    </table>
+}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/dataSetList.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/dataSetList.scala.html b/ApacheCMDA_Frontend_1.0/app/views/dataSetList.scala.html
index 83aeb18..078c6c8 100644
--- a/ApacheCMDA_Frontend_1.0/app/views/dataSetList.scala.html
+++ b/ApacheCMDA_Frontend_1.0/app/views/dataSetList.scala.html
@@ -72,15 +72,15 @@
 								<div class="well col-lg-offset-4 col-lg-4 col-sm-offset-3 col-sm-6">
 									<div class="text-center">
 										<img class="card-img-top" style=" width:60%;"
-											src='@routes.Assets.at("images/data.png")' >
+											src='@routes.Assets.at("images/giphy.gif")' >
 									</div>
 									<div class="card-block text-center">
 										<h4 class="card-title">@dataSet.getName()</h4>
 										<p class="card-text text-muted">A data set (or dataset) is a collection of data.</p>
 									</div>
 									<ul class="list-group list-group-flush">
-										<li class="list-group-item"><strong>Agency:</strong> <code>@dataSet.getAgencyId()</code></li>
-										<li class="list-group-item"><strong>Instrument:</strong> <code>@dataSet.getInstrument()</code></li>
+										<li class="list-group-item"><strong>Agency:</strong> <a href="@dataSet.getAgencyURL()" target="_blank"><code><u>@dataSet.getAgencyId()</u></code></a></li>
+										<li class="list-group-item"><strong>Instrument/Model Experiment:</strong> <a href="@dataSet.getInstrumentURL()" target="_blank"><code><u>@dataSet.getInstrument()</u></code></a></li>
 										<li class="list-group-item"><strong>Units:</strong> <code>@dataSet.getUnits()</code></li>
 										<li class="list-group-item"><strong>Start Time:</strong> <code>@dataSet.getStartTime()</code></li>
 										<li class="list-group-item"><strong>End Time:</strong> <code>@dataSet.getEndTime()</code></li>
@@ -102,15 +102,20 @@
 									</div>
 									
 									<div class="row">
+									@for(climateService <- dataSet.getClimateServices()) {
 									  <div class="col-md-6">
 									    <div class="thumbnail">
+									    <a href="@climateService.getUrl()">
 									      <img src='@routes.Assets.at("images/github.png")' >
+								      	</a>
 									      <div class="caption">
-									        <h5>NASA</h5>				        
-									        <p><a href="#" class="btn btn-primary" role="button">Go</a> <a href="#" class="btn btn-default" role="button">Ignore</a></p>
+									        <h5>@climateService.getName()</h5>				        
+									        
 									      </div>				      
 									    </div>
 									  </div>
+									  }
+									  <!--  
 									  <div class="col-md-6">
 									    <div class="thumbnail">
 									      <img src='@routes.Assets.at("images/bug.png")' >
@@ -120,6 +125,7 @@
 									      </div>				      
 									    </div>
 									  </div>
+									  -->
 									</div>
 									
 								</div>
@@ -162,7 +168,7 @@
 		-->
 		<th style = "vertical-align: top;" class="col-md-2">Dataset Name</th>
 		<th style = "vertical-align: top;" class="col-md-1">Agency</th>
-		<th style = "vertical-align: top;" class="col-md-1">Instrument</th>
+		<th style = "vertical-align: top;" class="col-md-1">Instrument/Model Experiment</th>
 		<th style = "vertical-align: top;" class="col-md-2">Physical variable</th>
 		<th style = "vertical-align: top;" class="col-md-1">Variable short name</th>
 		<th style = "vertical-align: top;" class="col-md-1">Units</th>

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/dataSetListPopular.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/dataSetListPopular.scala.html b/ApacheCMDA_Frontend_1.0/app/views/dataSetListPopular.scala.html
new file mode 100644
index 0000000..9df2a3d
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/app/views/dataSetListPopular.scala.html
@@ -0,0 +1,68 @@
+@(dataSetForm: play.data.Form[Dataset], dataSets: List[Dataset])
+
+@import helper._
+@import java.math.BigInteger;var k=1;var n = 0;
+
+@scripts = {
+	<script src='@routes.Assets.at("javascripts/edit_button.js")'></script>
+	<script type="text/javascript">
+	$(document).ready(function(){
+		//alert($("#url").text());
+	});
+	</script>
+}
+
+@main("Dataset List", scripts) { 
+	 
+    <h1>Datasets List</h1>
+    <h2>@dataSets.size() Datasets Found</h2>
+<div style="overflow-y:scroll">
+		<table class="table table-striped table-bordered table-condensed tablesorter" id ="myTable">
+		<thead>
+	<tr >
+		<!-- 
+		<th style = "vertical-align: top;" class="col-md-1 header">Id</th>
+		-->
+		<th style = "vertical-align: top;" class="col-md-2">Dataset Name</th>
+		<th style = "vertical-align: top;" class="col-md-1">Agency</th>
+		<th style = "vertical-align: top;" class="col-md-1">Instrument/Model Experiment</th>
+		<th style = "vertical-align: top;" class="col-md-2">Physical variable</th>
+		<th style = "vertical-align: top;" class="col-md-1">Variable short name</th>
+		<th style = "vertical-align: top;" class="col-md-1">Units</th>
+		<th style = "vertical-align: top;" class="col-md-1">Grid Dimension</th>
+		
+		<th style = "vertical-align: top;" class="col-md-2">Variable Name in Web Interface</th>
+		<th style = "vertical-align: top;" class="col-md-1">Data Source Input Parameter</th>
+		
+		<th style = "vertical-align: top;" class="col-md-1">Dataset Start Time</th>
+		<th style = "vertical-align: top;"class="col-md-1">Dataset End Time</th>
+		<th style = "vertical-align: top;"class="col-md-1">Duration</th>
+
+	</tr>
+	</thead>
+	<tbody>
+@for(dataSet <- dataSets){
+							<tr>
+								<!-- 
+								<td><font size="2">@dataSet.getId()</font></td>
+								-->
+								<td><font size="2">@dataSet.getName()</font></td>
+								<td><font size="2">@dataSet.getAgencyId()</font></td>
+								<td><font size="2">@dataSet.getInstrument()</font></td>
+								<td><font size="2">@dataSet.getPhysicalVariable()</font></td>
+								<td><font size="2">@dataSet.getCMIP5VarName()</font></td>
+								<td><font size="2">@dataSet.getUnits()</font></td>
+								<td><font size="2">@dataSet.getGridDimension()</font></td>
+								<td><font size="2">@dataSet.getVariableNameInWebInterface()</font></td>
+								<td><font size="2">@dataSet.getDataSourceInputParameterToCallScienceApplicationCode()</font></td>
+								<td><font size="2">@dataSet.getStartTime()</font></td>
+								<td><font size="2">@dataSet.getEndTime()</font></td>
+								<td><font size="2">@dataSet.getDuration()</font></td>
+							</tr>
+							}
+
+	
+	</tbody>
+    </table>
+    </div>
+}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/header.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/header.scala.html b/ApacheCMDA_Frontend_1.0/app/views/header.scala.html
index c67371d..3446fdd 100644
--- a/ApacheCMDA_Frontend_1.0/app/views/header.scala.html
+++ b/ApacheCMDA_Frontend_1.0/app/views/header.scala.html
@@ -10,8 +10,8 @@
 				</button>
 				<a class="navbar-brand" style="padding-bottom: 0;" href="/">
 					<div>
-					<img src='@routes.Assets.at("images/NASA_JPL_logo.png")' style="height: 30px; width: 180px;">&nbsp&nbsp
-					<img src='@routes.Assets.at("images/logo.png")' style="height: 15px; width: 200px;">
+					<img src='@routes.Assets.at("images/NASA_JPL_logo.png")' style="height: 24px; width: 144px;">
+					<img src='@routes.Assets.at("images/logo.png")' style="height: 12px; width: 160px;">
 					</div>
 				</a>
 			</div>
@@ -19,6 +19,14 @@
 				<ul class="nav navbar-nav navbar-right">
 					
 					<li class="dropdown">
+						<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="text-danger">Recommendation</span><b class="caret"></b></a>
+						<ul class="dropdown-menu">
+							<li><a href="@routes.ClimateServiceController.recommendationSummary()">Summary</a></li>
+							
+						</ul>				
+					</li>
+					
+					<li class="dropdown">
 						<a href="#" class="dropdown-toggle" data-toggle="dropdown">Web Service<b class="caret"></b></a>
 						<ul class="dropdown-menu">
 							<li><a href="@routes.ClimateServiceController.mostRecentlyAddedClimateServices()">Most Recently Added</a></li>
@@ -28,14 +36,14 @@
 							@if(true) {
 								<li><a href="@routes.ClimateServiceController.addAClimateService()">Register A Service</a></li>
 							}
-							<li><a>Search Service</a></li>
+							<li><a href="@routes.ClimateServiceController.searchClimateServices()">Search Service</a></li>
 						</ul>				
 					</li>
 					
 					<li class="dropdown">
 						<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dataset<b class="caret"></b></a>
 						<ul class="dropdown-menu">
-							<li><a>Most Popular</a></li>
+							<li><a href="@routes.DatasetController.mostPopularDatasets()">Most Popular</a></li>
 							<li><a href="@routes.DatasetController.showAllDatasets()">Dataset List</a></li>
 							@if(true) {
 								<li><a href="#">Register A Dataset</a></li>
@@ -50,7 +58,7 @@
 							<li><a href="@routes.ServiceExecutionLogController.getServiceLog">Service Execution Log</a></li>
 							<li><a href="@routes.ServiceExecutionLogController.searchServiceLog">Search Service Log</a></li>
 							<li><a href="@routes.DatasetLogController.getAllDatasetLogs">Dataset Log</a></li>
-							<li><a href="@routes.AnalyticsController.getRecommend">Semantic Service Analytics</a></li>
+							<li><a href="@routes.AnalyticsController.getKnowledgeGraph">Knowledge Graph</a></li>
 							<li><a href="@routes.AnalyticsController.getDatasetRecommend">Semantic Dataset Analytics</a></li>
 							<li><a href="@routes.AnalyticsController.getScientistRecommend">User Analytics</a></li>
 							<li><a href="@routes.AnalyticsController.getLogGraph">Service Execution Log Analytics</a></li>



[4/5] incubator-cmda git commit: Add KnowledgeGraph page and recommendationSummary page. Update backend models and create new APIs to support new features. Add KnowledgCard in Dataset search result page.

Posted by xi...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/knowledgeGraph.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/knowledgeGraph.scala.html b/ApacheCMDA_Frontend_1.0/app/views/knowledgeGraph.scala.html
new file mode 100644
index 0000000..fe6a223
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/app/views/knowledgeGraph.scala.html
@@ -0,0 +1,320 @@
+@(jsonData: String)
+@import helper._
+
+@scripts = {
+	<link rel="stylesheet" href='@routes.Assets.at("stylesheets/vis.css")'>
+	<style type="text/css">
+	        html, body {
+	            font: 10pt arial;
+	          }
+	        #mynetwork {
+	            width: 600px;
+	            height: 600px;
+	            border: 1px solid lightgray;
+	        }
+	        #loadingBar {
+	            position:absolute;
+	            
+	            width: 610px;
+	            height: 610px;
+	            background-color:rgba(200,200,200,0.8);
+	            -webkit-transition: all 0.5s ease;
+	            -moz-transition: all 0.5s ease;
+	            -ms-transition: all 0.5s ease;
+	            -o-transition: all 0.5s ease;
+	            transition: all 0.5s ease;
+	            opacity:1;
+	        }
+	        #wrapper {
+	            position:relative;
+	            width:900px;
+	            height:900px;
+	        }
+	
+	        #text {
+	            position:absolute;
+	            top:0px;
+	            left:530px;
+	            width:30px;
+	            height:50px;
+	            margin:auto auto auto auto;
+	            font-size:22px;
+	            color: #000000;
+	        }
+	
+	
+	        div.outerBorder {
+	            position:relative;
+	            top:300px;
+	            width:600px;
+	            height:44px;
+	            margin:auto auto auto auto;
+	            border:8px solid rgba(0,0,0,0.1);
+	            background: rgb(252,252,252); /* Old browsers */
+	            background: -moz-linear-gradient(top,  rgba(252,252,252,1) 0%, rgba(237,237,237,1) 100%); /* FF3.6+ */
+	            background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(252,252,252,1)), color-stop(100%,rgba(237,237,237,1))); /* Chrome,Safari4+ */
+	            background: -webkit-linear-gradient(top,  rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* Chrome10+,Safari5.1+ */
+	            background: -o-linear-gradient(top,  rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* Opera 11.10+ */
+	            background: -ms-linear-gradient(top,  rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* IE10+ */
+	            background: linear-gradient(to bottom,  rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* W3C */
+	            filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfcfc', endColorstr='#ededed',GradientType=0 ); /* IE6-9 */
+	            border-radius:72px;
+	            box-shadow: 0px 0px 10px rgba(0,0,0,0.2);
+	        }
+	
+	        #border {
+	            position:absolute;
+	            top:2px;
+	            left:2px;
+	            width:500px;
+	            height:23px;
+	            margin:auto auto auto auto;
+	            box-shadow: 0px 0px 4px rgba(0,0,0,0.2);
+	            border-radius:10px;
+	        }
+	
+	        #bar {
+	            position:absolute;
+	            
+	            width:10px;
+	            height:20px;
+	            margin:auto auto auto auto;
+	            border-radius:11px;
+	            border:2px solid rgba(30,30,30,0.05);
+	            background: rgb(153, 255, 255); /* Old browsers */
+	            box-shadow: 2px 2px 4px rgba(0,0,0,0.4);
+	        }
+	
+	        #config {            
+	            
+	            width: 400px;
+	            height: 600px;
+	
+	        }
+	        #config input {
+	            display: inline-block;
+	        }
+	        #config input.vis-configuration.vis-config-rangeinput {
+	            height: 15px;
+	        }
+	        #config button, input, select, textarea {
+	            line-height: 100%;
+	        }
+	</style>
+	
+	<script type="text/javascript" src='@routes.Assets.at("javascripts/exampleUtil.js")'></script>
+	<script type="text/javascript" src='@routes.Assets.at("javascripts/vis.js")'></script>
+	<script type="text/javascript">
+	$(document).ready(function() {  
+	    $("#panel").hide(); 
+	    $("#config").hide();
+	    
+	    draw();
+	  })
+
+	    var nodes = null;
+	    var edges = null;
+	    var network = null;
+
+	    var visConfig = 1;
+
+	    function hideConfig() {
+	        if (visConfig == 0) {
+	            $("#config").hide();
+	            visConfig =1;
+	        }else {
+	            $("#config").show();
+	            visConfig =0;
+	        }
+	    }
+
+	    function draw() {
+	    	console.log("draw");
+	      // create people.
+	      // value corresponds with the age of the person
+	      var jsonString = $('#jsonData').text();
+	      var test = jsonString;
+	      
+	      //test = JSON.stringify(test);
+	      console.log("test: " + test);
+	      test = JSON.parse(test);
+	      var nodes = test.nodes;
+	      console.log("nodes: " + nodes);
+	      var edges = test.edges;
+	      console.log("edges: " + edges); 
+
+	      // Instantiate our network object.
+	      var container = document.getElementById('mynetwork');
+	      var data = {
+	        nodes: nodes,
+	        edges: edges
+	      };
+	      var options = {
+   		  nodes: {
+   			    color: {
+   			      highlight: {
+   			        border: "red",
+   			        background: "pink"
+   			      }
+   			    },
+   			    scaling: {
+   			      min: 12
+   			    },
+   			    shadow: {
+   			      enabled: true,
+   			      size: 8
+   			    },
+	   			 font: {
+	   		      color: "rgba(52,52,52,1)",
+	   		      size: 10,
+	   		      strokeWidth: 4
+	   		    },
+   			    shape: "dot",
+   			    shapeProperties: {
+   			      borderRadius: 5
+   			    }
+   			  },
+   			  edges: {
+   			    arrows: {
+   			      to: {
+   			        enabled: true,
+   			        scaleFactor: 0.4
+   			      }
+   			    },
+ 			  color: {
+ 			      highlight: "rgba(244,1,0,1)",
+ 			      hover: "rgba(0,0,0,1)",
+ 			      inherit: false
+ 			    },
+		      smooth: {
+ 			      type: "continuous",
+ 			      forceDirection: "vertical"
+ 			    }
+   			  },
+   			  interaction: {
+   			    hover: true,
+   			    multiselect: true
+   			  },
+	         groups: {
+	          dataset: {
+	            color:"#A9E2F3"
+	          },
+	          user: {
+	        	color:"#F781F3"
+	          }
+	        },
+	        
+	        physics: {    
+	          barnesHut: {
+	        	  centralGravity: 1.95,	              
+	        	  springLength: 195,
+	              springConstant: 0.185,
+	        	  damping: 0.25,
+	              avoidOverlap: 0.2
+   			    },
+   			 	maxVelocity: 10,
+   			    minVelocity: 0.75,
+	          stabilization: {
+	            enabled:true,
+	            iterations:200,
+	            updateInterval:1
+	          }
+	        },
+	        configure: {
+	          filter:function (option, path) {
+	            if (path.indexOf('physics') !== -1 || option === 'physics') {
+	              return true;
+	            }
+	            if (path.indexOf('smooth') !== -1 || option === 'smooth') {
+	              return true;
+	            }
+	            return true;
+	          },
+	          container: document.getElementById('config')
+	        }
+	      };
+	      network = new vis.Network(container, data, options);
+
+	      network.on("stabilizationProgress", function(params) {
+	                var maxWidth = 496;
+	                var minWidth = 20;
+	                var widthFactor = params.iterations/params.total;
+	                var width = Math.max(minWidth,maxWidth * widthFactor);
+
+	                document.getElementById('bar').style.width = width + 'px';
+	                document.getElementById('text').innerHTML = Math.round(widthFactor*100) + '%';
+	            });
+	            network.once("stabilizationIterationsDone", function() {
+	                document.getElementById('text').innerHTML = '100%';
+	                document.getElementById('bar').style.width = '496px';
+	                document.getElementById('loadingBar').style.opacity = 0;
+	                // really clean the dom element
+	                setTimeout(function () {document.getElementById('loadingBar').style.display = 'none';}, 500);
+	            });
+
+	      //network.focusOnNode(19);
+	      network.on('select', function(properties) {
+	        var select_node = $.grep(data.nodes, function(e){
+	          return e["id"] == properties.nodes[0];
+	        })[0];
+
+	        $("#nodeName").text(select_node["title"]);
+	        //alert(select_node["title"]);
+	        $("#id").text(select_node["id"]);
+	        $("#cluster").text(select_node["cluster"]);
+	        $("#label").text(select_node["label"]);
+
+	        $("#panel").show();
+	      });
+	    }
+	    
+	    
+	</script>
+	<script type="text/javascript" src='@routes.Assets.at("javascripts/googleAnalytics.js")'></script>
+}
+
+@main("Knowledge Graph", scripts){
+	<div id="jsonData" style="display: none;">@jsonData</div>
+	<div id="knowledgeGraph">
+	
+	   <div id="loadingBar" class="col-lg-3">
+	    <div class="outerBorder" >
+	        <div id="text">0%</div>
+	        <div id="border">
+	            <div id="bar"></div>
+	        </div>
+	    </div>	    
+	   </div>
+	   
+	  <div id="mynetwork" class="col-lg-3"></div>
+	  <div class = "col-lg-offset-7">
+	        <button type="button" onclick="hideConfig()" class="btn btn-default btn-lg "><span class="glyphicon glyphicon-star" aria-hidden="true">
+	        </span> Show Advanced Settings </button>
+	  </div>
+	  <div id="config" class="col-lg-offset-7"></div>  
+	</div>
+	
+	<br>
+	
+	<div id="panel" class="col-lg-offset-7">  
+	  <div class="well col-lg-5">
+	    <div class="text-center">
+	      <img class="card-img-top" style=" width:60%;" src="/assets/images/data.png">
+	    </div>
+	    <div class="card-block text-center">
+	      <h4 class="card-title" id="nodeName">card</h4>
+	      <p class="card-text text-muted" >A data set (or dataset) is a collection of data.</p>
+	    </div>
+	    <ul class="list-group list-group-flush">
+	      <li class="list-group-item"><strong>Id:</strong><code id="id"></code></li>
+	      <li class="list-group-item"><strong>Cluster:</strong><code id="cluster"></code></li>
+	      <li class="list-group-item"><strong>Label:</strong><code id="label"></code></li>
+	    </ul>
+	    <div class="card-block">
+	      <a href="#" class="card-link col-lg-offset-0 col-lg-6">Card link</a> 
+	      <a href="#" class="card-link col-lg-6">Another link</a>
+	    </div>    
+	  </div>  
+	</div>
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/main.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/main.scala.html b/ApacheCMDA_Frontend_1.0/app/views/main.scala.html
index 37a5caa..a41f414 100644
--- a/ApacheCMDA_Frontend_1.0/app/views/main.scala.html
+++ b/ApacheCMDA_Frontend_1.0/app/views/main.scala.html
@@ -32,8 +32,6 @@
 	href='@routes.Assets.at("stylesheets/livefitler.css")'>
 <link rel="stylesheet"
     href='@routes.Assets.at("stylesheets/custom_recommend.css")'>
-<link rel="stylesheet"
-	href="https://cdnjs.cloudflare.com/ajax/libs/vis/3.11.0/vis.min.css">
 <link rel="stylesheet" 
 	href="http://code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css">
 

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/recommendationSummary.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/recommendationSummary.scala.html b/ApacheCMDA_Frontend_1.0/app/views/recommendationSummary.scala.html
new file mode 100644
index 0000000..7cd4d3f
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/app/views/recommendationSummary.scala.html
@@ -0,0 +1,171 @@
+@(climateServices: List[ClimateService], dataSets: List[Dataset], users: List[User])
+
+@import helper._
+
+@scripts = {
+	<script type="text/javascript">
+	$(document).ready(function(){
+		$('#myTabs a').click(function (e) {
+			  e.preventDefault()
+			  $(this).tab('show')
+		})
+	});
+	</script>
+}
+
+@main("Climate Services", scripts) {
+	 
+    <h1>Recommendation</h1>
+    
+    <div>
+	  <!-- Nav tabs -->
+	  <ul class="nav nav-tabs" role="tablist">
+	    <li role="presentation" class="active"><a href="#mostPopService" aria-controls="home" role="tab" data-toggle="tab">Most Popular Service</a></li>
+	    <li role="presentation"><a href="#mostPopDataset" aria-controls="profile" role="tab" data-toggle="tab">Most Popular Dataset</a></li>
+	    <li role="presentation"><a href="#mostActUsers" aria-controls="messages" role="tab" data-toggle="tab">Most Active User</a></li>
+	    <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Settings</a></li>
+	  </ul>	
+	  <!-- Tab panes -->
+	  <div class="tab-content">
+	    <div role="tabpanel" class="tab-pane active" id="mostPopService">
+				<table class="table table-striped table-bordered table-condensed ex2">
+					<tr>
+						<td class="col-md-2">Climate Service Name</td>
+						<td class="col-md-2">Purpose</td>
+						<td class="col-md-4">Url</td>
+						<td class="col-md-2">Scenario</td>
+						<td class="col-md-2">Version</td>
+						<td class="col-md-2">Root_Service</td>						  
+					</tr>
+					
+					@for(climateService <- climateServices){
+					<tr>
+						<td><a href = "@climateService.getUrl()">@climateService.getName()</a></td>
+				
+						<td><span class="@climateService.getName() editable" data-name='purpose'>
+								@climateService.getPurpose() </span></td>
+						
+						<td><span class="@climateService.getName() editable" id = "url" data-name='url'>
+								<a href = "@climateService.getUrl()">
+								@climateService.getUrl()</a> </span></td>
+								
+						<td><span class="@climateService.getName() editable" data-name='scenario'>
+								@climateService.getScenario() </span></td>
+								
+						<td><span class="@climateService.getName() editable" data-name='versionNo'>
+								@climateService.getVersionNo() </span></td>
+								
+						<td><span class="@climateService.getName() editable" data-name='rootServiceId'>
+								@climateService.getRootServiceId() </span></td>						
+					</tr>
+					}
+			    </table>
+    	</div>
+    	
+	    <div role="tabpanel" class="tab-pane" id="mostPopDataset">
+				<table class="table table-striped table-bordered table-condensed ex2 tablesorter" >
+					<thead>
+					<tr>
+						<!--  
+						<th style = "vertical-align: top;" class="col-md-1 header">Id</th>
+						-->
+						<th style = "vertical-align: top;" class="col-md-2">Dataset Name</th>
+						<th style = "vertical-align: top;" class="col-md-1">Agency</th>
+						<th style = "vertical-align: top;" class="col-md-1">Instrument/Model Experiment</th>
+						<th style = "vertical-align: top;" class="col-md-2">Physical variable</th>
+						<th style = "vertical-align: top;" class="col-md-1">Variable short name</th>
+						<th style = "vertical-align: top;" class="col-md-1">Units</th>
+						<th style = "vertical-align: top;" class="col-md-1">Grid Dimension</th>
+						<!--  
+						<th style = "vertical-align: top;" class="col-md-3">Source</th> 
+						<th style = "vertical-align: top;" class="col-md-3">Status</th>
+						<th style = "vertical-align: top;" class="col-md-4">Responsible Person</th>
+						<th style = "vertical-align: top;" class="col-md-4">Data Source Name in Web Interface</th> 
+						-->
+						<th style = "vertical-align: top;" class="col-md-2">Variable Name in Web Interface</th>
+						<th style = "vertical-align: top;" class="col-md-1">Data Source Input Parameter</th>
+						<!-- <th style = "vertical-align: top;" class="col-md-3">Variable Name Input Parameter</th> -->
+						<th style = "vertical-align: top;" class="col-md-1">Dataset Start Time</th>
+						<th style = "vertical-align: top;"class="col-md-1">Dataset End Time</th>
+						<th style = "vertical-align: top;"class="col-md-1">Duration</th>
+					</tr>
+					</thead>
+					<tbody>
+					@for(dataSet <- dataSets){
+					<tr>
+						<!--  
+						<td><font size="2">@dataSet.getId()</font></td> 
+						-->
+						<td><font size="2">@dataSet.getName()</font></td>
+						<td><font size="2">@dataSet.getAgencyId()</font></td>
+						<td><font size="2">@dataSet.getInstrument()</font></td>
+						<td><font size="2">@dataSet.getPhysicalVariable()</font></td>
+						<td><font size="2">@dataSet.getCMIP5VarName()</font></td>
+						<td><font size="2">@dataSet.getUnits()</font></td>
+						<td><font size="2">@dataSet.getGridDimension()</font></td>
+						<!--
+						<td><font size="2">@dataSet.getSource()</font></td>
+						<td><font size="2">@dataSet.getStatus()</font></td>
+						<td><font size="2">@dataSet.getResponsiblePerson()</font></td>
+						<td><font size="2">@dataSet.getDataSourceNameinWebInterface()</font></td>
+						-->
+						<td><font size="2">@dataSet.getVariableNameInWebInterface()</font></td>
+						<td><font size="2">@dataSet.getDataSourceInputParameterToCallScienceApplicationCode()</font></td>
+						<!--<td><font size="2">@dataSet.getVariableNameInputParameterToCallScienceApplicationCode()</font></td> -->
+						<td><font size="2">@dataSet.getStartTime()</font></td>
+						<td><font size="2">@dataSet.getEndTime()</font></td>
+						<td><font size="2">@dataSet.getDuration()</font></td>						
+					</tr>					
+					}
+					</tbody>
+				    </table>
+		
+		</div>
+	    <div role="tabpanel" class="tab-pane" id="mostActUsers">
+
+			<table class="table table-striped table-bordered table-condensed ex2">
+				<tr>
+					<td class="col-md-1">Id</td>
+					<td class="col-md-2">User Name</td>
+					<td class="col-md-2">First Name</td>
+					<td class="col-md-2">Middle Name</td>
+					<td class="col-md-2">Last Name</td>
+					<td class="col-md-2">Afflication</td>
+					<td class="col-md-4">Email</td>
+					<td class="col-md-2">Research Area</td>
+					
+				</tr>
+				@for(user <- users){
+				<tr>
+					<td>@user.getId()</td>
+					
+					<td><span class="@user.getId() editable" data-name='username'>@user.getUserName()</span></td>
+							
+					<td><span class="@user.getId() editable" data-name='firstName'>@user.getFirstName()</span></td>
+							
+					<td><span class="@user.getId() editable" data-name='middleInitial'>@user.getMiddleInitial()</span></td>
+							
+					<td><span class="@user.getId() editable" data-name='lastName'>@user.getLastName()</span></td>
+					
+					<td><span class="@user.getId() editable" data-name='affiliation'>@user.getAffiliation()</span></td>
+							
+					<td><span class="@user.getId() editable" data-name='email'>@user.getEmail()</span></td>
+							
+					<td><span class="@user.getId() editable" data-name='researchFields'>@user.getResearchFields()</span></td>
+						
+				</tr>
+				}
+		    </table>
+		
+		
+		
+		</div>
+	    <div role="tabpanel" class="tab-pane" id="settings">...</div>
+	  </div>
+	</div>
+    
+	
+ 
+    
+     
+}

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/searchClimateService.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/searchClimateService.scala.html b/ApacheCMDA_Frontend_1.0/app/views/searchClimateService.scala.html
new file mode 100644
index 0000000..84ae278
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/app/views/searchClimateService.scala.html
@@ -0,0 +1,117 @@
+@(climateServiceForm: play.data.Form[ClimateService])
+
+@import helper._
+
+@scripts = {
+	<script src='@routes.Assets.at("javascripts/edit_button.js")'></script>
+	<link rel="stylesheet" href="//code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css">
+	<script src="//code.jquery.com/jquery-1.10.2.js"></script>
+  	<script src="//code.jquery.com/ui/1.11.3/jquery-ui.js"></script>
+	<script type="text/javascript">
+		$(document)
+				.ready(
+						function() {
+							$("#preview")
+									.click(
+											function() {
+												var target = document
+														.getElementById("show");
+												if (target.style.display == "none") {
+													target.style.display = "block";
+													$("#preview").text("Hide");
+													var climateServiceName = $(
+															"#climateServiceName")
+															.val();
+													var purpose = $("#purpose")
+															.val();
+													var scenario = $(
+															"#scenario")
+															.val();
+													var url = $(
+															"#url")
+															.val();
+													var versionNo = $(
+															"#versionNo")
+															.val();
+												
+													if (climateServiceName != "") {
+														$("#content")
+																.append(
+																		" Climate Service Name = "
+																				+ climateServiceName);
+													}
+													if (purpose != ""
+															&& purpose != null) {
+														$("#content")
+																.append(
+																		" Purpose = "
+																				+ purpose);
+													}
+												
+													if (scenario != ""
+															&& scenario != null) {
+														$("#content")
+																.append(
+																		" Scenario = "
+																				+ scenario);
+													}
+													if (url != ""
+															&& url != null) {
+														$("#content")
+																.append(
+																		" URL = "
+																				+ url);
+													}
+													if (versionNo != ""
+															&& versionNo != null) {
+														$("#content")
+																.append(
+																		" Version Number = "
+																				+ versionNo);
+													}
+
+												} else {
+													$("#content").val('');
+													target.style.display = "none";
+													$("#preview").text(
+															"Preview");
+												}
+											});
+						});
+	</script>
+}
+
+@main("Search Climate Service", scripts){ 
+	 
+    <h1 style="margin-left:420px">Search Climate Service</h1>
+    @helper.form(routes.ClimateServiceController.getSearchResult()) {
+    	<div class="ui-widget col-sm-offset-3 col-sm-7">
+    	<div class = "form-group">
+    		@inputText(climateServiceForm("Climate Service Name"), 'class -> "form-control", 'id -> "climateServiceName", '_label -> Messages("Climate Service Name"), 'placeholder -> "twoDimSlice3D", 'size->70) 
+    	</div>
+    	<div class = "form-group">
+    		@inputText(climateServiceForm("Purpose"), 'class -> "form-control", 'id -> "purpose", '_label -> Messages("Purpose"), 'placeholder -> "service purpose", 'size->70) 
+    	</div>
+    	
+       	<div class = "form-group">
+       		@inputText(climateServiceForm("Scenario"), 'class -> "form-control", 'id -> "scenario", '_label -> Messages("Scenario"), 'placeholder -> "1", 'size->70)
+	    </div>
+	    <div class = "form-group">
+	    	@inputText(climateServiceForm("Url"), 'class -> "form-control", 'id -> "url", '_label -> Messages("Url"), 'placeholder -> "http://", 'size->70)
+	    	
+	    </div>
+	    <div class = "form-group">
+       		@inputText(climateServiceForm("Version Number"), 'class -> "form-control", 'id -> "versionNo", '_label -> Messages("Version Number"), 'placeholder -> "1", 'size->70)
+	    
+	    	<div id="show" style="display: none;">
+	    		<textarea style="width: 640px" rows="4" id="content"></textarea>
+	    	</div>
+	    </div>
+	    <div align="center">
+	    	<button id="preview" type="button" class="btn btn-info"> Preview</button>
+	    	<input class="btn" type="submit" value="Search">
+	    </div>
+	    </div>
+	    
+	    }
+	 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/app/views/serviceLog.scala.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/app/views/serviceLog.scala.html b/ApacheCMDA_Frontend_1.0/app/views/serviceLog.scala.html
index b5d99f2..1ef867e 100644
--- a/ApacheCMDA_Frontend_1.0/app/views/serviceLog.scala.html
+++ b/ApacheCMDA_Frontend_1.0/app/views/serviceLog.scala.html
@@ -57,12 +57,19 @@
 	<td><font size="2">@serviceLog.getDataSetStartTime</font></td>
 	<td><font size="2">@serviceLog.getDataSetEndTime</font></td>
 	<td>
-	@form(routes.ServiceExecutionLogController.getConfigurationByConfId()){
-		<input
-			name="logId" class="hidden" type="hidden"
-			value="@serviceLog.getId">
-		<input
-			type="submit"  value="see details">
+	@if(serviceLog.getUrl() != null){
+		<form method="post" action="@serviceLog.getUrl">
+			<input type="submit"  value="see details">
+		</form>
+	
+	}else{
+		@form(routes.ServiceExecutionLogController.getConfigurationByConfId()){
+			<input
+				name="logId" class="hidden" type="hidden"
+				value="@serviceLog.getId">
+			<input
+				type="submit"  value="see details">
+		}
 	}
 	</td>
 	<!--

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/conf/routes
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/conf/routes b/ApacheCMDA_Frontend_1.0/conf/routes
index 35927f7..47558c9 100644
--- a/ApacheCMDA_Frontend_1.0/conf/routes
+++ b/ApacheCMDA_Frontend_1.0/conf/routes
@@ -12,6 +12,9 @@ GET		/createNewUser				controllers.Application.createNewUser()
 GET		/createSuccess				controllers.Application.createSuccess()
 POST	/isEmailExisted				controllers.Application.isEmailExisted()
 
+#recommendation overview
+GET		/climateService/recommendationSummary					controllers.ClimateServiceController.recommendationSummary()
+
 # Climate Service
 GET		/climateService/allServices									controllers.ClimateServiceController.showAllClimateServices()
 POST		/climateService/add											controllers.ClimateServiceController.addClimateService()
@@ -24,6 +27,8 @@ POST		/climateService/ruleEngineData									controllers.ClimateServiceControlle
 GET     	/climateService/mostPopularServices						controllers.ClimateServiceController.mostPopularServices()
 GET		/climateService/mostRecentlyUsedClimateServices			controllers.ClimateServiceController.mostRecentlyUsedClimateServices()
 GET		/climateService/mostRecentlyAddedClimateServices		controllers.ClimateServiceController.mostRecentlyAddedClimateServices()
+GET		/climateService/searchClimateService 					 		controllers.ClimateServiceController.searchClimateServices()
+GET 	/climateService/getSearchResult				    controllers.ClimateServiceController.getSearchResult()
 
 #replace page
 POST 	/climateService/replaceFile								controllers.ClimateServiceController.replaceFile()
@@ -39,6 +44,7 @@ GET 		/getConfigurationByConfId                               controllers.Servic
 GET     /dataSet/allDatasets                        controllers.DatasetController.showAllDatasets()
 GET		/dataSet/searchDataSet 					 	controllers.DatasetController.searchDataset()
 GET 	/dataSet/getSearchResult				    controllers.DatasetController.getSearchResult()
+GET     /dataSet/mostPopularDatasets				controllers.DatasetController.mostPopularDatasets()
 
 # Dataset Log
 GET		/datasetLog/allDatasetLogs					controllers.DatasetLogController.getAllDatasetLogs()
@@ -49,6 +55,7 @@ GET     /datasetRecommend                           controllers.AnalyticsControl
 GET     /profileRecommend                           controllers.AnalyticsController.getScientistRecommend()
 GET     /serviceLogGraph                            controllers.AnalyticsController.getLogGraph()
 GET 	/searchAndGenerateWorkflow					controllers.AnalyticsController.getSearchAndGenerateWorkflow()
+GET     /serviceKnowledgeGraph                      controllers.AnalyticsController.getKnowledgeGraph()
 
 # Users
 GET		/scientist/allUsers							controllers.UsersController.getAllUsers()
@@ -56,6 +63,7 @@ GET		/scientist/searchUser 					 	controllers.UsersController.searchUser()
 
 # Map static resources from the /public folder to the /assets URL path
 GET     /assets/*file               controllers.Assets.at(path="/public", file)
+POST    /assets/*file               controllers.Assets.at(path="/public", file)
 
 
 # About

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/html/js2/.DS_Store
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/html/js2/.DS_Store b/ApacheCMDA_Frontend_1.0/public/html/js2/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/ApacheCMDA_Frontend_1.0/public/html/js2/.DS_Store differ

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/html/js2/common.css
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/html/js2/common.css b/ApacheCMDA_Frontend_1.0/public/html/js2/common.css
new file mode 100644
index 0000000..477fb80
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/html/js2/common.css
@@ -0,0 +1,29 @@
+  .center1 {text-align: center;}
+  .right1 {text-align: right;}
+  /*.left1 {text-align: left; margin-left: 50px;}*/
+  .left1 {text-align: left;}
+  .middle1 {vertical-align: middle;}
+  .textwrapper {
+    border:1px solid #999999;
+    margin:5px 0;
+    padding:3px;
+  }
+  textarea { width:100%; }
+
+  .subtitle1 {color: DarkBlue; font-weight: bold; }
+
+  /*.color-head {background-color: Aqua;} */
+  .color-head {background-color: #C2EBFF  ;} /* A6C0CE  *A6C0CE  ABD8C0 */
+  .color4 {background-color: #B8B8B8;}  /*Azure EBFFF5  */
+  .color3 {background-color: #C8C8C8;}  /* Beige C2F0F0 */
+  /* .color3 {border-color: Azure; border-style: solid; } */ /* Beige C2F0F0 */
+  .color2 {background-color: #E8E8E8;}   /* YellowGreen B2B2E0 */
+  .color1 {background-color: #D8D8D8;}   /* SpringGreen*/
+  .color0 {background-color: #F8F8F8;}   /* Turquoise*/
+
+
+@media screen and (max-width: 768px) {
+.right1 {text-align: left;}
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/html/js2/common.js
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/html/js2/common.js b/ApacheCMDA_Frontend_1.0/public/html/js2/common.js
new file mode 100644
index 0000000..625de5f
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/html/js2/common.js
@@ -0,0 +1,548 @@
+// The following is for the code navigation purpose.
+//
+// enable_download data button
+// disable_pres1__
+// enable_pres1__(ID)
+// put_data__
+// data_block_str__
+// change_datan_
+// put_var__
+// is3D__
+// select_var__
+// time_range__
+// time_range2__
+// time_range3__
+// monthList__
+// fillMonth__
+// reset_months__
+// no_month_check
+// select_all_months__
+// select_months__
+// getMonthStr__
+// parse_pres__
+// get_querystring__
+
+var naValue = "-999999";
+
+// disable download data button
+function disable_download_button()
+{
+  var x=document.getElementById("download_data");
+  x.disabled=true;
+}
+
+// enable_download data button
+function enable_download_button()
+{
+  var x=document.getElementById("download_data");
+  x.disabled=false;
+}
+
+// disable pressure level box for 2D var
+// disable_pres1__
+function disable_pres1(ID)
+{
+  // if isPressure1 is defined, there is no pressure widget 
+  try {
+    var x;
+    x=document.getElementById("pres"+ID);
+    x.value = "N/A";
+    x.disabled=true;
+    var y=document.getElementById("pressureLabel"+ID);
+    y.innerHTML = "pressure:";
+  }
+  catch(err) {}
+}
+
+// enable pressure level box for 3D var
+// enable_pres1__(ID)
+function enable_pres1(ID)
+{
+  var var_string = $("#var"+ID).val();
+  var oceanStr = "";
+
+  try { 
+    var rangeStr0 = eval("rangeStr"+ID); 
+  } catch(err) { 
+    var rangeStr0 = "";
+  }
+
+  try {
+    var y=document.getElementById("pressureLabel"+ID);
+  //alert(y.value);
+    y.innerHTML = "atmospheric pressure " + rangeStr0 + "(hPa):";
+  } catch(err) {}
+
+  if (varList[var_string][1]==="ocean") {
+    oceanStr = "o";
+    try {
+    y.innerHTML = "ocean pressure " + rangeStr0 + "(dbar):";
+    } catch(err) {}
+  } 
+
+  // there can be no pressure widget, so there is a error catch here.
+  try {
+    var pressDf0;
+    try { 
+      pressDf0 = eval("pressDf"+ID+oceanStr); 
+    } catch(err) {
+      pressDf0 = "500";
+    }
+
+
+    var x=document.getElementById("pres"+ID);
+    x.value = pressDf0;
+    x.disabled=false;
+  } catch(err) {}
+/*  try {
+    if ( eval("typeof pressDf"+ID) !== 'undefined') var pressDf0 = eval("pressDf"+ID);
+    else var pressDf0 = "500";
+
+    var x=document.getElementById("pres"+ID);
+    x.value = pressDf0;
+    x.disabled=false;
+  } catch(err) {}
+*/
+}
+
+// put_data__
+function put_data(ID){
+  var list1=document.getElementById("data"+ID);
+
+  for(var key in dataList) {
+    if (key.slice(0,5)==="group") {
+      var og = document.createElement("OPTGROUP");
+      og.setAttribute('label', dataList[key][0]);
+      list1.add(og);
+
+    } else {
+      var toAdd = true;
+
+      // whether the dataset has only 2D or only 3D variables
+      if   ( (typeof isOnly2d !== 'undefined') 
+          || (typeof isOnly3d !== 'undefined') ) {
+        var dims = "";
+        var varList2 = dataList[key][1];  
+        for(var i=0; i<varList2.length; i++)   
+          dims += String(varList[ varList2[i] ][2]);
+
+        if (typeof isOnly2d !== 'undefined') 
+          if (dims.indexOf('2')==-1) toAdd = false;
+        if (typeof isOnly3d !== 'undefined') 
+          if (dims.indexOf('3')==-1) toAdd = false;
+      }
+  
+      // add to the option group
+      if (toAdd) og.appendChild(new Option(key,key));
+    }
+  }
+}
+
+// change_datan_
+function change_datan(numTB){
+  var nVar=Number( document.getElementById("nVar").value );
+  //alert(nVar);
+
+  for (var i=0; i<nVar; i++) {
+    var str1 = data_block_str(String(i+2), numTB, "Source Variable "+String(i+1), "", 500);
+    //alert(str1);
+    document.getElementById("datan"+(i+1)).innerHTML = str1;
+    put_data(i+2);
+    put_var(i+2);
+    select_var(i+2);
+  }
+  for (var i=nVar; i<10; i++) {
+    document.getElementById("datan"+(i+1)).innerHTML = "";
+  }
+}
+
+// data_block_str__
+function data_block_str(ID, numTB, dataTitle, isRange, pressDf){
+var temp1= '';
+temp1 += '<div class="row ">\n'
+temp1 += '<div class="col-sm-12 center1 subtitle1">\n';
+temp1 += dataTitle + '\n';
+temp1 += '</div>\n';
+temp1 += '</div> <!-- row --> \n';
+
+temp1 += '<div class="row">\n';
+temp1 += ' <div class="col-sm-4 right1">\n';
+temp1 += '   source:' + '\n';
+temp1 += '  </div> <!-- col-sm-6 -->\n';
+temp1 += '  <div class="col-sm-8 left1">\n';
+temp1 += '    <select name="data' + ID + '", id="data' + ID;
+temp1 += '" onchange="put_var(' + ID + '); select_var(' + ID + ');time_range' + numTB + '()"></select>\n';
+temp1 += '  </div> <!-- col-sm-6 level2-->\n';
+temp1 += '</div> <!-- row -->\n';
+
+temp1 += '<div class="row">\n';
+temp1 += '  <div class="col-sm-4 right1">\n';
+temp1 += '    variable name:\n';
+temp1 += '  </div> <!-- col-sm-6 level2-->\n';
+temp1 += '  <div class="col-sm-8 left1">\n';
+temp1 += '    <select name="var' + ID +'", id="var' + ID;
+temp1 += '" onchange="select_var(' + ID + '); select_var(' + ID + '); time_range' + numTB + '()"> </select>\n';
+temp1 += '  </div> <!-- col-sm-6 level2-->\n';
+temp1 += '</div> <!-- row -->\n';
+
+temp1 += '<div class="row">\n';
+temp1 += '  <div class="col-sm-4 right1" id="pressureLabel' + ID + '">\n';
+//temp1 += '    pressure ' + isRange + '(atmosphere hPa) <br> or (ocean dbar):\n';
+temp1 += '    pressure ' + isRange +':\n';
+temp1 += '  </div> <!-- col-sm-6 level2-->\n';
+temp1 += '  <div class="col-sm-8 left1">\n';
+temp1 += '    <input id="pres' + ID + '" value="' + pressDf + '" alt="pressure"/>\n';
+temp1 += '  </div> <!-- col-sm-6 level2-->\n';
+temp1 += '</div> <!-- row -->\n';
+// alert(temp1);
+return temp1;
+}
+
+// put_var__
+function put_var(ID) {
+  var list1=document.getElementById("var"+ID);
+  for (var i=list1.length-1; i>=0; i--) {
+  list1.remove(i);
+  }
+
+  data_string =  document.getElementById("data"+ID).value;
+  var varList2 = dataList[data_string][1];  
+
+  if (typeof isOnly2d !== 'undefined') {
+    // list only 2D variables
+    for (var i=0; i<varList2.length; i++) {
+      var k = varList2[i];
+      if (varList[k][2]==2) list1.add(new Option(varList[k][0],k));
+    }
+
+  } else if (typeof isOnly3d !== 'undefined') {
+    // list only 3D variables
+    for (var i=0; i<varList2.length; i++) {
+      var k = varList2[i];
+      if (varList[k][2]==3) list1.add(new Option(varList[k][0],k));
+    }
+
+  } else {
+    // list all 2D/3D variables
+    for (var i=0; i<varList2.length; i++) {
+      var k = varList2[i];
+      list1.add(new Option(varList[k][0],k));
+    }
+  }
+
+  var nVar = list1.options.length;
+  if (nVar==0) {
+    alert(data_string + " has no suitable variable.");
+    document.getElementById("data"+ID).options[0].selected = true; 
+    put_var(ID);
+  }
+}
+
+// is3D__
+function is3D(ID)
+{
+  var var_string = $("#var"+ID).val();
+  return varList[var_string][2]==3;
+}
+
+// select_var__
+function select_var(ID)
+{
+  // if there isOnly2d is defined, there is no pressure widget.
+  try {
+    //var var_string = $("#var"+ID).val();
+    //alert(is3D(ID));
+    if (is3D(ID)) {
+      enable_pres1(ID);
+    } else {
+      disable_pres1(ID);
+    }
+  }
+  catch(err) {}
+}
+
+
+// time_range__
+// this is identical to time_range1()
+function time_range() {
+  var var_string1 = $("#var"+1).val();
+  var data_string1 = $("#data"+1).val();
+
+  var sTime = dataList[data_string1][2][var_string1][0].toString();
+  var eTime = dataList[data_string1][2][var_string1][1].toString();
+
+  $("#startYear").html("start year-month: (earliest:" + sTime.slice(0,4) + "-" + sTime.slice(4,6) + ")");
+  $("#endYear").html("end year-month: (latest:" + eTime.slice(0,4) + "-" + eTime.slice(4,6) + ")");
+}
+
+function time_range1() {
+  var var_string1 = $("#var"+1).val();
+  var data_string1 = $("#data"+1).val();
+
+  var sTime = dataList[data_string1][2][var_string1][0].toString();
+  var eTime = dataList[data_string1][2][var_string1][1].toString();
+
+  $("#startYear").html("start year-month: (earliest:" + sTime.slice(0,4) + "-" + sTime.slice(4,6) + ")");
+  $("#endYear").html("end year-month: (latest:" + eTime.slice(0,4) + "-" + eTime.slice(4,6) + ")");
+}
+
+// time_range2__
+function time_range2() {
+  var var_string1 = $("#var"+1).val();
+  var var_string2 = $("#var"+2).val();
+  var data_string1 = $("#data"+1).val();
+  var data_string2 = $("#data"+2).val();
+  //alert(data_string1);
+  //alert(data_string2);
+  
+
+  var sTime = Math.max( Number(dataList[data_string1][2][var_string1][0]),
+                        Number(dataList[data_string2][2][var_string2][0]) ).toString();
+  var eTime = Math.min( Number(dataList[data_string1][2][var_string1][1]),
+                        Number(dataList[data_string2][2][var_string2][1]) ).toString();
+
+  //sTime = sTime.toString();
+  //eTime = eTime.toString();
+
+  $("#startYear").html("start year-month: (earliest:" + sTime.slice(0,4) + "-" + sTime.slice(4,6) + ")");
+  $("#endYear").html("end year-month: (latest:" + eTime.slice(0,4) + "-" + eTime.slice(4,6) + ")");
+}
+
+// time_range3__
+function time_range3() {
+  var var_string1 = $("#var"+1).val();
+  var var_string2 = $("#var"+2).val();
+  var var_string3 = $("#var"+3).val();
+  var data_string1 = $("#data"+1).val();
+  var data_string2 = $("#data"+2).val();
+  var data_string3 = $("#data"+3).val();
+
+  var sTime = Math.max( 
+        Number(dataList[data_string1][2][var_string1][0]),
+        Number(dataList[data_string2][2][var_string2][0]),
+        Number(dataList[data_string3][2][var_string3][0]) 
+        ).toString();
+  var eTime = Math.min(
+        Number(dataList[data_string1][2][var_string1][1]),
+        Number(dataList[data_string2][2][var_string2][1]),
+        Number(dataList[data_string3][2][var_string3][1]) 
+        ).toString();
+
+  $("#startYear").html("start year-month: (earliest:" + sTime.slice(0,4) + "-" + sTime.slice(4,6) + ")");
+  $("#endYear").html("end year-month: (latest:" + eTime.slice(0,4) + "-" + eTime.slice(4,6) + ")");
+}
+
+// monthList__
+var monthList = [
+"Jan",
+"Feb",
+"Mar",
+"Apr",
+"May",
+"Jun",
+"Jul",
+"Aug",
+"Sep",
+"Oct",
+"Nov",
+"Dec",
+];
+
+// fillMonth__
+function fillMonth() { 
+  var temp1 = 'select months:\
+<select name="months" id="months" onchange="select_months()">\
+<option id="all">select all</option>\
+<option id="none">select none</option>\
+<option id="summer">Summer:Jun-Jul-Aug</option>\
+<option id="autum">Autumn:Sep-Oct-Nov</option>\
+<option id="winter">Winter:Dec-Jan-Feb</option>\
+<option id="spring">Spring:Mar-Apr-May</option> </select>';
+  $("#monthSelect0").html(temp1); 
+
+  temp1 = '<form role="form">'; 
+  for (var i=0; i<monthList.length; i++) {
+    temp1 +=
+        '<label"><input type="checkbox" id="' + monthList[i] + '" value="' + monthList[i] + '" checked/></label>' 
+          +  monthList[i] + " ";
+  }
+  temp1 += '</form>';
+  $("#monthSelect").html(temp1); 
+}
+
+// unselect all months in the checkboxes
+// reset_months__
+function reset_months()
+{
+  for (var i=0; i<monthList.length; i++) {
+    document.getElementById(monthList[i]).checked = false;
+  }
+}
+
+// see if no month is selected
+// no_month_check
+function no_month_check()
+{
+  var nonChecked = true;
+  for (var i=0; i<monthList.length; i++) {
+    if (document.getElementById(monthList[i]).checked == true) {
+      nonChecked = false;
+    }
+  }
+  return nonChecked;
+}
+
+// select all months in the checkboxes
+// select_all_months__
+function select_all_months()
+{
+  for (var i=0; i<monthList.length; i++) {
+    document.getElementById(monthList[i]).checked = true;
+  }
+}
+
+// select checkboxes based on "months" dropdown
+// select_months__
+function select_months()
+{
+  var s1=document.getElementById("months");
+  // alert(s1.selectedIndex);
+  // alert(s1.options[s1.selectedIndex].value);
+
+  // disable the download button because of this change
+  disable_download_button();
+
+  // "select none"
+  if (s1.selectedIndex == 1) {
+    reset_months();
+  }
+  // "select all"
+  if (s1.selectedIndex == 0) {
+    select_all_months();
+  }
+  // "summer"
+  if (s1.selectedIndex == 2) {
+    reset_months();
+    document.getElementById('Jun').checked = true;
+    document.getElementById('Jul').checked = true;
+    document.getElementById('Aug').checked = true;
+  }
+  // "autumn"
+  if (s1.selectedIndex == 3) {
+    reset_months();
+    document.getElementById('Sep').checked = true;
+    document.getElementById('Oct').checked = true;
+    document.getElementById('Nov').checked = true;
+  }
+  // "winter"
+  if (s1.selectedIndex == 4) {
+    reset_months();
+    document.getElementById('Dec').checked = true;
+    document.getElementById('Jan').checked = true;
+    document.getElementById('Feb').checked = true;
+  }
+  // "spring"
+  if (s1.selectedIndex == 5) {
+    reset_months();
+    document.getElementById('Mar').checked = true;
+    document.getElementById('Apr').checked = true;
+    document.getElementById('May').checked = true;
+  }
+
+}
+
+// getMonthStr__
+function getMonthStr() {
+        // get months checked by client
+        var month_str = "";
+        for (var i=0; i<monthList.length; i++) {
+          var mm = document.getElementById(monthList[i]);
+          if (mm.checked == true) {
+            month_str += ","+(i+1);
+          }
+        }
+        month_str = month_str.substr(1);
+        return month_str;
+}
+
+// parse_pres__
+function parse_pres(pres10) {
+  var pres1 = "";
+
+  if (pres10=="") {pres1 = naValue; }
+  else {
+    if (!(isNaN(Number(pres10)))) { 
+      pres1 = pres10; 
+    } else {
+      var checkNan = 0;
+      var pres2 = [];
+      var temp1=pres10.split(",");
+      //for (var i in temp1) {
+      for (var i=0; i<temp1.length; i++) {
+        if (isNaN(Number(temp1[i]))) {
+          checkNan = 1; 
+        } else {
+          pres2.push(Number(temp1[i]));
+        }
+      }
+      if (pres2.length>0) { pres1 = pres2.join(); }
+      else { pres1 = naValue; }
+    }
+  }
+  return pres1;
+}
+
+// get_querystring__
+function get_querystring() {
+  var queries = {};
+  $.each(document.location.search.substr(1).split('&'),function(c,q){
+    var i = q.split('=');
+    queries[i[0].toString()] = i[1].toString();
+  });
+  return queries;
+}
+
+
+function showUrl(inputs) {
+  var v1q, v2, key0, key1;
+  try {
+    var temp1 = "";
+    //for (var i=0; i<inputs.length; i++) {
+    for (key0 in inputs) {
+      if (!inputs.hasOwnProperty(key0)) { continue; }
+      if ( key0 == "Image" || key0 == "data_url" ) { continue; }
+      key1 = inputs[key0];
+
+      try {
+        v1q = $("#"+key1).val();
+
+        if ( key0.slice(0,5) == "model" ) {
+          v1q = v1q.replace("/", "_");
+        }
+
+        if ( key0 == "startT" || key0 == "endT" ) {
+          v1q = v1q.replace("-", "");
+        }
+
+        if ( key0 == "purpose" ) {
+          v1q = escape(v1q);
+        }
+
+/*
+        if ( key0.slice(0,4) == "pres" ) {
+          if ( Number(v1q) == NaN ) {
+            v1q = "-999999";
+          }
+        }
+*/
+        temp1 += key0 + "=" + v1q + "&";
+      } catch(err) {}
+    }
+    temp1 = temp1.slice(0,-1);
+  } catch(err) { 
+    var temp1 = document.location.search.substr(1);
+  }
+
+  document.getElementById("actionUrl").innerHTML = document.location.href.split('?')[0] + "?" + temp1;
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/html/js2/dataList2.js
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/html/js2/dataList2.js b/ApacheCMDA_Frontend_1.0/public/html/js2/dataList2.js
new file mode 100644
index 0000000..8cf0903
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/html/js2/dataList2.js
@@ -0,0 +1,42 @@
+// modelName: [category, listOfVar],
+var groupList={
+"group1":         ["Model: Historical"],
+"group2":         ["Model: AMIP"],
+"group3":         ["Observation"],
+"group4":         ["Reanalysis"],
+};
+
+var dataList={
+"group1":         ["Model: Historical"],
+"GFDL/ESM2G":     ["Model: Historical",      ["pr", "clt", "ts", "tos", "uas", "vas", "sfcWind", "zos", "lai", "rlds", "rlus", "rldscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "ta", "hus", "cli", "clw", "wap", "hur", ], {'uas': [199101, 200512, '.'], 'rlutcs': [199601, 200512, '.'], 'rsutcs': [199101, 200512, '.'], 'rldscs': [199601, 200512, '.'], 'pr': [199601, 200512, '.'], 'rlut': [199601, 200512, '.'], 'cli': [199101, 200512, 'regridded'], 'rlus': [199601, 200512, '.'], 'tos': [199601, 200512, 'regridded'], 'ts': [199601, 200512, '.'], 'zos': [199601, 200512, 'regridded'], 'clt': [199601, 200512, '.'], 'vas': [199101, 200512, '.'], 'clw': [199101, 200512, 'regridded'], 'ta': [199101, 200512, '.'], 'lai': [199601, 200512, '.'], 'rsdt': [199101, 200512, '.'], 'hur': [198601, 200512, '.'], 'hus': [199101, 200512, '.'], 'sfcWind': [199101, 200512, '.'], 'rlds': [199601, 200512, '.'], 'wap': [198601, 200512, '.'], 'rsut': [199101, 200512, '.']} ],       
+"GISS/E2-H":      ["Model: Historical",      ["pr", "clt", "ts", "tos", "uas", "vas", "sfcWind", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", "wap", "hur", ], {'hur': [195101, 200512, '.'], 'rsuscs': [199501, 200512, '.'], 'rsdscs': [199501, 200512, '.'], 'rlutcs': [199501, 200512, '.'], 'rsutcs': [199501, 200512, '.'], 'rldscs': [199501, 200512, '.'], 'pr': [199501, 200512, '.'], 'rlut': [199501, 200512, '.'], 'cli': [195101, 200512, 'regridded'], 'rlus': [199501, 200512, '.'], 'rlds': [199501, 200512, '.'], 'ts': [199501, 200512, '.'], 'clt': [199501, 200512, '.'], 'vas': [199501, 200512, '.'], 'clw': [195101, 200512, 'regridded'], 'uas': [199501, 200512, '.'], 'wap': [195101, 200512, '.'], 'rsdt': [199501, 200512, '.'], 'rsds': [199501, 200512, '.'], 'prw': [199501, 200512, '.'], 'sfcWind': [199501, 200512, '.'], 'tos': [199501, 200512, '.'], 'rsus': [199501, 200512, '.'], 'rsut': [199501, 200512, '.']} ],
       
+"GISS/E2-R":      ["Model: Historical",      ["pr", "clt", "ts", "tos", "uas", "vas", "sfcWind", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", "wap", "hur", ], {'hur': [195101, 200512, '.'], 'rsuscs': [199501, 200012, '.'], 'uas': [199501, 200512, '.'], 'rlutcs': [199501, 200012, '.'], 'rsutcs': [199501, 200012, '.'], 'rldscs': [199501, 200012, '.'], 'pr': [199501, 200512, '.'], 'rlut': [199501, 200012, '.'], 'cli': [200101, 200512, 'regridded'], 'rlus': [199501, 200012, '.'], 'tos': [199501, 200512, '.'], 'ts': [199501, 200512, '.'], 'clt': [199501, 200512, '.'], 'vas': [199501, 200512, '.'], 'clw': [199501, 200512, 'regridded'], 'rsdscs': [199501, 200012, '.'], 'wap': [195101, 200512, '.'], 'rsdt': [199501, 200012, '.'], 'rsds': [199501, 200012, '.'], 'sfcWind': [199501, 200512, '.'], 'rsus': [199501, 200012, '.'], 'rsut': [199501, 200012, '.']} ],      
+"NCAR/CAM5":      ["Model: Historical",      ["pr", "clt", "ts", "tos", "sfcWind", "zos", "lai", "rlds", "rsds", "rlus", "rsus", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", "wap", "hur", ], {'hur': [195001, 200512, '.'], 'rsuscs': [199501, 200512, '.'], 'rsdscs': [199501, 200512, '.'], 'rlutcs': [199501, 200512, '.'], 'rsutcs': [199501, 200512, '.'], 'pr': [199501, 200512, '.'], 'rlut': [199501, 200512, '.'], 'cli': [197501, 200512, 'regridded'], 'rlus': [199501, 200512, '.'], 'tos': [199501, 200512, 'regridded'], 'ts': [199501, 200512, '.'], 'zos': [199501, 200512, 'regridded'], 'clt': [199501, 200512, '.'], 'clw': [197501, 200512, 'regridded'], 'wap': [195001, 200512, '.'], 'lai': [199501, 200512, '.'], 'rsdt': [199501, 200512, '.'], 'rsds': [199501, 200512, '.'], 'sfcWind': [199501, 200512, '.'], 'rlds': [199501, 200512, '.'], 'rsus': [199501, 200512, '.'], 'rsut': [199501, 200512, '.']} ],      
+"NCC/NORESM":     ["Model: Historical",      ["pr", "clt", "ts", "tos", "uas", "vas", "zos", "lai", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "ta", "hus", "cli", "clw", "wap", "hur", ], {'hur': [195001, 200512, '.'], 'rsuscs': [199501, 200512, '.'], 'rsdscs': [199501, 200512, '.'], 'rlutcs': [199501, 200512, '.'], 'rsutcs': [199501, 200512, '.'], 'rldscs': [199501, 200512, '.'], 'pr': [199501, 200512, '.'], 'rlut': [199501, 200512, '.'], 'cli': [195001, 200512, 'regridded'], 'rlus': [199501, 200512, '.'], 'tos': [199501, 200512, 'regridded'], 'ts': [199501, 200512, '.'], 'zos': [199501, 200512, 'regridded'], 'clt': [199501, 200512, '.'], 'vas': [199501, 200512, '.'], 'clw': [195001, 200512, 'regridded'], 'uas': [199501, 200512, '.'], 'wap': [195001, 200512, '.'], 'lai': [199501, 200512, '.'], 'rsdt': [199501, 200512, '.'], 'rsds': [199501, 200512, '.'], 'hus': [199501, 200512, '.'], 'rlds': [199501, 200512, '.'], 'rsus'
 : [199501, 200512, '.'], 'ta': [199501, 200512, '.'], 'rsut': [199501, 200512, '.']} ],       
+"UKMO/HadGEM2-ES":["Model: Historical",      ["pr", "clt", "ts", "uas", "vas", "sfcWind", "zos", "lai", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", "wap", "hur", ], {'rsds': [199501, 200511, '.'], 'rsuscs': [199501, 200511, '.'], 'rsdscs': [199501, 200511, '.'], 'rlutcs': [199501, 200511, '.'], 'rsutcs': [199501, 200511, '.'], 'rldscs': [199501, 200511, '.'], 'pr': [199501, 200511, '.'], 'rlut': [199501, 200511, '.'], 'cli': [198412, 200511, 'regridded'], 'rlus': [199501, 200511, '.'], 'rlds': [199501, 200511, '.'], 'ts': [199501, 200511, '.'], 'zos': [195912, 200512, '.'], 'clt': [199501, 200511, '.'], 'vas': [199501, 200511, '.'], 'clw': [198412, 200511, 'regridded'], 'uas': [199501, 200511, '.'], 'wap': [198412, 200511, '.'], 'lai': [199501, 200511, '.'], 'rsdt': [199501, 200511, '.'], 'hur': [198412, 200511, '.'], 'sfcWind': [199501, 200511, '.'], 'rsus': [199501, 200511, '.'], 'rsut': [199501, 200511, '
 .']} ],            
+//                [ 
+"group2":         ["Model: AMIP"],
+"CCCMA/CANAM4":   ["Model: AMIP",            ["pr", "clt", "ts", "tas", "hurs", "uas", "vas", "sfcWind", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "ta", "hus", "cli", "clw", "wap", "hur", ], {'va': [195001, 200912, '.'], 'ci': [195001, 200912, '.'], 'sci': [195001, 200912, '.'], 'rsds': [195001, 200912, '.'], 'prc': [195001, 200912, '.'], 'cl': [195001, 200912, '.'], 'rsuscs': [195001, 200912, '.'], 'uas': [195001, 200912, '.'], 'huss': [195001, 200912, '.'], 'hfss': [195001, 200912, '.'], 'rlutcs': [195001, 200912, '.'], 'evspsbl': [195001, 200912, '.'], 'prsn': [195001, 200912, '.'], 'rldscs': [195001, 200912, '.'], 'ccb': [195001, 200912, '.'], 'pr': [195001, 200912, '.'], 'ps': [195001, 200912, '.'], 'cli': [195001, 200912, 'regridded'], 'rlus': [195001, 200912, '.'], 'rlds': [195001, 200912, '.'], 'tas': [195001, 200912, '.'], 'ts': [195001, 200912, '.'], 'prw': [195001, 200912, '.'], 'clt': [195001, 200912, '.'], 
 'vas': [195001, 200912, '.'], 'clw': [195001, 200912, 'regridded'], 'rsdscs': [195001, 200912, '.'], 'wap': [195001, 200912, '.'], 'zg': [195001, 200912, '.'], 'tasmin': [195001, 200912, '.'], 'psl': [195001, 200912, '.'], 'rlut': [195001, 200912, '.'], 'hurs': [195001, 200912, '.'], 'rsdt': [195001, 200912, '.'], 'hur': [195001, 200912, '.'], 'hus': [195001, 200912, '.'], 'sbl': [195001, 200912, '.'], 'clivi': [195001, 200912, '.'], 'mc': [195001, 200912, '.'], 'rtmt': [195001, 200912, '.'], 'cct': [195001, 200912, '.'], 'rsutcs': [195001, 200912, '.'], 'sfcWind': [195001, 200912, '.'], 'tauv': [195001, 200912, '.'], 'clwvi': [195001, 200912, '.'], 'tauu': [195001, 200912, '.'], 'tasmax': [195001, 200912, '.'], 'rsus': [195001, 200912, '.'], 'ta': [195001, 200912, '.'], 'ua': [195001, 200912, '.'], 'rsut': [195001, 200912, '.'], 'hfls': [195001, 200912, '.']} ],         
+"CSIRO/MK3.6":    ["Model: AMIP",            ["pr", "clt", "ts", "uas", "vas", "sfcWind", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", "wap", "hur", ], {'rsds': [197901, 200912, '.'], 'rsuscs': [197901, 200912, '.'], 'uas': [197901, 200912, '.'], 'rlutcs': [197901, 200912, '.'], 'rsutcs': [197901, 200912, '.'], 'rldscs': [197901, 200912, '.'], 'pr': [199501, 200912, '.'], 'rlut': [197901, 200912, '.'], 'cli': [197901, 200912, 'regridded'], 'rlus': [197901, 200912, '.'], 'rlds': [197901, 200912, '.'], 'ts': [199501, 200912, '.'], 'clt': [199501, 200912, '.'], 'vas': [197901, 200912, '.'], 'clw': [199901, 200912, 'regridded'], 'rsdscs': [197901, 200912, '.'], 'wap': [199001, 200512, '.'], 'rsdt': [197901, 200912, '.'], 'hur': [199001, 200512, '.'], 'sfcWind': [197901, 200912, '.'], 'rsus': [197901, 200912, '.'], 'rsut': [197901, 200912, '.']} ],        
+"GFDL/CM3":       ["Model: AMIP",            ["pr", "clt", "ts", "uas", "vas", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "ta", "hus", "cli", "clw", "wap", "hur", ], {'hur': [198901, 200812, '.'], 'rsuscs': [199401, 200812, '.'], 'rsdscs': [199401, 200812, '.'], 'rlutcs': [199401, 200812, '.'], 'rsutcs': [199401, 200812, '.'], 'rldscs': [199401, 200812, '.'], 'pr': [199401, 200812, '.'], 'rlut': [199401, 200812, '.'], 'cli': [197901, 200812, 'regridded'], 'rlus': [199401, 200812, '.'], 'rlds': [199401, 200812, '.'], 'ts': [199401, 200812, '.'], 'clt': [199401, 200812, '.'], 'vas': [199401, 200812, '.'], 'clw': [197901, 200812, 'regridded'], 'uas': [199401, 200812, '.'], 'wap': [198901, 200812, '.'], 'rsdt': [199401, 200812, '.'], 'rsds': [199401, 200812, '.'], 'hus': [198901, 200812, '.'], 'rsus': [199401, 200812, '.'], 'ta': [198901, 200812, '.'], 'rsut': [199401, 200812, '.']} ],     
+"IPSL/CM5A-LR":   ["Model: AMIP",            ["pr", "clt", "ts", "lai", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", ], {'pr': [199501, 200912, '.'], 'rlut': [199501, 200912, '.'], 'rsus': [199501, 200912, '.'], 'cli': [197901, 200912, 'regridded'], 'rlus': [199501, 200912, '.'], 'rsdt': [199501, 200912, '.'], 'rlds': [199501, 200912, '.'], 'rsdscs': [199501, 200912, '.'], 'ts': [199501, 200912, '.'], 'rlutcs': [199501, 200912, '.'], 'rsutcs': [199501, 200912, '.'], 'rsds': [199501, 200912, '.'], 'rsuscs': [199501, 200912, '.'], 'clt': [199501, 200912, '.'], 'rldscs': [199501, 200912, '.'], 'clw': [197901, 200912, 'regridded'], 'rsut': [199501, 200912, '.'], 'lai': [199501, 200912, '.']} ],         
+"MIROC/MIROC5":   ["Model: AMIP",            ["pr", "clt", "ts", "uas", "vas", "sfcWind", "lai", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", "wap", "hur", ], {'hur': [192001, 200912, '.'], 'rsuscs': [197901, 200812, '.'], 'rsdscs': [197901, 200812, '.'], 'rlutcs': [197901, 200812, '.'], 'rsutcs': [197901, 200812, '.'], 'rldscs': [197901, 200812, '.'], 'pr': [197901, 200812, '.'], 'rlut': [197901, 200812, '.'], 'cli': [197901, 199812, 'regridded'], 'rlus': [197901, 200812, '.'], 'rlds': [197901, 200812, '.'], 'ts': [197901, 200812, '.'], 'clt': [197901, 200812, '.'], 'vas': [197901, 200812, '.'], 'clw': [197901, 200812, 'regridded'], 'uas': [197901, 200812, '.'], 'wap': [192001, 200912, '.'], 'lai': [197901, 200812, '.'], 'rsdt': [197901, 200812, '.'], 'rsds': [197901, 200812, '.'], 'sfcWind': [197901, 200812, '.'], 'rsus': [197901, 200812, '.'], 'rsut': [197901, 200812, '.']} ],         
+"UKMO/HadGEM2-A": ["Model: AMIP",            ["pr", "clt", "ts", "hurs", "uas", "vas", "sfcWind", "rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", "cli", "clw", "wap", "hur", ], {'hur': [197809, 200812, '.'], 'rsuscs': [199501, 200812, '.'], 'rsdscs': [199501, 200812, '.'], 'rlutcs': [199501, 200812, '.'], 'rsutcs': [199501, 200812, '.'], 'rldscs': [199501, 200812, '.'], 'pr': [199501, 200812, '.'], 'rlut': [199501, 200812, '.'], 'cli': [197809, 200811, 'regridded'], 'rlus': [200812, 200812, '.'], 'rlds': [199501, 200812, '.'], 'ts': [199501, 200812, '.'], 'clt': [199501, 200812, '.'], 'vas': [199501, 200812, '.'], 'clw': [197809, 200811, 'regridded'], 'uas': [199501, 200812, '.'], 'wap': [197809, 200812, '.'], 'hurs': [197809, 200812, '.'], 'rsdt': [199501, 200812, '.'], 'rsds': [199501, 200812, '.'], 'sfcWind': [199501, 200812, '.'], 'rsus': [199501, 200812, '.'], 'rsut': [199501, 200812, '.']} ],           
+//                [ 
+"group3":         ["Observation"],
+"NASA/GRACE":     ["Observation", ["zl", "zo", ], {'zl': [200302, 201112, '.'], 'zo': [200302, 201112, '.']} ],            
+"NASA/MODIS":     ["Observation", ["clt", "lai", ], {'cltNobs': [200003, 201109, '.'], 'clt': [200003, 201109, '.'], 'lai': [200002, 200912, '.'], 'cltStddev': [200003, 201109, '.']} ],
+"NASA/AMSRE":     ["Observation", ["tos", ], {'tosNobs': [200206, 201012, '.'], 'tos': [200206, 201012, '.'], 'tosStderr': [200206, 201012, '.']} ],
+"NASA/TRMM":      ["Observation", ["pr", ], {'pr': [199801, 201312, '.']} ],
+"NASA/GPCP":      ["Observation", ["pr", ], {'pr': [197901, 201106, '.']} ],
+"NASA/QuikSCAT":  ["Observation", ["uas", "vas", "sfcWind", ], {'uasNobs': [199908, 200910, '.'], 'vasStderr': [199908, 200910, '.'], 'uas': [199908, 200910, '.'], 'uasStderr': [199908, 200910, '.'], 'vas': [199908, 200910, '.'], 'sfcWind': [199908, 200910, '.'], 'sfcWindStderr': [199908, 200910, '.'], 'sfcWindNobs': [199908, 200910, '.'], 'vasNobs': [199908, 200910, '.']} ],
+"NASA/AVISO":     ["Observation", ["zos", ], {'zos': [199210, 201012, '.']} ],
+"NOAA/NODC":      ["Observation", ["ohc700", "ohc2000", ], {'ohc2000': [200501, 201212, '.'], 'ohc700': [195501, 201212, '.']} ],
+"NASA/CERES":     ["Observation", ["rlds", "rsds", "rlus", "rsus", "rldscs", "rsdscs", "rsuscs", "rsdt", "rlut", "rsut", "rlutcs", "rsutcs", ], {'rlut': [200003, 201206, '.'], 'rlus': [200003, 201002, '.'], 'rlutcs': [200003, 201206, '.'], 'rsuscs': [200003, 201002, '.'], 'rsdscs': [200003, 201002, '.'], 'rsdt': [200003, 201206, '.'], 'rsutcs': [200003, 201206, '.'], 'rsds': [200003, 201002, '.'], 'rlds': [200003, 201002, '.'], 'rldscs': [200003, 201002, '.'], 'rsus': [200003, 201002, '.'], 'rsut': [200003, 201206, '.']} ],
+"NASA/AIRS":      ["Observation", ["tas", "ta", "hus", ], {'hus': [200209, 201105, '.'], 'tas': [200209, 201112, '.'], 'ta': [200209, 201105, '.']} ],
+"NASA/MLS":       ["Observation", ["ta", "hus", ], {'hus': [200408, 201012, '.'], 'ta': [200408, 201012, '.']} ],
+"ARGO/ARGO":      ["Observation", ["ot", "os", ], {'ot': [200101, 201305, '.'], 'os': [200101, 201305, '.']} ],           
+//
+"group4":         ["Reanalysis"],
+"ECMWF/interim":  ["Reanalysis",  ["clt", "tos", "uas", "vas", "sfcWind", "wap", "hur", ], {'tos': [197901, 201402, '.'], 'uas': [199501, 201412, '.'], 'sfcWind': [199501, 201412, '.'], 'hur': [197901, 201402, '.'], 'clt': [197901, 201404, '.'], 'vas': [199501, 201412, '.'], 'wap': [197901, 201402, '.']} ], 
+};

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/html/js2/varList.js
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/html/js2/varList.js b/ApacheCMDA_Frontend_1.0/public/html/js2/varList.js
new file mode 100644
index 0000000..51cb5ad
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/html/js2/varList.js
@@ -0,0 +1,40 @@
+// shortName: [longName, groupName, dimension, units],
+var varList = {
+"pr":       ["Precipitation Flux",                                "", 2, "kg  m-2 s-1"],    
+"clt":      ["Total Cloud Fraction",                              "", 2, "%"],      
+"ts":       ["Surface Temperature",                               "", 2, "K"],     
+"lst_day":  ["Daytime Land Surface Temperature",                  "", 2, "K"],   
+"lst_night":["Nighttime Land Surface Temperature",                "", 2, "K"],   
+"tas":      ["Near-Surface Air Temperature",                      "", 2, "K"],   
+"hurs":     ["Near-Surface Relative Humidity",                    "", 2, "%"],   
+"tos":      ["Sea Surface Temperature",                           "", 2, "K"],         
+"uas":      ["Eastward Near-Surface Wind",                        "", 2, "m s-1"],            
+"vas":      ["Northward Near-Surface Wind",                       "", 2, "m s-1"],             
+"sfcWind":  ["Near-Surface Wind Speed",                           "", 2, "m s-1"],         
+"zos":      ["Sea Surface Height",                                "", 2, "m"],    
+"lai":      ["Leaf Area Index",                                   "", 2, "1"], 
+"zl":       ["Equivalent Water Height Over Land",                 "", 2, "cm"],                   
+"zo":       ["Equivalent Water Height Over Ocean",                "", 2, "cm"],                    
+"ohc700":   ["Ocean Heat Content Anomaly within 700 m Depth",     "", 2, "1e18 joules"],                
+"ohc2000":  ["Ocean Heat Content Anomaly within 2000 m Depth",    "", 2, "1e18 joules"],                
+"rlds":     ["Surface Downwelling Longwave Radiation",            "", 2, "W m-2"],                        
+"rsds":     ["Surface Downwelling Shortwave Radiation",           "", 2, "W m-2"],                         
+"rlus":     ["Surface Upwelling Longwave Radiation",              "", 2, "W m-2"],                      
+"rsus":     ["Surface Upwelling Shortwave Radiation",             "", 2, "W m-2"],                       
+"rldscs":   ["Surface Downwelling Clear-Sky Longwave Radiation",  "", 2, "W m-2"],             
+"rsdscs":   ["Surface Downwelling Clear-Sky Shortwave Radiation", "", 2, "W m-2"],                   
+"rsuscs":   ["Surface Upwelling Clear-Sky Shortwave Radiation",   "", 2, "W m-2"],                
+"rsdt":     ["TOA Incident Shortwave Radiation",                  "", 2, "W m-2"],                  
+"rlut":     ["TOA Outgoing Longwave Radiation",                   "", 2, "W m-2"],                 
+"rsut":     ["TOA Outgoing Shortwave Radiation",                  "", 2, "W m-2"],                  
+"rlutcs":   ["TOA Outgoing Clear-Sky Longwave Radiation",         "", 2, "W m-2"],       
+"rsutcs":   ["TOA Outgoing Clear-Sky Shortwave Radiation",        "", 2, "W m-2"],              
+"ta":       ["Air Temperature",                                   "", 3, "K"], 
+"hus":      ["Specific Humidity",                                 "", 3, "1"],   
+"cli":      ["Cloud Ice Water Content",                           "", 3, "1"],         
+"clw":      ["Cloud Liquid Water Content",                        "", 3, "1"],            
+"ot":       ["Ocean Temperature",                            "ocean", 3, "K"],   
+"os":       ["Ocean Salinity",                               "ocean", 3, "psu"],
+"wap":      ["Vertical Wind Velocity",                            "", 3, "m s-1"],        
+"hur":      ["Relative Humidity",                                 "", 3, "%"],   
+};

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/html/serviceScatterPlot2Vars.html
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/html/serviceScatterPlot2Vars.html b/ApacheCMDA_Frontend_1.0/public/html/serviceScatterPlot2Vars.html
new file mode 100644
index 0000000..6e96fd2
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/html/serviceScatterPlot2Vars.html
@@ -0,0 +1,672 @@
+<!DOCTYPE html>
+
+
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+
+  <!-- for Bootstrap -->
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+  <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
+
+  <!-- still needed? -->
+<!--
+  <script src="js/jquery.flot.min.js"></script>
+  <script src="js/json2.js"></script>
+  <script src="js/xmisc.js"></script>
+-->
+
+  <!-- cmac related -->
+  <link rel="stylesheet" href="js2/common.css">
+  <script src='js2/dataList2.js'></script>
+  <script src='js2/varList.js'></script>
+  <script src='js2/common.js'></script>
+
+  <title>Scatter and Histogram Plot</title>
+
+  <script>
+
+    var Response = null;
+    var variable1 = "";
+    var variable2 = "";
+
+    var naValue = "-999999";
+    var defaultDataIndex = 0; // not used yet
+
+    
+    var isPressure1 = true;
+    
+
+    
+    var pressDf1 = "500";
+    
+    
+
+    
+
+    
+
+    
+      var inputs = {
+'model1':'data1',
+'var1':'var1',
+'pres1':'pres1',
+'model2':'data2',
+'var2':'var2',
+'pres2':'pres2',
+'lon1':'lon0',
+'lon2':'lon1',
+'lat1':'lat0',
+'lat2':'lat1',
+'nSample':'nSample',
+'startT':'t0',
+'endT':'t1',
+'purpose':'purpose',
+'Image':'Image',
+'data_url':'data_url',
+};
+    
+
+    // called on load or reload
+    window.onload = function() {
+      
+      put_data(1);
+      put_data(2);
+      put_var(1);
+      put_var(2);
+      select_var(1);
+      select_var(2);
+      time_range2();
+      //fillMonth();
+
+      disable_download_button();
+
+      
+
+      // parse querystring
+      
+      queries = get_querystring();
+      //for (var key in queries) { if (queries.hasOwnProperty(key)) { alert(key + " -> " + queries[key]); } }
+
+      var key0, key1, v1q;
+
+      for (key0 in queries) {
+        if (!queries.hasOwnProperty(key0)) { continue; }
+        if (!inputs.hasOwnProperty(key0)) { continue; }
+        key1 = inputs[key0];
+        v1q = queries[key0];
+        v1q = v1q.trim();
+
+        if ( key0.slice(0,5) == "model" ) {
+          v1q = v1q.replace("_", "/");
+        }
+
+        if ( key0 == "startT" || key0 == "endT" ) {
+          v1q = v1q.slice(0,4) + "-" + v1q.slice(4,6);
+        }
+
+        if ( key0 == "purpose" ) {
+          v1q = unescape(v1q);
+        }
+
+        try {
+          if ( key1 == "Image" ) {
+            $("#"+key1).html( "<img src='" + v1q + "' width='820'/>" );
+          } else if ( key1 == "data_url" ) {
+            $("#"+key1).val( v1q );
+            enable_download_button();
+          } else {
+            $("#"+key1).val(v1q);
+            $("#"+key1).change();
+          }
+        } catch(err) {}
+      }
+
+/*
+      key1 = "var1";
+      if (queries.hasOwnProperty(key1)) {
+        v1q = queries[key1];
+        v1q = v1q.trim();
+        $("#var1").val(v1q);
+        $("#var1").change();
+      }
+         
+      key1 = "pres1";
+      if (queries.hasOwnProperty(key1)) {
+        v1q = queries[key1];
+        v1q = v1q.trim();
+        $("#pres1").val(v1q);
+      }
+*/
+       
+    }
+
+    $(document).ready(function(){
+      
+
+      $("a").click(function(event){
+        alert("As you can see, the link no longer took you to jquery.com");
+        event.preventDefault();
+      });
+
+
+      $("#download_data").click(function(event) {
+        var durl = $("#data_url").val();
+        // alert(durl);
+        window.location.assign(durl);
+      });
+
+
+      $("#action1").click(function(event) {
+        showUrl(inputs);
+        Response = null;
+
+        // no data to download yet
+        disable_download_button();
+
+        $("#Response").html("Calculating ...");
+        $("#data_url").html("Calculating ...");
+        $("#Image").html("");
+
+        // sample url: http://cmacws.jpl.nasa.gov:8090/svc/scatterPlot2V?model1=ukmo_hadgem2-a&var1=ts&pres1=200&model2=ukmo_hadgem2-a&var2=clt&pres2=200&start_time=199001&end_time=199512&lon1=0&lon2=100&lat1=-29&lat2=29
+        // form url string
+        // var url = "http://cmacws.jpl.nasa.gov:8090/svc/scatterPlot2V?";
+        var url = "http://" + window.location.hostname + ":9002/svc/newScatterPlot2V?";
+        // alert("url: " + url);
+
+        var d1 = $("#data1").val();
+        var model1 = d1.replace("/", "_");
+        model1 = model1.toLowerCase();
+
+        var arglist = "";
+        arglist = arglist.concat("model1=");
+        arglist = arglist.concat(model1);
+
+        // alert("arglist: " + arglist);
+
+        var variable1 = $("#var1").val();
+        arglist = arglist.concat("&var1=");
+        arglist = arglist.concat(variable1);
+
+        // alert("arglist: " + arglist);
+
+        var pres1 = $("#pres1").val();
+        arglist = arglist.concat("&pres1=");
+        arglist = arglist.concat(pres1);
+
+        var d2 = $("#data2").val();
+        var model2 = d2.replace("/", "_");
+        model2 = model2.toLowerCase();
+
+        arglist = arglist.concat("&model2=");
+        arglist = arglist.concat(model2);
+
+        // alert("arglist: " + arglist);
+
+        var variable2 = $("#var2").val();
+        arglist = arglist.concat("&var2=");
+        arglist = arglist.concat(variable2);
+
+        // alert("arglist: " + arglist);
+
+        var pres2 = $("#pres2").val();
+        arglist = arglist.concat("&pres2=");
+        arglist = arglist.concat(pres2);
+
+        var t0 = $("#t0").val();
+        var t1 = $("#t1").val();
+
+        t0 = t0.replace("-", "");
+        t1 = t1.replace("-", "");
+
+        arglist = arglist.concat("&start_time=");
+        arglist = arglist.concat(t0);
+
+        arglist = arglist.concat("&end_time=");
+        arglist = arglist.concat(t1);
+
+        // alert("arglist: " + arglist);
+
+        var lon0 = $("#lon0").val();
+        var lon1 = $("#lon1").val();
+        var lat0 = $("#lat0").val();
+        var lat1 = $("#lat1").val();
+
+        arglist = arglist.concat("&lon1=");
+        arglist = arglist.concat(lon0);
+
+        arglist = arglist.concat("&lon2=");
+        arglist = arglist.concat(lon1);
+
+        arglist = arglist.concat("&lat1=");
+        arglist = arglist.concat(lat0);
+
+        arglist = arglist.concat("&lat2=");
+        arglist = arglist.concat(lat1);
+
+        var nSample = $("#nSample").val();
+        arglist = arglist.concat("&nSample=");
+        arglist = arglist.concat(nSample);
+
+        var purpose = $("#purpose").val();
+        arglist = arglist.concat("&purpose=");
+        arglist = arglist.concat(purpose);
+
+        // alert("arglist: " + arglist);
+
+        // url = url + encodeURIComponent(arglist);
+        url = url + encodeURI(arglist);
+        // url = url + arglist;
+        // alert("url: " + url);
+
+        var urlTimeBounds = "http://" + window.location.hostname + ":9002/svc/two_time_bounds?";
+        var arglistTB = "";
+        arglistTB = arglistTB.concat("serviceType=");
+        arglistTB = arglistTB.concat("2");
+        arglistTB = arglistTB.concat("&source1=");
+        arglistTB = arglistTB.concat(d1);
+        arglistTB = arglistTB.concat("&var1=");
+        arglistTB = arglistTB.concat(variable1);
+        arglistTB = arglistTB.concat("&source2=");
+        arglistTB = arglistTB.concat(d2);
+        arglistTB = arglistTB.concat("&var2=");
+        arglistTB = arglistTB.concat(variable2);
+        urlTimeBounds = urlTimeBounds + encodeURI(arglistTB);
+        // alert("urlTimeBounds: " + urlTimeBounds);
+
+        $.ajax({
+            type: "GET",
+            url: urlTimeBounds,
+            dataType: "json",
+            data: null,
+            success: function(data, textStatus, xhr) {
+                Response = data;
+                // alert("data: " + data);
+                if (data.success == false) {
+                    // alert(data.error);
+                    Response = null;
+                    var text = JSON.stringify(data, null, 4);
+                    text = "Error in backend: <br>" + text; 
+                    $("#Response").html(text);
+                    $("#data_url").html(text);
+                    return;
+                }
+                var text = JSON.stringify(data, null, 4);
+                // alert("text: " + text);
+                // $("#Response").html("<pre>"+text+"</pre>");
+                // $("#Response").html(text);
+
+                var tb1 = data.time_bounds1;
+                var bds1 = String(tb1).split(",");
+                // alert("tb1: " + tb1);
+                // alert("bds1: " + bds1);
+                var lowerT1 = parseInt(bds1[0]);
+                // alert("inside ajax, lowerT1: " + lowerT1);
+                var upperT1 = parseInt(bds1[1]);
+                // alert("upperT1: " + upperT1);
+
+                var tb2 = data.time_bounds2;
+                var bds2 = String(tb2).split(",");
+                // alert("tb2: " + tb2);
+                // alert("bds2: " + bds2);
+                var lowerT2 = parseInt(bds2[0]);
+                // alert("inside ajax, lowerT2: " + lowerT2);
+                var upperT2 = parseInt(bds2[1]);
+                // alert("upperT2: " + upperT2);
+
+                var t0I = parseInt(t0);
+                var t1I = parseInt(t1);
+                // alert("t0: " + t0I);
+                // alert("t1: " + t1I);
+
+                var lowerT, upperT;
+                // compute the intersection of the two data bounds
+                if (lowerT1 == 0  || upperT1 == 0){ // no data-1
+                  alert("We do not have data for the data-1 source and variable configuration.");
+                  return;
+                }
+                else if (lowerT2 == 0  || upperT2 == 0){ // no data-2
+                  alert("We do not have data for the data-2 source and variable configuration.");
+                  return;
+                }
+                else if (lowerT2 > upperT1 || lowerT1 > upperT2) { // no intersection
+                  alert("The two data sets/vars do not have a common time range.");
+                  return;
+                }
+                else { // compute intersection
+                  if (lowerT1 > lowerT2) { // pick bigger lower time bound
+                    lowerT = lowerT1;
+                  }
+                  else {
+                    lowerT = lowerT2;
+                  }
+
+                  if (upperT1 > upperT2) { // pick smaller upper time bound
+                    upperT = upperT2;
+                  }
+                  else {
+                    upperT = upperT1;
+                  }
+                }
+                // alert("lowerT: " + lowerT);
+                // alert("upperT: " + upperT);
+
+                if (t0I < lowerT && t1I < lowerT ||
+                    t0I > upperT && t1I > upperT) {
+                  alert("We do not have data that span your time range. Try the range inside ["+lowerT+", "+upperT+"].");
+                  return;
+                }
+
+                if (t0I < lowerT && t1I <= upperT) {
+                  alert("Your start year-month is out of bound. It has to be in or later than " + lowerT +
+                        ". We will use the range ["+lowerT+", "+t1I+"] for you.");
+                }
+
+                if (t1I > upperT && t0I >= lowerT) {
+                  alert("Your end year-month is out of bound. It has to be in or earlier than " + upperT +
+                        ". We will use the range ["+t0I+", "+upperT+"] for you.");
+                }
+
+                if (t0I < lowerT && t1I > upperT ) {
+                  alert("Both of your start and end year-months are out of bounds. They have to be in or earlier than " + upperT +
+                        ", and in or later than " + lowerT + ". We will use the range ["+lowerT+", "+upperT+"] for you.");
+                }
+            },
+            error: function(xhr, textStatus, errorThrown) {
+		$("#Response").html("error!");
+		$("#data_url").html("error!");
+                // alert("xhr.status: "+xhr.status);
+                // alert("error status: "+textStatus);
+            },
+            complete: function(xhr, textStatus) {
+                //alert("complete status: "+textStatus);
+            },
+        });
+
+
+        $.ajax({
+            type: "GET",
+            url: url,
+            dataType: "json",
+            data: null,
+            success: function(data, textStatus, xhr) {
+                Response = data;
+                // alert("data: " + data);
+                if (data.success == false) {
+                    // alert(data.error);
+                    Response = null;
+                    var text = JSON.stringify(data, null, 4);
+
+                    if (text.indexOf("No Data") != -1) {
+                      $("#Image").html("No Data");
+                      $("#Response").html("No Data");
+                      $("#data_url").html("No Data");
+                      return;
+                    }
+
+                    text = "Error in backend: <br>" + text; 
+                    // $("#Response").html("<span style='color:red'>" + text + "</span>");
+                    $("#Response").html(text);
+                    $("#data_url").html(text);
+
+                    return;
+                }
+                var text = JSON.stringify(data, null, 4);
+                // alert(text);
+                // $("#Response").html("<pre>"+text+"</pre>");
+                $("#Response").html(text);
+
+                var html = "<img src='"+data.url+"' width='820'/>";
+                // alert(html);
+                $("#Image").html(html);
+
+                // post dataUrl to textarea and enable download button
+                $("#data_url").html(data.dataUrl);
+                enable_download_button();
+            },
+            error: function(xhr, textStatus, errorThrown) {
+                $("#Response").html("error!");
+                $("#data_url").html("error!");
+                // alert("xhr.status: "+xhr.status);
+                // alert("error status: "+textStatus);
+            },
+            complete: function(xhr, textStatus) {
+                //alert("complete status: "+textStatus);
+            },
+        });
+
+      });
+      
+    });
+
+
+
+  </script>
+
+</head>
+
+<body>
+<div class="container-fluid">
+<div class="row center1">
+<div class="col-sm-8 col-sm-offset-2 col-xs-12 color-head">
+<h3>Service: Scatter and Histogram Plot of Two Variables</h3>
+This service generates a scatter plot between two specified variables and the histograms of the two variables, and calculates the correlation of the two variables. The two variables can be either a two-dimensional variable or a slice of a three-dimensional variable at a specific pressure level. The number of samples used for this analysis should be specified.
+</div> <!-- col-sm -->
+<div class="col-sm-offset-2">
+</div> <!-- col-sm -->
+</div> <!-- row center1 -->
+
+
+
+<div class="color0">
+<div class="row ">
+<div class="col-sm-12 center1 subtitle1">
+Variable 1
+</div>
+</div> <!-- row --> 
+
+<div class="row">
+ <div class="col-sm-4 right1">
+   model:
+  </div> <!-- col-sm-6 -->
+  <div class="col-sm-8 left1">
+    <select name="data1"  id="data1" onchange="put_var(1); select_var(1); time_range2()"></select>;
+  </div> <!-- col-sm-6 level2-->
+</div> <!-- row -->
+
+<div class="row">
+ <div class="col-sm-4 right1">
+   variable:
+  </div> <!-- col-sm-6 -->
+  <div class="col-sm-8 left1">
+    <select name="var1"  id="var1" onchange="select_var(1); time_range2()"></select>;
+  </div> <!-- col-sm-6 level2-->
+</div> <!-- row -->
+
+
+<div class="row">
+  <div class="col-sm-4 right1" id="pressureLabel1" >
+    pressure:
+  </div> <!-- col-sm-6 level2-->
+  <div class="col-sm-8 left1">
+    <input id="pres1" value="500"  alt="pressure" size=7>
+  </div> <!-- col-sm-6 level2-->
+</div> <!-- row -->
+ 
+
+</div> <!-- color0 -->
+ 
+
+ 
+
+
+
+<div class="color1">
+<div class="row ">
+<div class="col-sm-12 center1 subtitle1">
+Variable 2
+</div>
+</div> <!-- row --> 
+
+<div class="row">
+ <div class="col-sm-4 right1">
+   model:
+  </div> <!-- col-sm-6 -->
+  <div class="col-sm-8 left1">
+    <select name="data2"  id="data2" onchange="put_var(2); select_var(2); time_range2()"></select>;
+  </div> <!-- col-sm-6 level2-->
+</div> <!-- row -->
+
+<div class="row">
+ <div class="col-sm-4 right1">
+   variable:
+  </div> <!-- col-sm-6 -->
+  <div class="col-sm-8 left1">
+    <select name="var2"  id="var2" onchange="select_var(2); time_range2()"></select>;
+  </div> <!-- col-sm-6 level2-->
+</div> <!-- row -->
+
+
+<div class="row">
+  <div class="col-sm-4 right1" id="pressureLabel2" >
+    pressure:
+  </div> <!-- col-sm-6 level2-->
+  <div class="col-sm-8 left1">
+    <input id="pres2" value="500"  alt="pressure" size=7>
+  </div> <!-- col-sm-6 level2-->
+</div> <!-- row -->
+ 
+
+</div> <!-- color1 -->
+ 
+
+
+<div class="color3">
+<div class="row center1 subtitle1" >
+Data Subsetting
+</div> <!-- row -->
+
+
+<div class="row">
+  <div class="col-sm-4 right1">
+    <div id=startYear>start year-month:</div>
+  </div>
+  <div class="col-sm-2 left1">
+    <input id="t0" value="2004-01" alt="start" size=7>
+  </div>
+
+  <div class="col-sm-4 right1">
+    <div id=endYear>end year-month:</div>
+  </div>
+  <div class="col-sm-2 left1">
+    <input id="t1" value="2004-12" alt="end" size=7>
+  </div>
+</div> <!-- row -->
+
+
+<div class="row">
+  <div class="col-sm-4 right1">
+    start lon (deg):
+  </div>
+  <div class="col-sm-2 left1">
+    <input id="lon0" value="0" size=7>
+  </div>
+  <div class="col-sm-4 right1">
+    end lon (deg):
+  </div>
+  <div class="col-sm-2 left1">
+    <input id="lon1" value="360" size=7>
+  </div>
+</div> <!-- row -->
+
+
+<div class="row">
+  <div class="col-sm-4 right1">
+    start lat (deg):
+  </div>
+  <div class="col-sm-2 left1">
+    <input id="lat0" value="-90" size=7>
+  </div>
+  <div class="col-sm-4 right1">
+    end lat (deg):
+  </div>
+  <div class="col-sm-2 left1">
+    <input id="lat1" value="90" size=7>
+  </div>
+</div> <!-- row -->
+
+<div class="row">
+  <div class="col-sm-4 right1">
+    number of samples:
+  </div>
+  <div class="col-sm-8 left1">
+    <input id="nSample" value="500" size=7>  
+  </div>
+</div>
+
+</div> <!-- color3 -->
+
+
+
+
+
+
+<div class="color2">
+<div class="row">
+  <div class="col-sm-4 right1">
+    Execution purpose:
+  </div> <!-- col -->
+  <div class="col-sm-8 left1">
+    <form>
+    <textarea name="purpose" id="purpose" rows="4" cols="50"> </textarea>
+    </form>
+  </div> <!-- col -->
+</div> <!-- row -->
+</div> <!-- color2 -->
+
+<div class="color4">
+<div class="row">
+  <div class="col-sm-4 center1">
+    <input id="action1" type="submit" value="Get Plot" style="height:28px"/>
+  </div>
+  <div class="col-sm-4 center1">
+    <button id="showUrl1" onclick="showUrl(inputs)">Show Service URL</button>
+  </div>
+  <div class="col-sm-4 center1">
+    <form>
+      <input id="download_data" type="button" value="Download Data" style="height:28px"/>
+    </form>
+  </div>
+</div> <!-- row -->
+
+</div> <!-- color4 -->
+
+<div class="row" >
+  <div class="col-sm-12 center1">
+    <textarea readonly id="actionUrl" >Service URL Here</textarea>
+  </div>
+</div> <!-- row -->
+ 			
+<div class="row" center1>
+  <div class="col-sm-12 center1">
+    <div id="Image">Image Here</div>
+  </div>
+</div> <!-- row -->
+
+<div class="row" >
+  <div class="col-sm-12 center1">
+    <textarea id="data_url" cols="150" rows="1">Data URL Here</textarea>
+  </div>
+</div> <!-- row -->
+
+<div class="row" center1>
+  <div class="col-sm-12 center1">
+    <textarea id="Response" cols="150" rows="6">Service Response Text Here</textarea>
+  </div>
+</div> <!-- row -->
+
+</div> <!-- container -->
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/images/giphy.gif
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/images/giphy.gif b/ApacheCMDA_Frontend_1.0/public/images/giphy.gif
new file mode 100644
index 0000000..f5dabf5
Binary files /dev/null and b/ApacheCMDA_Frontend_1.0/public/images/giphy.gif differ

http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/javascripts/exampleUtil.js
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/javascripts/exampleUtil.js b/ApacheCMDA_Frontend_1.0/public/javascripts/exampleUtil.js
new file mode 100644
index 0000000..aeeb2df
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/javascripts/exampleUtil.js
@@ -0,0 +1,126 @@
+/**
+ * Created by Alex on 5/20/2015.
+ */
+
+function loadJSON(path, success, error) {
+  var xhr = new XMLHttpRequest();
+  xhr.onreadystatechange = function () {
+    if (xhr.readyState === 4) {
+      if (xhr.status === 200) {
+        success(JSON.parse(xhr.responseText));
+      }
+      else {
+        error(xhr);
+      }
+    }
+  };
+  xhr.open('GET', path, true);
+  xhr.send();
+}
+
+
+function getScaleFreeNetwork(nodeCount) {
+  var nodes = [];
+  var edges = [];
+  var connectionCount = [];
+
+  // randomly create some nodes and edges
+  for (var i = 0; i < nodeCount; i++) {
+    nodes.push({
+      id: i,
+      label: String(i)
+    });
+
+    connectionCount[i] = 0;
+
+    // create edges in a scale-free-network way
+    if (i == 1) {
+      var from = i;
+      var to = 0;
+      edges.push({
+        from: from,
+        to: to
+      });
+      connectionCount[from]++;
+      connectionCount[to]++;
+    }
+    else if (i > 1) {
+      var conn = edges.length * 2;
+      var rand = Math.floor(Math.random() * conn);
+      var cum = 0;
+      var j = 0;
+      while (j < connectionCount.length && cum < rand) {
+        cum += connectionCount[j];
+        j++;
+      }
+
+
+      var from = i;
+      var to = j;
+      edges.push({
+        from: from,
+        to: to
+      });
+      connectionCount[from]++;
+      connectionCount[to]++;
+    }
+  }
+
+  return {nodes:nodes, edges:edges};
+}
+
+var randomSeed = 764; // Math.round(Math.random()*1000);
+function seededRandom() {
+  var x = Math.sin(randomSeed++) * 10000;
+  return x - Math.floor(x);
+}
+
+function getScaleFreeNetworkSeeded(nodeCount) {
+  var nodes = [];
+  var edges = [];
+  var connectionCount = [];
+
+  // randomly create some nodes and edges
+  for (var i = 0; i < nodeCount; i++) {
+    nodes.push({
+      id: i,
+      label: String(i)
+    });
+
+    connectionCount[i] = 0;
+
+    // create edges in a scale-free-network way
+    if (i == 1) {
+      var from = i;
+      var to = 0;
+      edges.push({
+        from: from,
+        to: to
+      });
+      connectionCount[from]++;
+      connectionCount[to]++;
+    }
+    else if (i > 1) {
+      var conn = edges.length * 2;
+      var rand = Math.floor(seededRandom() * conn);
+      var cum = 0;
+      var j = 0;
+      while (j < connectionCount.length && cum < rand) {
+        cum += connectionCount[j];
+        j++;
+      }
+
+
+      var from = i;
+      var to = j;
+      edges.push({
+        from: from,
+        to: to
+      });
+      connectionCount[from]++;
+      connectionCount[to]++;
+    }
+  }
+
+  return {nodes:nodes, edges:edges};
+}
\ No newline at end of file



[3/5] incubator-cmda git commit: Add KnowledgeGraph page and recommendationSummary page. Update backend models and create new APIs to support new features. Add KnowledgCard in Dataset search result page.

Posted by xi...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/javascripts/googleAnalytics.js
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/javascripts/googleAnalytics.js b/ApacheCMDA_Frontend_1.0/public/javascripts/googleAnalytics.js
new file mode 100644
index 0000000..3bdfc85
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/javascripts/googleAnalytics.js
@@ -0,0 +1,12 @@
+(function (i, s, o, g, r, a, m) {
+  i['GoogleAnalyticsObject'] = r;
+  i[r] = i[r] || function () {
+      (i[r].q = i[r].q || []).push(arguments)
+    }, i[r].l = 1 * new Date();
+  a = s.createElement(o), m = s.getElementsByTagName(o)[0];
+  a.async = 1;
+  a.src = g;
+  m.parentNode.insertBefore(a, m)
+})(window, document, 'script', 'http://www.google-analytics.com/analytics.js', 'ga');
+ga('create', 'UA-61231638-1', 'auto');
+ga('send', 'pageview');
\ No newline at end of file


[2/5] incubator-cmda git commit: Add KnowledgeGraph page and recommendationSummary page. Update backend models and create new APIs to support new features. Add KnowledgCard in Dataset search result page.

Posted by xi...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-cmda/blob/aa50efa2/ApacheCMDA_Frontend_1.0/public/javascripts/vis.js
----------------------------------------------------------------------
diff --git a/ApacheCMDA_Frontend_1.0/public/javascripts/vis.js b/ApacheCMDA_Frontend_1.0/public/javascripts/vis.js
new file mode 100644
index 0000000..3388fc4
--- /dev/null
+++ b/ApacheCMDA_Frontend_1.0/public/javascripts/vis.js
@@ -0,0 +1,43387 @@
+/**
+ * vis.js
+ * https://github.com/almende/vis
+ *
+ * A dynamic, browser-based visualization library.
+ *
+ * @version 4.9.0
+ * @date    2015-10-01
+ *
+ * @license
+ * Copyright (C) 2011-2015 Almende B.V, http://almende.com
+ *
+ * Vis.js is dual licensed under both
+ *
+ * * The Apache 2.0 License
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * and
+ *
+ * * The MIT License
+ *   http://opensource.org/licenses/MIT
+ *
+ * Vis.js may be distributed under either license.
+ */
+
+"use strict";
+
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else if(typeof exports === 'object')
+		exports["vis"] = factory();
+	else
+		root["vis"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = true;
+
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+
+
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+  // utils
+  'use strict';
+
+  exports.util = __webpack_require__(1);
+  exports.DOMutil = __webpack_require__(7);
+
+  // data
+  exports.DataSet = __webpack_require__(8);
+  exports.DataView = __webpack_require__(10);
+  exports.Queue = __webpack_require__(9);
+
+  // Graph3d
+  exports.Graph3d = __webpack_require__(11);
+  exports.graph3d = {
+    Camera: __webpack_require__(15),
+    Filter: __webpack_require__(16),
+    Point2d: __webpack_require__(14),
+    Point3d: __webpack_require__(13),
+    Slider: __webpack_require__(17),
+    StepNumber: __webpack_require__(18)
+  };
+
+  // Timeline
+  exports.Timeline = __webpack_require__(19);
+  exports.Graph2d = __webpack_require__(49);
+  exports.timeline = {
+    DateUtil: __webpack_require__(27),
+    DataStep: __webpack_require__(52),
+    Range: __webpack_require__(24),
+    stack: __webpack_require__(32),
+    TimeStep: __webpack_require__(30),
+
+    components: {
+      items: {
+        Item: __webpack_require__(34),
+        BackgroundItem: __webpack_require__(38),
+        BoxItem: __webpack_require__(36),
+        PointItem: __webpack_require__(37),
+        RangeItem: __webpack_require__(33)
+      },
+
+      Component: __webpack_require__(26),
+      CurrentTime: __webpack_require__(44),
+      CustomTime: __webpack_require__(42),
+      DataAxis: __webpack_require__(51),
+      GraphGroup: __webpack_require__(53),
+      Group: __webpack_require__(31),
+      BackgroundGroup: __webpack_require__(35),
+      ItemSet: __webpack_require__(29),
+      Legend: __webpack_require__(57),
+      LineGraph: __webpack_require__(50),
+      TimeAxis: __webpack_require__(39)
+    }
+  };
+
+  // Network
+  exports.Network = __webpack_require__(59);
+  exports.network = {
+    Images: __webpack_require__(117),
+    dotparser: __webpack_require__(115),
+    gephiParser: __webpack_require__(116),
+    allOptions: __webpack_require__(111)
+  };
+  exports.network.convertDot = function (input) {
+    return exports.network.dotparser.DOTToGraph(input);
+  };
+  exports.network.convertGephi = function (input, options) {
+    return exports.network.gephiParser.parseGephi(input, options);
+  };
+
+  // bundled external libraries
+  exports.moment = __webpack_require__(2);
+  exports.Hammer = __webpack_require__(20);
+  exports.keycharm = __webpack_require__(41);
+
+/***/ },
+/* 1 */
+/***/ function(module, exports, __webpack_require__) {
+
+  // utility functions
+
+  // first check if moment.js is already loaded in the browser window, if so,
+  // use this instance. Else, load via commonjs.
+
+  'use strict';
+
+  var moment = __webpack_require__(2);
+  var uuid = __webpack_require__(6);
+
+  /**
+   * Test whether given object is a number
+   * @param {*} object
+   * @return {Boolean} isNumber
+   */
+  exports.isNumber = function (object) {
+    return object instanceof Number || typeof object == 'number';
+  };
+
+  /**
+   * Remove everything in the DOM object
+   * @param DOMobject
+   */
+  exports.recursiveDOMDelete = function (DOMobject) {
+    if (DOMobject) {
+      while (DOMobject.hasChildNodes() === true) {
+        exports.recursiveDOMDelete(DOMobject.firstChild);
+        DOMobject.removeChild(DOMobject.firstChild);
+      }
+    }
+  };
+
+  /**
+   * this function gives you a range between 0 and 1 based on the min and max values in the set, the total sum of all values and the current value.
+   *
+   * @param min
+   * @param max
+   * @param total
+   * @param value
+   * @returns {number}
+   */
+  exports.giveRange = function (min, max, total, value) {
+    if (max == min) {
+      return 0.5;
+    } else {
+      var scale = 1 / (max - min);
+      return Math.max(0, (value - min) * scale);
+    }
+  };
+
+  /**
+   * Test whether given object is a string
+   * @param {*} object
+   * @return {Boolean} isString
+   */
+  exports.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
+   */
+  exports.isDate = function (object) {
+    if (object instanceof Date) {
+      return true;
+    } else if (exports.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;
+  };
+
+  /**
+   * Create a semi UUID
+   * source: http://stackoverflow.com/a/105074/1262753
+   * @return {String} uuid
+   */
+  exports.randomUUID = function () {
+    return uuid.v4();
+  };
+
+  /**
+   * assign all keys of an object that are not nested objects to a certain value (used for color objects).
+   * @param obj
+   * @param value
+   */
+  exports.assignAllKeys = function (obj, value) {
+    for (var prop in obj) {
+      if (obj.hasOwnProperty(prop)) {
+        if (typeof obj[prop] !== 'object') {
+          obj[prop] = value;
+        }
+      }
+    }
+  };
+
+  /**
+   * Fill an object with a possibly partially defined other object. Only copies values if the a object has an object requiring values.
+   * That means an object is not created on a property if only the b object has it.
+   * @param obj
+   * @param value
+   */
+  exports.fillIfDefined = function (a, b) {
+    var allowDeletion = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
+
+    for (var prop in a) {
+      if (b[prop] !== undefined) {
+        if (typeof b[prop] !== 'object') {
+          if ((b[prop] === undefined || b[prop] === null) && a[prop] !== undefined && allowDeletion === true) {
+            delete a[prop];
+          } else {
+            a[prop] = b[prop];
+          }
+        } else {
+          if (typeof a[prop] === 'object') {
+            exports.fillIfDefined(a[prop], b[prop], allowDeletion);
+          }
+        }
+      }
+    }
+  };
+
+  /**
+   * 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
+   */
+  exports.protoExtend = function (a, b) {
+    for (var i = 1; i < arguments.length; i++) {
+      var other = arguments[i];
+      for (var prop in other) {
+        a[prop] = other[prop];
+      }
+    }
+    return a;
+  };
+
+  /**
+   * 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
+   */
+  exports.extend = function (a, b) {
+    for (var i = 1; i < arguments.length; 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
+   */
+  exports.selectiveExtend = function (props, a, b) {
+    if (!Array.isArray(props)) {
+      throw new Error('Array with property names expected as first argument');
+    }
+
+    for (var i = 2; i < arguments.length; i++) {
+      var other = arguments[i];
+
+      for (var p = 0; p < props.length; p++) {
+        var prop = props[p];
+        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
+   */
+  exports.selectiveDeepExtend = function (props, a, b) {
+    var allowDeletion = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
+
+    // TODO: add support for Arrays to deepExtend
+    if (Array.isArray(b)) {
+      throw new TypeError('Arrays are not supported by deepExtend');
+    }
+    for (var i = 2; i < arguments.length; i++) {
+      var other = arguments[i];
+      for (var p = 0; p < props.length; p++) {
+        var prop = props[p];
+        if (other.hasOwnProperty(prop)) {
+          if (b[prop] && b[prop].constructor === Object) {
+            if (a[prop] === undefined) {
+              a[prop] = {};
+            }
+            if (a[prop].constructor === Object) {
+              exports.deepExtend(a[prop], b[prop], false, allowDeletion);
+            } else {
+              if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+                delete a[prop];
+              } else {
+                a[prop] = b[prop];
+              }
+            }
+          } else if (Array.isArray(b[prop])) {
+            throw new TypeError('Arrays are not supported by deepExtend');
+          } else {
+            if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+              delete a[prop];
+            } else {
+              a[prop] = b[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
+   */
+  exports.selectiveNotDeepExtend = function (props, a, b) {
+    var allowDeletion = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
+
+    // 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 (props.indexOf(prop) == -1) {
+          if (b[prop] && b[prop].constructor === Object) {
+            if (a[prop] === undefined) {
+              a[prop] = {};
+            }
+            if (a[prop].constructor === Object) {
+              exports.deepExtend(a[prop], b[prop]);
+            } else {
+              if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+                delete a[prop];
+              } else {
+                a[prop] = b[prop];
+              }
+            }
+          } else if (Array.isArray(b[prop])) {
+            a[prop] = [];
+            for (var i = 0; i < b[prop].length; i++) {
+              a[prop].push(b[prop][i]);
+            }
+          } else {
+            if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+              delete a[prop];
+            } else {
+              a[prop] = b[prop];
+            }
+          }
+        }
+      }
+    }
+    return a;
+  };
+
+  /**
+   * Deep extend an object a with the properties of object b
+   * @param {Object} a
+   * @param {Object} b
+   * @param [Boolean] protoExtend --> optional parameter. If true, the prototype values will also be extended.
+   *                                  (ie. the options objects that inherit from others will also get the inherited options)
+   * @param [Boolean] global      --> optional parameter. If true, the values of fields that are null will not deleted
+   * @returns {Object}
+   */
+  exports.deepExtend = function (a, b, protoExtend, allowDeletion) {
+    for (var prop in b) {
+      if (b.hasOwnProperty(prop) || protoExtend === true) {
+        if (b[prop] && b[prop].constructor === Object) {
+          if (a[prop] === undefined) {
+            a[prop] = {};
+          }
+          if (a[prop].constructor === Object) {
+            exports.deepExtend(a[prop], b[prop], protoExtend);
+          } else {
+            if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+              delete a[prop];
+            } else {
+              a[prop] = b[prop];
+            }
+          }
+        } else if (Array.isArray(b[prop])) {
+          a[prop] = [];
+          for (var i = 0; i < b[prop].length; i++) {
+            a[prop].push(b[prop][i]);
+          }
+        } else {
+          if (b[prop] === null && a[prop] !== undefined && allowDeletion === true) {
+            delete a[prop];
+          } 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.
+   */
+  exports.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
+   */
+  exports.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 (exports.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 (exports.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 ' + exports.getType(object) + ' to type Date');
+        }
+
+      case 'Moment':
+        if (exports.isNumber(object)) {
+          return moment(object);
+        }
+        if (object instanceof Date) {
+          return moment(object.valueOf());
+        } else if (moment.isMoment(object)) {
+          return moment(object);
+        }
+        if (exports.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 ' + exports.getType(object) + ' to type Date');
+        }
+
+      case 'ISODate':
+        if (exports.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 (exports.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 ' + exports.getType(object) + ' to type ISODate');
+        }
+
+      case 'ASPDate':
+        if (exports.isNumber(object)) {
+          return '/Date(' + object + ')/';
+        } else if (object instanceof Date) {
+          return '/Date(' + object.valueOf() + ')/';
+        } else if (exports.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 ' + exports.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 exports.getType([]) returns 'Array'
+   * @param {*} object
+   * @return {String} type
+   */
+  exports.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 (Array.isArray(object)) {
+        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';
+    } else if (type === undefined) {
+      return 'undefined';
+    }
+
+    return type;
+  };
+
+  /**
+   * Used to extend an array and copy it. This is used to propagate paths recursively.
+   *
+   * @param arr
+   * @param newValue
+   * @returns {Array}
+   */
+  exports.copyAndExtendArray = function (arr, newValue) {
+    var newArr = [];
+    for (var i = 0; i < arr.length; i++) {
+      newArr.push(arr[i]);
+    }
+    newArr.push(newValue);
+    return newArr;
+  };
+
+  /**
+   * Used to extend an array and copy it. This is used to propagate paths recursively.
+   *
+   * @param arr
+   * @param newValue
+   * @returns {Array}
+   */
+  exports.copyArray = function (arr) {
+    var newArr = [];
+    for (var i = 0; i < arr.length; i++) {
+      newArr.push(arr[i]);
+    }
+    return newArr;
+  };
+
+  /**
+   * 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.
+   */
+  exports.getAbsoluteLeft = function (elem) {
+    return elem.getBoundingClientRect().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.
+   */
+  exports.getAbsoluteTop = function (elem) {
+    return elem.getBoundingClientRect().top;
+  };
+
+  /**
+   * add a className to the given elements style
+   * @param {Element} elem
+   * @param {String} className
+   */
+  exports.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
+   */
+  exports.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)
+   */
+  exports.forEach = function (object, callback) {
+    var i, len;
+    if (Array.isArray(object)) {
+      // 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
+   */
+  exports.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
+   */
+  exports.updateProperty = function (object, key, value) {
+    if (object[key] !== value) {
+      object[key] = value;
+      return true;
+    } else {
+      return false;
+    }
+  };
+
+  /**
+   * Throttle the given function to be only executed once every `wait` milliseconds
+   * @param {function} fn
+   * @param {number} wait    Time in milliseconds
+   * @returns {function} Returns the throttled function
+   */
+  exports.throttle = function (fn, wait) {
+    var timeout = null;
+    var needExecution = false;
+
+    return function throttled() {
+      if (!timeout) {
+        needExecution = false;
+        fn();
+
+        timeout = setTimeout(function () {
+          timeout = null;
+          if (needExecution) {
+            throttled();
+          }
+        }, wait);
+      } else {
+        needExecution = true;
+      }
+    };
+  };
+
+  /**
+   * 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]
+   */
+  exports.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]
+   */
+  exports.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);
+    }
+  };
+
+  /**
+   * Cancels the event if it is cancelable, without stopping further propagation of the event.
+   */
+  exports.preventDefault = function (event) {
+    if (!event) event = window.event;
+
+    if (event.preventDefault) {
+      event.preventDefault(); // non-IE browsers
+    } else {
+      event.returnValue = false; // IE browsers
+    }
+  };
+
+  /**
+   * Get HTML element which is the target of the event
+   * @param {Event} event
+   * @return {Element} target element
+   */
+  exports.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;
+  };
+
+  /**
+   * Check if given element contains given parent somewhere in the DOM tree
+   * @param {Element} element
+   * @param {Element} parent
+   */
+  exports.hasParent = function (element, parent) {
+    var e = element;
+
+    while (e) {
+      if (e === parent) {
+        return true;
+      }
+      e = e.parentNode;
+    }
+
+    return false;
+  };
+
+  exports.option = {};
+
+  /**
+   * Convert a value into a boolean
+   * @param {Boolean | function | undefined} value
+   * @param {Boolean} [defaultValue]
+   * @returns {Boolean} bool
+   */
+  exports.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
+   */
+  exports.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
+   */
+  exports.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
+   */
+  exports.option.asSize = function (value, defaultValue) {
+    if (typeof value == 'function') {
+      value = value();
+    }
+
+    if (exports.isString(value)) {
+      return value;
+    } else if (exports.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
+   */
+  exports.option.asElement = function (value, defaultValue) {
+    if (typeof value == 'function') {
+      value = value();
+    }
+
+    return value || defaultValue || null;
+  };
+
+  /**
+   * http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
+   *
+   * @param {String} hex
+   * @returns {{r: *, g: *, b: *}} | 255 range
+   */
+  exports.hexToRGB = function (hex) {
+    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
+    var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+    hex = hex.replace(shorthandRegex, function (m, r, g, b) {
+      return r + r + g + g + b + b;
+    });
+    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+    return result ? {
+      r: parseInt(result[1], 16),
+      g: parseInt(result[2], 16),
+      b: parseInt(result[3], 16)
+    } : null;
+  };
+
+  /**
+   * This function takes color in hex format or rgb() or rgba() format and overrides the opacity. Returns rgba() string.
+   * @param color
+   * @param opacity
+   * @returns {*}
+   */
+  exports.overrideOpacity = function (color, opacity) {
+    if (color.indexOf('rgba') != -1) {
+      return color;
+    } else if (color.indexOf('rgb') != -1) {
+      var rgb = color.substr(color.indexOf('(') + 1).replace(')', '').split(',');
+      return 'rgba(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ',' + opacity + ')';
+    } else {
+      var rgb = exports.hexToRGB(color);
+      if (rgb == null) {
+        return color;
+      } else {
+        return 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + opacity + ')';
+      }
+    }
+  };
+
+  /**
+   *
+   * @param red     0 -- 255
+   * @param green   0 -- 255
+   * @param blue    0 -- 255
+   * @returns {string}
+   * @constructor
+   */
+  exports.RGBToHex = function (red, green, blue) {
+    return '#' + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1);
+  };
+
+  /**
+   * Parse a color property into an object with border, background, and
+   * highlight colors
+   * @param {Object | String} color
+   * @return {Object} colorObject
+   */
+  exports.parseColor = function (color) {
+    var c;
+    if (exports.isString(color) === true) {
+      if (exports.isValidRGB(color) === true) {
+        var rgb = color.substr(4).substr(0, color.length - 5).split(',').map(function (value) {
+          return parseInt(value);
+        });
+        color = exports.RGBToHex(rgb[0], rgb[1], rgb[2]);
+      }
+      if (exports.isValidHex(color) === true) {
+        var hsv = exports.hexToHSV(color);
+        var lighterColorHSV = { h: hsv.h, s: hsv.s * 0.8, v: Math.min(1, hsv.v * 1.02) };
+        var darkerColorHSV = { h: hsv.h, s: Math.min(1, hsv.s * 1.25), v: hsv.v * 0.8 };
+        var darkerColorHex = exports.HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
+        var lighterColorHex = exports.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 || undefined;
+      c.border = color.border || undefined;
+
+      if (exports.isString(color.highlight)) {
+        c.highlight = {
+          border: color.highlight,
+          background: color.highlight
+        };
+      } else {
+        c.highlight = {};
+        c.highlight.background = color.highlight && color.highlight.background || undefined;
+        c.highlight.border = color.highlight && color.highlight.border || undefined;
+      }
+
+      if (exports.isString(color.hover)) {
+        c.hover = {
+          border: color.hover,
+          background: color.hover
+        };
+      } else {
+        c.hover = {};
+        c.hover.background = color.hover && color.hover.background || undefined;
+        c.hover.border = color.hover && color.hover.border || undefined;
+      }
+    }
+
+    return c;
+  };
+
+  /**
+   * http://www.javascripter.net/faq/rgb2hsv.htm
+   *
+   * @param red
+   * @param green
+   * @param blue
+   * @returns {*}
+   * @constructor
+   */
+  exports.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 };
+  };
+
+  var cssUtil = {
+    // split a string with css styles into an object with key/values
+    split: function split(cssText) {
+      var styles = {};
+
+      cssText.split(';').forEach(function (style) {
+        if (style.trim() != '') {
+          var parts = style.split(':');
+          var key = parts[0].trim();
+          var value = parts[1].trim();
+          styles[key] = value;
+        }
+      });
+
+      return styles;
+    },
+
+    // build a css text string from an object with key/values
+    join: function join(styles) {
+      return Object.keys(styles).map(function (key) {
+        return key + ': ' + styles[key];
+      }).join('; ');
+    }
+  };
+
+  /**
+   * Append a string with css styles to an element
+   * @param {Element} element
+   * @param {String} cssText
+   */
+  exports.addCssText = function (element, cssText) {
+    var currentStyles = cssUtil.split(element.style.cssText);
+    var newStyles = cssUtil.split(cssText);
+    var styles = exports.extend(currentStyles, newStyles);
+
+    element.style.cssText = cssUtil.join(styles);
+  };
+
+  /**
+   * Remove a string with css styles from an element
+   * @param {Element} element
+   * @param {String} cssText
+   */
+  exports.removeCssText = function (element, cssText) {
+    var styles = cssUtil.split(element.style.cssText);
+    var removeStyles = cssUtil.split(cssText);
+
+    for (var key in removeStyles) {
+      if (removeStyles.hasOwnProperty(key)) {
+        delete styles[key];
+      }
+    }
+
+    element.style.cssText = cssUtil.join(styles);
+  };
+
+  /**
+   * https://gist.github.com/mjijackson/5311256
+   * @param h
+   * @param s
+   * @param v
+   * @returns {{r: number, g: number, b: number}}
+   * @constructor
+   */
+  exports.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) };
+  };
+
+  exports.HSVToHex = function (h, s, v) {
+    var rgb = exports.HSVToRGB(h, s, v);
+    return exports.RGBToHex(rgb.r, rgb.g, rgb.b);
+  };
+
+  exports.hexToHSV = function (hex) {
+    var rgb = exports.hexToRGB(hex);
+    return exports.RGBToHSV(rgb.r, rgb.g, rgb.b);
+  };
+
+  exports.isValidHex = function (hex) {
+    var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
+    return isOk;
+  };
+
+  exports.isValidRGB = function (rgb) {
+    rgb = rgb.replace(' ', '');
+    var isOk = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(rgb);
+    return isOk;
+  };
+  exports.isValidRGBA = function (rgba) {
+    rgba = rgba.replace(' ', '');
+    var isOk = /rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),(.{1,3})\)/i.test(rgba);
+    return isOk;
+  };
+
+  /**
+   * This recursively redirects the prototype of JSON objects to the referenceObject
+   * This is used for default options.
+   *
+   * @param referenceObject
+   * @returns {*}
+   */
+  exports.selectiveBridgeObject = function (fields, referenceObject) {
+    if (typeof referenceObject == 'object') {
+      var objectTo = Object.create(referenceObject);
+      for (var i = 0; i < fields.length; i++) {
+        if (referenceObject.hasOwnProperty(fields[i])) {
+          if (typeof referenceObject[fields[i]] == 'object') {
+            objectTo[fields[i]] = exports.bridgeObject(referenceObject[fields[i]]);
+          }
+        }
+      }
+      return objectTo;
+    } else {
+      return null;
+    }
+  };
+
+  /**
+   * This recursively redirects the prototype of JSON objects to the referenceObject
+   * This is used for default options.
+   *
+   * @param referenceObject
+   * @returns {*}
+   */
+  exports.bridgeObject = function (referenceObject) {
+    if (typeof referenceObject == 'object') {
+      var objectTo = Object.create(referenceObject);
+      for (var i in referenceObject) {
+        if (referenceObject.hasOwnProperty(i)) {
+          if (typeof referenceObject[i] == 'object') {
+            objectTo[i] = exports.bridgeObject(referenceObject[i]);
+          }
+        }
+      }
+      return objectTo;
+    } else {
+      return null;
+    }
+  };
+
+  /**
+   * this is used to set the options of subobjects in the options object. A requirement of these subobjects
+   * is that they have an 'enabled' element which is optional for the user but mandatory for the program.
+   *
+   * @param [object] mergeTarget | this is either this.options or the options used for the groups.
+   * @param [object] options     | options
+   * @param [String] option      | this is the option key in the options argument
+   * @private
+   */
+  exports.mergeOptions = function (mergeTarget, options, option) {
+    var allowDeletion = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
+    var globalOptions = arguments.length <= 4 || arguments[4] === undefined ? {} : arguments[4];
+
+    if (options[option] === null) {
+      mergeTarget[option] = Object.create(globalOptions[option]);
+    } else {
+      if (options[option] !== undefined) {
+        if (typeof options[option] === 'boolean') {
+          mergeTarget[option].enabled = options[option];
+        } else {
+          if (options[option].enabled === undefined) {
+            mergeTarget[option].enabled = true;
+          }
+          for (var prop in options[option]) {
+            if (options[option].hasOwnProperty(prop)) {
+              mergeTarget[option][prop] = options[option][prop];
+            }
+          }
+        }
+      }
+    }
+  };
+
+  /**
+   * This function does a binary search for a visible item in a sorted list. If we find a visible item, the code that uses
+   * this function will then iterate in both directions over this sorted list to find all visible items.
+   *
+   * @param {Item[]} orderedItems       | Items ordered by start
+   * @param {function} searchFunction   | -1 is lower, 0 is found, 1 is higher
+   * @param {String} field
+   * @param {String} field2
+   * @returns {number}
+   * @private
+   */
+  exports.binarySearchCustom = function (orderedItems, searchFunction, field, field2) {
+    var maxIterations = 10000;
+    var iteration = 0;
+    var low = 0;
+    var high = orderedItems.length - 1;
+
+    while (low <= high && iteration < maxIterations) {
+      var middle = Math.floor((low + high) / 2);
+
+      var item = orderedItems[middle];
+      var value = field2 === undefined ? item[field] : item[field][field2];
+
+      var searchResult = searchFunction(value);
+      if (searchResult == 0) {
+        // jihaa, found a visible item!
+        return middle;
+      } else if (searchResult == -1) {
+        // it is too small --> increase low
+        low = middle + 1;
+      } else {
+        // it is too big --> decrease high
+        high = middle - 1;
+      }
+
+      iteration++;
+    }
+
+    return -1;
+  };
+
+  /**
+   * This function does a binary search for a specific value in a sorted array. If it does not exist but is in between of
+   * two values, we return either the one before or the one after, depending on user input
+   * If it is found, we return the index, else -1.
+   *
+   * @param {Array} orderedItems
+   * @param {{start: number, end: number}} target
+   * @param {String} field
+   * @param {String} sidePreference   'before' or 'after'
+   * @returns {number}
+   * @private
+   */
+  exports.binarySearchValue = function (orderedItems, target, field, sidePreference) {
+    var maxIterations = 10000;
+    var iteration = 0;
+    var low = 0;
+    var high = orderedItems.length - 1;
+    var prevValue, value, nextValue, middle;
+
+    while (low <= high && iteration < maxIterations) {
+      // get a new guess
+      middle = Math.floor(0.5 * (high + low));
+      prevValue = orderedItems[Math.max(0, middle - 1)][field];
+      value = orderedItems[middle][field];
+      nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field];
+
+      if (value == target) {
+        // we found the target
+        return middle;
+      } else if (prevValue < target && value > target) {
+        // target is in between of the previous and the current
+        return sidePreference == 'before' ? Math.max(0, middle - 1) : middle;
+      } else if (value < target && nextValue > target) {
+        // target is in between of the current and the next
+        return sidePreference == 'before' ? middle : Math.min(orderedItems.length - 1, middle + 1);
+      } else {
+        // didnt find the target, we need to change our boundaries.
+        if (value < target) {
+          // it is too small --> increase low
+          low = middle + 1;
+        } else {
+          // it is too big --> decrease high
+          high = middle - 1;
+        }
+      }
+      iteration++;
+    }
+
+    // didnt find anything. Return -1.
+    return -1;
+  };
+
+  /*
+   * Easing Functions - inspired from http://gizma.com/easing/
+   * only considering the t value for the range [0, 1] => [0, 1]
+   * https://gist.github.com/gre/1650294
+   */
+  exports.easingFunctions = {
+    // no easing, no acceleration
+    linear: function linear(t) {
+      return t;
+    },
+    // accelerating from zero velocity
+    easeInQuad: function easeInQuad(t) {
+      return t * t;
+    },
+    // decelerating to zero velocity
+    easeOutQuad: function easeOutQuad(t) {
+      return t * (2 - t);
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutQuad: function easeInOutQuad(t) {
+      return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
+    },
+    // accelerating from zero velocity
+    easeInCubic: function easeInCubic(t) {
+      return t * t * t;
+    },
+    // decelerating to zero velocity
+    easeOutCubic: function easeOutCubic(t) {
+      return --t * t * t + 1;
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutCubic: function easeInOutCubic(t) {
+      return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
+    },
+    // accelerating from zero velocity
+    easeInQuart: function easeInQuart(t) {
+      return t * t * t * t;
+    },
+    // decelerating to zero velocity
+    easeOutQuart: function easeOutQuart(t) {
+      return 1 - --t * t * t * t;
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutQuart: function easeInOutQuart(t) {
+      return t < .5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
+    },
+    // accelerating from zero velocity
+    easeInQuint: function easeInQuint(t) {
+      return t * t * t * t * t;
+    },
+    // decelerating to zero velocity
+    easeOutQuint: function easeOutQuint(t) {
+      return 1 + --t * t * t * t * t;
+    },
+    // acceleration until halfway, then deceleration
+    easeInOutQuint: function easeInOutQuint(t) {
+      return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
+    }
+  };
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+  // first check if moment.js is already loaded in the browser window, if so,
+  // use this instance. Else, load via commonjs.
+  'use strict';
+
+  module.exports = typeof window !== 'undefined' && window['moment'] || __webpack_require__(3);
+
+/***/ },
+/* 3 */
+/***/ function(module, exports, __webpack_require__) {
+
+  /* WEBPACK VAR INJECTION */(function(module) {//! moment.js
+  //! version : 2.10.6
+  //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
+  //! license : MIT
+  //! momentjs.com
+
+  (function (global, factory) {
+       true ? module.exports = factory() :
+      typeof define === 'function' && define.amd ? define(factory) :
+      global.moment = factory()
+  }(this, function () { 'use strict';
+
+      var hookCallback;
+
+      function utils_hooks__hooks () {
+          return hookCallback.apply(null, arguments);
+      }
+
+      // This is done to register the method called with moment()
+      // without creating circular dependencies.
+      function setHookCallback (callback) {
+          hookCallback = callback;
+      }
+
+      function isArray(input) {
+          return Object.prototype.toString.call(input) === '[object Array]';
+      }
+
+      function isDate(input) {
+          return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
+      }
+
+      function map(arr, fn) {
+          var res = [], i;
+          for (i = 0; i < arr.length; ++i) {
+              res.push(fn(arr[i], i));
+          }
+          return res;
+      }
+
+      function hasOwnProp(a, b) {
+          return Object.prototype.hasOwnProperty.call(a, b);
+      }
+
+      function extend(a, b) {
+          for (var i in b) {
+              if (hasOwnProp(b, i)) {
+                  a[i] = b[i];
+              }
+          }
+
+          if (hasOwnProp(b, 'toString')) {
+              a.toString = b.toString;
+          }
+
+          if (hasOwnProp(b, 'valueOf')) {
+              a.valueOf = b.valueOf;
+          }
+
+          return a;
+      }
+
+      function create_utc__createUTC (input, format, locale, strict) {
+          return createLocalOrUTC(input, format, locale, strict, true).utc();
+      }
+
+      function defaultParsingFlags() {
+          // We need to deep clone this object.
+          return {
+              empty           : false,
+              unusedTokens    : [],
+              unusedInput     : [],
+              overflow        : -2,
+              charsLeftOver   : 0,
+              nullInput       : false,
+              invalidMonth    : null,
+              invalidFormat   : false,
+              userInvalidated : false,
+              iso             : false
+          };
+      }
+
+      function getParsingFlags(m) {
+          if (m._pf == null) {
+              m._pf = defaultParsingFlags();
+          }
+          return m._pf;
+      }
+
+      function valid__isValid(m) {
+          if (m._isValid == null) {
+              var flags = getParsingFlags(m);
+              m._isValid = !isNaN(m._d.getTime()) &&
+                  flags.overflow < 0 &&
+                  !flags.empty &&
+                  !flags.invalidMonth &&
+                  !flags.invalidWeekday &&
+                  !flags.nullInput &&
+                  !flags.invalidFormat &&
+                  !flags.userInvalidated;
+
+              if (m._strict) {
+                  m._isValid = m._isValid &&
+                      flags.charsLeftOver === 0 &&
+                      flags.unusedTokens.length === 0 &&
+                      flags.bigHour === undefined;
+              }
+          }
+          return m._isValid;
+      }
+
+      function valid__createInvalid (flags) {
+          var m = create_utc__createUTC(NaN);
+          if (flags != null) {
+              extend(getParsingFlags(m), flags);
+          }
+          else {
+              getParsingFlags(m).userInvalidated = true;
+          }
+
+          return m;
+      }
+
+      var momentProperties = utils_hooks__hooks.momentProperties = [];
+
+      function copyConfig(to, from) {
+          var i, prop, val;
+
+          if (typeof from._isAMomentObject !== 'undefined') {
+              to._isAMomentObject = from._isAMomentObject;
+          }
+          if (typeof from._i !== 'undefined') {
+              to._i = from._i;
+          }
+          if (typeof from._f !== 'undefined') {
+              to._f = from._f;
+          }
+          if (typeof from._l !== 'undefined') {
+              to._l = from._l;
+          }
+          if (typeof from._strict !== 'undefined') {
+              to._strict = from._strict;
+          }
+          if (typeof from._tzm !== 'undefined') {
+              to._tzm = from._tzm;
+          }
+          if (typeof from._isUTC !== 'undefined') {
+              to._isUTC = from._isUTC;
+          }
+          if (typeof from._offset !== 'undefined') {
+              to._offset = from._offset;
+          }
+          if (typeof from._pf !== 'undefined') {
+              to._pf = getParsingFlags(from);
+          }
+          if (typeof from._locale !== 'undefined') {
+              to._locale = from._locale;
+          }
+
+          if (momentProperties.length > 0) {
+              for (i in momentProperties) {
+                  prop = momentProperties[i];
+                  val = from[prop];
+                  if (typeof val !== 'undefined') {
+                      to[prop] = val;
+                  }
+              }
+          }
+
+          return to;
+      }
+
+      var updateInProgress = false;
+
+      // Moment prototype object
+      function Moment(config) {
+          copyConfig(this, config);
+          this._d = new Date(config._d != null ? config._d.getTime() : NaN);
+          // Prevent infinite loop in case updateOffset creates new moment
+          // objects.
+          if (updateInProgress === false) {
+              updateInProgress = true;
+              utils_hooks__hooks.updateOffset(this);
+              updateInProgress = false;
+          }
+      }
+
+      function isMoment (obj) {
+          return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
+      }
+
+      function absFloor (number) {
+          if (number < 0) {
+              return Math.ceil(number);
+          } else {
+              return Math.floor(number);
+          }
+      }
+
+      function toInt(argumentForCoercion) {
+          var coercedNumber = +argumentForCoercion,
+              value = 0;
+
+          if (coercedNumber !== 0 && isFinite(coercedNumber)) {
+              value = absFloor(coercedNumber);
+          }
+
+          return value;
+      }
+
+      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 Locale() {
+      }
+
+      var locales = {};
+      var globalLocale;
+
+      function normalizeLocale(key) {
+          return key ? key.toLowerCase().replace('_', '-') : key;
+      }
+
+      // pick the locale 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
+      function chooseLocale(names) {
+          var i = 0, j, next, locale, split;
+
+          while (i < names.length) {
+              split = normalizeLocale(names[i]).split('-');
+              j = split.length;
+              next = normalizeLocale(names[i + 1]);
+              next = next ? next.split('-') : null;
+              while (j > 0) {
+                  locale = loadLocale(split.slice(0, j).join('-'));
+                  if (locale) {
+                      return locale;
+                  }
+                  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 null;
+      }
+
+      function loadLocale(name) {
+          var oldLocale = null;
+          // TODO: Find a better way to register and load all the locales in Node
+          if (!locales[name] && typeof module !== 'undefined' &&
+                  module && module.exports) {
+              try {
+                  oldLocale = globalLocale._abbr;
+                  !(function webpackMissingModule() { var e = new Error("Cannot find module \"./locale\""); e.code = 'MODULE_NOT_FOUND'; throw e; }());
+                  // because defineLocale currently also sets the global locale, we
+                  // want to undo that for lazy loaded locales
+                  locale_locales__getSetGlobalLocale(oldLocale);
+              } catch (e) { }
+          }
+          return locales[name];
+      }
+
+      // This function will load locale and then set the global locale.  If
+      // no arguments are passed in, it will simply return the current global
+      // locale key.
+      function locale_locales__getSetGlobalLocale (key, values) {
+          var data;
+          if (key) {
+              if (typeof values === 'undefined') {
+                  data = locale_locales__getLocale(key);
+              }
+              else {
+                  data = defineLocale(key, values);
+              }
+
+              if (data) {
+                  // moment.duration._locale = moment._locale = data;
+                  globalLocale = data;
+              }
+          }
+
+          return globalLocale._abbr;
+      }
+
+      function defineLocale (name, values) {
+          if (values !== null) {
+              values.abbr = name;
+              locales[name] = locales[name] || new Locale();
+              locales[name].set(values);
+
+              // backwards compat for now: also set the locale
+              locale_locales__getSetGlobalLocale(name);
+
+              return locales[name];
+          } else {
+              // useful for testing
+              delete locales[name];
+              return null;
+          }
+      }
+
+      // returns locale data
+      function locale_locales__getLocale (key) {
+          var locale;
+
+          if (key && key._locale && key._locale._abbr) {
+              key = key._locale._abbr;
+          }
+
+          if (!key) {
+              return globalLocale;
+          }
+
+          if (!isArray(key)) {
+              //short-circuit everything else
+              locale = loadLocale(key);
+              if (locale) {
+                  return locale;
+              }
+              key = [key];
+          }
+
+          return chooseLocale(key);
+      }
+
+      var aliases = {};
+
+      function addUnitAlias (unit, shorthand) {
+          var lowerCase = unit.toLowerCase();
+          aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
+      }
+
+      function normalizeUnits(units) {
+          return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
+      }
+
+      function normalizeObjectUnits(inputObject) {
+          var normalizedInput = {},
+              normalizedProp,
+              prop;
+
+          for (prop in inputObject) {
+              if (hasOwnProp(inputObject, prop)) {
+                  normalizedProp = normalizeUnits(prop);
+                  if (normalizedProp) {
+                      normalizedInput[normalizedProp] = inputObject[prop];
+                  }
+              }
+          }
+
+          return normalizedInput;
+      }
+
+      function makeGetSet (unit, keepTime) {
+          return function (value) {
+              if (value != null) {
+                  get_set__set(this, unit, value);
+                  utils_hooks__hooks.updateOffset(this, keepTime);
+                  return this;
+              } else {
+                  return get_set__get(this, unit);
+              }
+          };
+      }
+
+      function get_set__get (mom, unit) {
+          return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();
+      }
+
+      function get_set__set (mom, unit, value) {
+          return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
+      }
+
+      // MOMENTS
+
+      function getSet (units, value) {
+          var unit;
+          if (typeof units === 'object') {
+              for (unit in units) {
+                  this.set(unit, units[unit]);
+              }
+          } else {
+              units = normalizeUnits(units);
+              if (typeof this[units] === 'function') {
+                  return this[units](value);
+              }
+          }
+          return this;
+      }
+
+      function zeroFill(number, targetLength, forceSign) {
+          var absNumber = '' + Math.abs(number),
+              zerosToFill = targetLength - absNumber.length,
+              sign = number >= 0;
+          return (sign ? (forceSign ? '+' : '') : '-') +
+              Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
+      }
+
+      var 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,9}|x|X|zz?|ZZ?|.)/g;
+
+      var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
+
+      var formatFunctions = {};
+
+      var formatTokenFunctions = {};
+
+      // token:    'M'
+      // padded:   ['MM', 2]
+      // ordinal:  'Mo'
+      // callback: function () { this.month() + 1 }
+      function addFormatToken (token, padded, ordinal, callback) {
+          var func = callback;
+          if (typeof callback === 'string') {
+              func = function () {
+                  return this[callback]();
+              };
+          }
+          if (token) {
+              formatTokenFunctions[token] = func;
+          }
+          if (padded) {
+              formatTokenFunctions[padded[0]] = function () {
+                  return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
+              };
+          }
+          if (ordinal) {
+              formatTokenFunctions[ordinal] = function () {
+                  return this.localeData().ordinal(func.apply(this, arguments), token);
+              };
+          }
+      }
+
+      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.localeData().invalidDate();
+          }
+
+          format = expandFormat(format, m.localeData());
+          formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
+
+          return formatFunctions[format](m);
+      }
+
+      function expandFormat(format, locale) {
+          var i = 5;
+
+          function replaceLongDateFormatTokens(input) {
+              return locale.longDateFormat(input) || input;
+          }
+
+          localFormattingTokens.lastIndex = 0;
+          while (i >= 0 && localFormattingTokens.test(format)) {
+              format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
+              localFormattingTokens.lastIndex = 0;
+              i -= 1;
+          }
+
+          return format;
+      }
+
+      var match1         = /\d/;            //       0 - 9
+      var match2         = /\d\d/;          //      00 - 99
+      var match3         = /\d{3}/;         //     000 - 999
+      var match4         = /\d{4}/;         //    0000 - 9999
+      var match6         = /[+-]?\d{6}/;    // -999999 - 999999
+      var match1to2      = /\d\d?/;         //       0 - 99
+      var match1to3      = /\d{1,3}/;       //       0 - 999
+      var match1to4      = /\d{1,4}/;       //       0 - 9999
+      var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999
+
+      var matchUnsigned  = /\d+/;           //       0 - inf
+      var matchSigned    = /[+-]?\d+/;      //    -inf - inf
+
+      var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
+
+      var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
+
+      // any word (or two) characters or numbers including two/three word month in arabic.
+      var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
+
+      var regexes = {};
+
+      function isFunction (sth) {
+          // https://github.com/moment/moment/issues/2325
+          return typeof sth === 'function' &&
+              Object.prototype.toString.call(sth) === '[object Function]';
+      }
+
+
+      function addRegexToken (token, regex, strictRegex) {
+          regexes[token] = isFunction(regex) ? regex : function (isStrict) {
+              return (isStrict && strictRegex) ? strictRegex : regex;
+          };
+      }
+
+      function getParseRegexForToken (token, config) {
+          if (!hasOwnProp(regexes, token)) {
+              return new RegExp(unescapeFormat(token));
+          }
+
+          return regexes[token](config._strict, config._locale);
+      }
+
+      // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+      function unescapeFormat(s) {
+          return s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
+              return p1 || p2 || p3 || p4;
+          }).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+      }
+
+      var tokens = {};
+
+      function addParseToken (token, callback) {
+          var i, func = callback;
+          if (typeof token === 'string') {
+              token = [token];
+          }
+          if (typeof callback === 'number') {
+              func = function (input, array) {
+                  array[callback] = toInt(input);
+              };
+          }
+          for (i = 0; i < token.length; i++) {
+              tokens[token[i]] = func;
+          }
+      }
+
+      function addWeekParseToken (token, callback) {
+          addParseToken(token, function (input, array, config, token) {
+              config._w = config._w || {};
+              callback(input, config._w, config, token);
+          });
+      }
+
+      function addTimeToArrayFromToken(token, input, config) {
+          if (input != null && hasOwnProp(tokens, token)) {
+              tokens[token](input, config._a, config, token);
+          }
+      }
+
+      var YEAR = 0;
+      var MONTH = 1;
+      var DATE = 2;
+      var HOUR = 3;
+      var MINUTE = 4;
+      var SECOND = 5;
+      var MILLISECOND = 6;
+
+      function daysInMonth(year, month) {
+          return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
+      }
+
+      // FORMATTING
+
+      addFormatToken('M', ['MM', 2], 'Mo', function () {
+          return this.month() + 1;
+      });
+
+      addFormatToken('MMM', 0, 0, function (format) {
+          return this.localeData().monthsShort(this, format);
+      });
+
+      addFormatToken('MMMM', 0, 0, function (format) {
+          return this.localeData().months(this, format);
+      });
+
+      // ALIASES
+
+      addUnitAlias('month', 'M');
+
+      // PARSING
+
+      addRegexToken('M',    match1to2);
+      addRegexToken('MM',   match1to2, match2);
+      addRegexToken('MMM',  matchWord);
+      addRegexToken('MMMM', matchWord);
+
+      addParseToken(['M', 'MM'], function (input, array) {
+          array[MONTH] = toInt(input) - 1;
+      });
+
+      addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
+          var month = config._locale.monthsParse(input, token, config._strict);
+          // if we didn't find a month name, mark the date as invalid.
+          if (month != null) {
+              array[MONTH] = month;
+          } else {
+              getParsingFlags(config).invalidMonth = input;
+          }
+      });
+
+      // LOCALES
+
+      var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
+      function localeMonths (m) {
+          return this._months[m.month()];
+      }
+
+      var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
+      function localeMonthsShort (m) {
+          return this._monthsShort[m.month()];
+      }
+
+      function localeMonthsParse (monthName, format, strict) {
+          var i, mom, regex;
+
+          if (!this._monthsParse) {
+              this._monthsParse = [];
+              this._longMonthsParse = [];
+              this._shortMonthsParse = [];
+          }
+
+          for (i = 0; i < 12; i++) {
+              // make the regex if we don't have it already
+              mom = create_utc__createUTC([2000, i]);
+              if (strict && !this._longMonthsParse[i]) {
+                  this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+                  this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+              }
+              if (!strict && !this._monthsParse[i]) {
+                  regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
+                  this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
+              }
+              // test the regex
+              if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+                  return i;
+              } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+                  return i;
+              } else if (!strict && this._monthsParse[i].test(monthName)) {
+                  return i;
+              }
+          }
+      }
+
+      // MOMENTS
+
+      function setMonth (mom, value) {
+          var dayOfMonth;
+
+          // TODO: Move this out of here!
+          if (typeof value === 'string') {
+              value = mom.localeData().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 getSetMonth (value) {
+          if (value != null) {
+              setMonth(this, value);
+              utils_hooks__hooks.updateOffset(this, true);
+              return this;
+          } else {
+              return get_set__get(this, 'Month');
+          }
+      }
+
+      function getDaysInMonth () {
+          return daysInMonth(this.year(), this.month());
+      }
+
+      function checkOverflow (m) {
+          var overflow;
+          var a = m._a;
+
+          if (a && getParsingFlags(m).overflow === -2) {
+              overflow =
+                  a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
+                  a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
+                  a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
+                  a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
+                  a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
+                  a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
+                  -1;
+
+              if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
+                  overflow = DATE;
+              }
+
+              getParsingFlags(m).overflow = overflow;
+          }
+
+          return m;
+      }
+
+      function warn(msg) {
+          if (utils_hooks__hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {
+              console.warn('Deprecation warning: ' + msg);
+          }
+      }
+
+      function deprecate(msg, fn) {
+          var firstTime = true;
+
+          return extend(function () {
+              if (firstTime) {
+                  warn(msg + '\n' + (new Error()).stack);
+                  firstTime = false;
+              }
+              return fn.apply(this, arguments);
+          }, fn);
+      }
+
+      var deprecations = {};
+
+      function deprecateSimple(name, msg) {
+          if (!deprecations[name]) {
+              warn(msg);
+              deprecations[name] = true;
+          }
+      }
+
+      utils_hooks__hooks.suppressDeprecationWarnings = false;
+
+      var from_string__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)?)?$/;
+
+      var 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
+      var 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/]
+      ];
+
+      var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
+
+      // date from iso format
+      function configFromISO(config) {
+          var i, l,
+              string = config._i,
+              match = from_string__isoRegex.exec(string);
+
+          if (match) {
+              getParsingFlags(config).iso = true;
+              for (i = 0, l = isoDates.length; i < l; i++) {
+                  if (isoDates[i][1].exec(string)) {
+                      config._f = isoDates[i][0];
+                      break;
+                  }
+              }
+              for (i = 0, l = isoTimes.length; i < l; i++) {
+                  if (isoTimes[i][1].exec(string)) {
+                      // match[6] should be 'T' or space
+                      config._f += (match[6] || ' ') + isoTimes[i][0];
+                      break;
+                  }
+              }
+              if (string.match(matchOffset)) {
+                  config._f += 'Z';
+              }
+              configFromStringAndFormat(config);
+          } else {
+              config._isValid = false;
+          }
+      }
+
+      // date from iso format or fallback
+      function configFromString(config) {
+          var matched = aspNetJsonRegex.exec(config._i);
+
+          if (matched !== null) {
+              config._d = new Date(+matched[1]);
+              return;
+          }
+
+          configFromISO(config);
+          if (config._isValid === false) {
+              delete config._isValid;
+              utils_hooks__hooks.createFromInputFallback(config);
+          }
+      }
+
+      utils_hooks__hooks.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 + (config._useUTC ? ' UTC' : ''));
+          }
+      );
+
+      function createDate (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 createUTCDate (y) {
+          var date = new Date(Date.UTC.apply(null, arguments));
+          if (y < 1970) {
+              date.setUTCFullYear(y);
+          }
+          return date;
+      }
+
+      addFormatToken(0, ['YY', 2], 0, function () {
+          return this.year() % 100;
+      });
+
+      addFormatToken(0, ['YYYY',   4],       0, 'year');
+      addFormatToken(0, ['YYYYY',  5],       0, 'year');
+      addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
+
+      // ALIASES
+
+      addUnitAlias('year', 'y');
+
+      // PARSING
+
+      addRegexToken('Y',      matchSigned);
+      addRegexToken('YY',     match1to2, match2);
+      addRegexToken('YYYY',   match1to4, match4);
+      addRegexToken('YYYYY',  match1to6, match6);
+      addRegexToken('YYYYYY', match1to6, match6);
+
+      addParseToken(['YYYYY', 'YYYYYY'], YEAR);
+      addParseToken('YYYY', function (input, array) {
+          array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input);
+      });
+      addParseToken('YY', function (input, array) {
+          array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input);
+      });
+
+      // HELPERS
+
+      function daysInYear(year) {
+          return isLeapYear(year) ? 366 : 365;
+      }
+
+      function isLeapYear(year) {
+          return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
+      }
+
+      // HOOKS
+
+      utils_hooks__hooks.parseTwoDigitYear = function (input) {
+          return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
+      };
+
+      // MOMENTS
+
+      var getSetYear = makeGetSet('FullYear', false);
+
+      function getIsLeapYear () {
+          return isLeapYear(this.year());
+      }
+
+      addFormatToken('w', ['ww', 2], 'wo', 'week');
+      addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
+
+      // ALIASES
+
+      addUnitAlias('week', 'w');
+      addUnitAlias('isoWeek', 'W');
+
+      // PARSING
+
+      addRegexToken('w',  match1to2);
+      addRegexToken('ww', match1to2, match2);
+      addRegexToken('W',  match1to2);
+      addRegexToken('WW', match1to2, match2);
+
+      addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
+          week[token.substr(0, 1)] = toInt(input);
+      });
+
+      // HELPERS
+
+      // 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 = local__createLocal(mom).add(daysToDayOfWeek, 'd');
+          return {
+              week: Math.ceil(adjustedMoment.dayOfYear() / 7),
+              year: adjustedMoment.year()
+          };
+      }
+
+      // LOCALES
+
+      function localeWeek (mom) {
+          return weekOfYear(mom, this._week.dow, this._week.doy).week;
+      }
+
+      var defaultLocaleWeek = {
+          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.
+      };
+
+      function localeFirstDayOfWeek () {
+          return this._week.dow;
+      }
+
+      function localeFirstDayOfYear () {
+          return this._week.doy;
+      }
+
+      // MOMENTS
+
+      function getSetWeek (input) {
+          var week = this.localeData().week(this);
+          return input == null ? week : this.add((input - week) * 7, 'd');
+      }
+
+      function getSetISOWeek (input) {
+          var week = weekOfYear(this, 1, 4).week;
+          return input == null ? week : this.add((input - week) * 7, 'd');
+      }
+
+      addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
+
+      // ALIASES
+
+      addUnitAlias('dayOfYear', 'DDD');
+
+      // PARSING
+
+      addRegexToken('DDD',  match1to3);
+      addRegexToken('DDDD', match3);
+      addParseToken(['DDD', 'DDDD'], function (input, array, config) {
+          config._dayOfYear = toInt(input);
+      });
+
+      // HELPERS
+
+      //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 week1Jan = 6 + firstDayOfWeek - firstDayOfWeekOfYear, janX = createUTCDate(year, 0, 1 + week1Jan), d = janX.getUTCDay(), dayOfYear;
+          if (d < firstDayOfWeek) {
+              d += 7;
+          }
+
+          weekday = weekday != null ? 1 * weekday : firstDayOfWeek;
+
+          dayOfYear = 1 + week1Jan + 7 * (week - 1) - d + weekday;
+
+          return {
+              year: dayOfYear > 0 ? year : year - 1,
+              dayOfYear: dayOfYear > 0 ?  dayOfYear : daysInYear(year - 1) + dayOfYear
+          };
+      }
+
+      // MOMENTS
+
+      function getSetDayOfYear (input) {
+          var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
+          return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
+      }
+
+      // Pick the first defined of two or three arguments.
+      function defaults(a, b, c) {
+          if (a != null) {
+              return a;
+          }
+          if (b != null) {
+              return b;
+          }
+          return c;
+      }
+
+      function currentDateArray(config) {
+          var now = new Date();
+          if (config._useUTC) {
+              return [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()];
+          }
+          return [now.getFullYear(), now.getMonth(), now.getDate()];
+      }
+
+      // 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 configFromArray (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 = defaults(config._a[YEAR], currentDate[YEAR]);
+
+              if (config._dayOfYear > daysInYear(yearToUse)) {
+                  getParsingFlags(config)._overflowDayOfYear = true;
+              }
+
+              date = createUTCDate(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];
+          }
+
+          // Check for 24:00:00.000
+          if (config._a[HOUR] === 24 &&
+                  config._a[MINUTE] === 0 &&
+                  config._a[SECOND] === 0 &&
+                  config._a[MILLISECOND] === 0) {
+              config._nextDay = true;
+              config._a[HOUR] = 0;
+          }
+
+          config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
+          // Apply timezone offset from input. The actual utcOffset can be changed
+          // with parseZone.
+          if (config._tzm != null) {
+              config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
+          }
+
+          if (config._nextDay) {
+              config._a[HOUR] = 24;
+          }
+      }
+
+      function dayOfYearFromWeekInfo(config) {
+          var w, weekYear, week, weekday, dow, doy, temp;
+
+          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 = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year);
+              week = defaults(w.W, 1);
+              weekday = defaults(w.E, 1);
+          } else {
+              dow = config._locale._week.dow;
+              doy = config._locale._week.doy;
+
+              weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year);
+              week = defaults(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;
+      }
+
+      utils_hooks__hooks.ISO_8601 = function () {};
+
+      // date from string and format string
+      function configFromStringAndFormat(config) {
+          // TODO: Move this to another part of the creation flow to prevent circular deps
+          if (config._f === utils_hooks__hooks.ISO_8601) {
+              configFromISO(config);
+              return;
+          }
+
+          config._a = [];
+          getParsingFlags(config).empty = true;
+
+          // This array is used to make a Date, either with `new Date` or `Date.UTC`
+          var string = '' + config._i,
+              i, parsedInput, tokens, token, skipped,
+              stringLength = string.length,
+              totalParsedInputLength = 0;
+
+          tokens = expandFormat(config._f, config._locale).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) {
+                      getParsingFlags(config).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) {
+                      getParsingFlags(config).empty = false;
+                  }
+                  else {
+                      getParsingFlags(config).unusedTokens.push(token);
+                  }
+                  addTimeToArrayFromToken(token, parsedInput, config);
+              }
+              else if (config._strict && !parsedInput) {
+                  getParsingFlags(config).unusedTokens.push(token);
+              }
+          }
+
+          // add remaining unparsed input length to the string
+          getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
+          if (string.length > 0) {
+              getParsingFlags(config).unusedInput.push(string);
+          }
+
+          // clear _12h flag if hour is <= 12
+          if (getParsingFlags(config).bigHour === true &&
+                  config._a[HOUR] <= 12 &&
+ 

<TRUNCATED>