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;">  
- <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>