You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sdap.apache.org by le...@apache.org on 2017/10/27 22:34:42 UTC
[01/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Repository: incubator-sdap-mudrod
Updated Branches:
refs/heads/master [created] 7b76fa168
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/underscore-min.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/underscore-min.js b/web/META-INF/resources/js/libs/underscore-min.js
new file mode 100644
index 0000000..f01025b
--- /dev/null
+++ b/web/META-INF/resources/js/libs/underscore-min.js
@@ -0,0 +1,6 @@
+// Underscore.js 1.8.3
+// http://underscorejs.org
+// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// Underscore may be freely distributed under the MIT license.
+(function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.h
asOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="1.8.3";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}}
,j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)
&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var
a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.c
all(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,
r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])<u?i=a+1:o=a}return i},m.i
ndexOf=r(1,m.findIndex,m.sortedIndex),m.lastIndexOf=r(-1,m.findLastIndex),m.range=function(n,t,r){null==t&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e<arguments.length;)i.push(arguments[e++]);return E(n,r,this,this,i)};return r},m.bindAll=function(n){var t,r,e=arguments.length;if(1>=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.
memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return func
tion(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e
,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=
function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t)
,i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))}
,m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n)
.join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i
="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=f
unction(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this);
+//# sourceMappingURL=underscore-min.map
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/services.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/services.js b/web/META-INF/resources/js/services.js
new file mode 100755
index 0000000..3d80be4
--- /dev/null
+++ b/web/META-INF/resources/js/services.js
@@ -0,0 +1,127 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+/* Services */
+
+var mudrodServices = angular.module('mudrodServices', ['ngResource']);
+
+mudrodServices.factory('MetaData', ['$resource',
+ function($resource) {
+ return $resource("services/metadata/search/", {}, {
+ get: {method: 'GET', cache: false, isArray: false}
+ });
+ }]);
+
+mudrodServices.factory('VocabList', ['$resource',
+ function($resource) {
+ return $resource("services/vocabulary/search/", {}, {
+ get: {method: 'GET', cache: false, isArray: false}
+ });
+ }]);
+
+mudrodServices.factory('Autocomplete', ['$resource',
+ function($resource) {
+ return $resource("services/autocomplete/query", {}, {
+ get: {method: 'GET', cache: false, isArray: true}
+ });
+ }]);
+
+mudrodServices.factory('DatasetDetail', ['$resource',
+ function($resource) {
+ return $resource("services/datasetdetail/search/", {}, {
+ get: {method: 'GET', cache: false, isArray: false}
+ });
+ }]);
+
+mudrodServices.factory('HRecommendation', ['$resource',
+ function($resource) {
+ return $resource("services/hrecommendation/search/", {}, {
+ get: {method: 'GET', cache: false, isArray: false}
+ });
+ }]);
+
+mudrodServices.factory('SearchOptions', function(){
+ var searchOptions = {'opt':'Or'};
+ return {
+ getSearchOptions: function () {
+ return searchOptions;
+ },
+ setSearchOptions: function (value) {
+ searchOptions = value;
+ }
+ };
+});
+
+mudrodServices.factory('PagerService',
+ function() {
+ // service definition
+ var service = {};
+
+ service.GetPager = GetPager;
+
+ return service;
+
+ // service implementation
+ function GetPager(totalItems, currentPage, pageSize) {
+ // default to first page
+ currentPage = currentPage || 1;
+
+ // default page size is 10
+ pageSize = pageSize || 10;
+
+ // calculate total pages
+ var totalPages = Math.ceil(totalItems / pageSize);
+
+ var startPage, endPage;
+ if (totalPages <= 10) {
+ // less than 10 total pages so show all
+ startPage = 1;
+ endPage = totalPages;
+ } else {
+ // more than 10 total pages so calculate start and end pages
+ if (currentPage <= 6) {
+ startPage = 1;
+ endPage = 10;
+ } else if (currentPage + 4 >= totalPages) {
+ startPage = totalPages - 9;
+ endPage = totalPages;
+ } else {
+ startPage = currentPage - 5;
+ endPage = currentPage + 4;
+ }
+ }
+
+ // calculate start and end item indexes
+ var startIndex = (currentPage - 1) * pageSize;
+ var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
+
+ // create an array of pages to ng-repeat in the pager control
+ var pages = _.range(startPage, endPage + 1);
+
+ // return object with all pager properties required by the view
+ return {
+ totalItems: totalItems,
+ currentPage: currentPage,
+ pageSize: pageSize,
+ totalPages: totalPages,
+ startPage: startPage,
+ endPage: endPage,
+ startIndex: startIndex,
+ endIndex: endIndex,
+ pages: pages
+ };
+ }
+ });
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/datasetResults.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/datasetResults.html b/web/META-INF/resources/partials/datasetResults.html
new file mode 100644
index 0000000..4e21b87
--- /dev/null
+++ b/web/META-INF/resources/partials/datasetResults.html
@@ -0,0 +1,152 @@
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+<div ng-include src="'partials/navbar-search.html'"></div>
+
+<div id="container" class="container view-area-fixed">
+ <div class="row no-gutter content-holder">
+ <div class="col-md-9 col-sm-8" id="content">
+ <div class="panel panel-primary post-holder">
+ <div class="panel-heading">
+ <h4 class="panel-title">
+ <strong class="title">{{dataset['Short Name']}}</strong>
+ </h4>
+ </div>
+ <div class="panel-body">
+ <table class="table table-strip">
+ <tbody>
+ <tr>
+ <td>Long Name</td>
+ <td>{{dataset['Long Name']}}</td>
+ </tr>
+ <tr>
+ <td>Landing Page</td>
+ <td>
+ <a ng-href="https://podaac.jpl.nasa.gov/dataset/{{dataset['Short Name'] | urlencode}}" target="_blank">https://podaac.jpl.nasa.gov/dataset/{{dataset['Short Name']}}</a>
+ </td>
+ </tr>
+ <tr>
+ <td>DOI</td>
+ <td>
+ <a ng-if="dataset['Dataset-Doi']" ng-href="https://podaac.jpl.nasa.gov/dataset/{{dataset['Short Name'] | urlencode}}" target="_blank">{{dataset['Dataset-Doi']}}</a>
+ <span ng-if="!dataset['Dataset-Doi']">Not Registered</span>
+ </td>
+ </tr>
+ <tr>
+ <td>Measurement</td>
+ <td>
+ <p ng-repeat="measurement in dataset['Measurements'] track by $index">
+ <span ng-repeat="element in measurement track by $index"><a ng-href="#/metadataView?query={{element | urlencode}}">{{element}}</a>{{$last ? '' : ' > '}}</span>
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>Version</td>
+ <td>{{dataset['Version'].join(', ')}}</td>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>{{dataset['Dataset-Description']}}</td>
+ </tr>
+ <tr>
+ <td>Processing Level</td>
+ <td>{{dataset['Processing Level']}}</td>
+ </tr>
+ <tr>
+ <td>Coverage</td>
+ <td>
+ Region: {{dataset['Region'].join(', ')}}<br>
+ Northernmost Latitude: {{dataset['NorthLat']}} degrees<br>
+ Southernmost Latitude: {{dataset['NorthLat']}} degrees<br>
+ Westernmost Longitude: {{dataset['WestLon']}} degrees<br>
+ Easternmost Longitude: {{dataset['EastLon']}} degrees<br>
+ Time Span: {{dataset['Time Span']}}
+ </td>
+ </tr>
+ <tr>
+ <td>Spatial Resolution</td>
+ <td>{{dataset['SpatialResolution']}}</td>
+ </tr>
+ <tr>
+ <td>Temporal Repeat</td>
+ <td>{{dataset['TemporalResolution']}}</td>
+ </tr>
+ <tr>
+ <td>Sensor</td>
+ <td>
+ <a ng-repeat="sensor in dataset['DatasetSource-Sensor-ShortName']" ng-href="#/metadataView?query={{sensor | urlencode}}">{{sensor}}{{$last ? '' : ', '}}</a>
+ </td>
+ </tr>
+ <tr>
+ <td>Project</td>
+ <td>
+ <a ng-repeat="project in dataset['DatasetProject-Project-ShortName']" ng-href="#/metadataView?query={{project | urlencode}}">{{project}}{{$last ? '' : ', '}}</a>
+ </td>
+ </tr>
+ <tr>
+ <td>Format</td>
+ <td>{{dataset['DataFormat']}}</td>
+ </tr>
+ <tr>
+ <td>Data Access</td>
+ <td>
+ <p ng-repeat="path in dataset['DatasetLocationPolicy-BasePath']">
+ <a ng-href="{{path}}" target="_blank">{{path}}</a>
+ </p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-3 col-sm-4">
+ <div class="panel-group">
+ <div class="panel panel-primary sidenav">
+ <div class="panel-heading">
+ <h4 class="panel-title">
+ <a data-toggle="collapse" data-parent="#accordion" data-target="#collapse1">Related Datasets</a>
+ </h4>
+ </div>
+ <div id="collapse1" class="panel-collapse collapse in">
+ <div class="panel-body" ng-controller="hRecommendationCtrl">
+ <div class="list-related-searches" ng-repeat="recommendation in recommendationList">
+ <a title="{{recommendation['name']}}" ng-href="#/datasetView?shortname={{recommendation['name'] | urlencode}}">{{recommendation['name']}}</a>
+ </div>
+ <div class="learn-more">
+ <a href="https://mudrod.github.io/recommendation-algorithms/" target="_blank">How does MUDROD find related Datasets?</a>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="panel panel-primary sidenav">
+ <div class="panel-heading">
+ <h4 class="panel-title">
+ <a data-toggle="collapse" data-parent="#accordion" data-target="#collapse2">Related Keyword Searches</a>
+ </h4>
+ </div>
+ <div id="collapse2" class="panel-collapse collapse in">
+ <div class="panel-body" ng-controller="vocabularyCtrl">
+ <div class="list-related-searches" ng-repeat="ontology in ontologyList">
+ <a title="{{ontology['word']}}" ng-href="#/metadataView?query={{ontology['word'] | urlencode}}">{{ontology['word'] | uppercase}} ({{ontology['weight']}})</a>
+ </div>
+ <div class="learn-more">
+ <a href="https://mudrod.github.io/vocabulary-similarity-algorithm/" target="_blank">How does MUDROD find related keyword searches?</a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/footer.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/footer.html b/web/META-INF/resources/partials/footer.html
new file mode 100644
index 0000000..13d526b
--- /dev/null
+++ b/web/META-INF/resources/partials/footer.html
@@ -0,0 +1,19 @@
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+
+<!--
+
+ This file can be used to provide a customized footer for the MUDROD website. It is currently left empty.
+
+ -->
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/main-header.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/main-header.html b/web/META-INF/resources/partials/main-header.html
new file mode 100644
index 0000000..6db05dc
--- /dev/null
+++ b/web/META-INF/resources/partials/main-header.html
@@ -0,0 +1,19 @@
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+
+<!--
+
+ This file can be used to provide a customized header for the MUDROD website. It is currently left empty.
+
+ -->
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/metadataResults.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/metadataResults.html b/web/META-INF/resources/partials/metadataResults.html
new file mode 100755
index 0000000..8daf6e7
--- /dev/null
+++ b/web/META-INF/resources/partials/metadataResults.html
@@ -0,0 +1,50 @@
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+<div ng-include src="'partials/navbar-search.html'"></div>
+
+<div id="container" class="container view-area-fixed" ng-controller="metadataViewCtrl as vm">
+ <div class="row no-gutter content-holder">
+ <div class="col-md-9 col-sm-8" id="content">
+
+ <ng-include ng-if="!searchComplete" ng-model="searchComplete" src="'partials/search-in-progress.html'"></ng-include>
+ <ng-include ng-if="searchComplete" ng-model="searchComplete" src="'partials/search-results.html'"></ng-include>
+
+ </div>
+
+ <div class="col-md-3 col-sm-4">
+ <div class="panel panel-primary sidenav">
+ <div class="panel-heading">
+ <h4 class="panel-title">
+ <a data-toggle="collapse" data-parent="#accordion" data-target="#collapse1">Related Searches</a>
+ </h4>
+ </div>
+ <div id="collapse1" class="panel-collapse collapse in">
+ <div class="panel-body" ng-controller="vocabularyCtrl">
+ <div ng-if="searchComplete && ontologyList.length > 0" ng-model="searchComplete" class="list-related-searches" ng-repeat="ontology in ontologyList">
+ <a ng-href="#/metadataView?query={{ontology['word'] | urlencode}}" title="{{ontology['word']}}">{{ontology['word'] | uppercase}} ({{ontology['weight']}})</a>
+ </div>
+
+ <div ng-if="searchComplete && ontologyList.length === 0" ng-model="searchComplete">
+ <span style="font-size: 1em;">No related searches found</span>
+ </div>
+
+ <div ng-if="!searchComplete" ng-model="searchComplete" id="spinner">
+ <img src="images/spinner.gif" title="Search in progress" style="height: 5em;">
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/navbar-plain.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/navbar-plain.html b/web/META-INF/resources/partials/navbar-plain.html
new file mode 100755
index 0000000..ce4e811
--- /dev/null
+++ b/web/META-INF/resources/partials/navbar-plain.html
@@ -0,0 +1,35 @@
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+<header>
+ <nav class="navbar navbar-inverse mudrod-navbar">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#mudrod-collapse" aria-expanded="false">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand navbar-link" href="https://mudrod.github.io/">MUDROD</a>
+ </div>
+ <div class="collapse navbar-collapse" id="mudrod-collapse">
+ <div class="nav navbar-nav">
+ <div class="nav-item active">
+ <a class="nav-link" href="#/">Home <span class="sr-only">(current)</span></a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </nav>
+</header>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/navbar-search.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/navbar-search.html b/web/META-INF/resources/partials/navbar-search.html
new file mode 100755
index 0000000..fdc99da
--- /dev/null
+++ b/web/META-INF/resources/partials/navbar-search.html
@@ -0,0 +1,62 @@
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+<header>
+
+ <nav class="navbar navbar-inverse mudrod-navbar">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#mudrod-collapse" aria-expanded="false">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand navbar-link" href="https://mudrod.github.io/">MUDROD</a>
+ </div>
+ <div class="collapse navbar-collapse" id="mudrod-collapse">
+ <div class="nav navbar-nav">
+ <div class="nav-item active">
+ <a class="nav-link" href="#/">Home <span class="sr-only">(current)</span></a>
+ </div>
+ </div>
+
+ <form id="searchForm" class="navbar-form navbar-right" autocomplete="off" ng-controller="searchCtrl">
+ <div class="form-group">
+ <input id="query" type="text" role="search" class="form-control" ng-model="options.query" ng-keyup="complete(options.query)"
+ placeholder="Enter ocean concepts (e.g. ocean wind) to search">
+ <ul class="list-group search-ul autocomplete" ng-model="hidethis" ng-hide="hidethis">
+ <li class="list-group-item" ng-repeat="searchdata in filterSearch" ng-click="fillTextbox(searchdata.value)">{{searchdata.value}}</li>
+ </ul>
+ <button class="btn btn-default" id="search-btn" ng-click="search(options)"
+ type="submit">
+ <i class="glyphicon glyphicon-search"></i>
+ </button>
+ <div class="searchOption input-group" id="searchOption">
+ <label for="searchOption" style="padding-right: .5em;">Search Operator: </label>
+ <label class="radio-inline">
+ <input type="radio" ng-model="options.opt" value="Or">Or
+ </label>
+ <label class="radio-inline">
+ <input type="radio" ng-model="options.opt" value="Phrase"> Phrase
+ </label>
+ <label class="radio-inline">
+ <input type="radio" ng-model="options.opt" value="And"> And
+ </label>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </nav>
+</header>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/search-in-progress.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/search-in-progress.html b/web/META-INF/resources/partials/search-in-progress.html
new file mode 100644
index 0000000..ea776d2
--- /dev/null
+++ b/web/META-INF/resources/partials/search-in-progress.html
@@ -0,0 +1,12 @@
+<div class="panel panel-primary post-holder">
+ <div class="panel-heading">
+ <h4 class="panel-title">
+ <strong class="title">Searching ...</strong>
+ </h4>
+ </div>
+ <div class="panel-body">
+ <div id="spinner">
+ <img src="images/spinner.gif" title="Search in progress">
+ </div>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/search-results.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/search-results.html b/web/META-INF/resources/partials/search-results.html
new file mode 100644
index 0000000..4dac2b5
--- /dev/null
+++ b/web/META-INF/resources/partials/search-results.html
@@ -0,0 +1,116 @@
+<div class="panel panel-primary post-holder">
+ <div class="panel-heading">
+ <select title="Sort By" class="title rankoption" name="rankOption" id="rankOption" ng-model="vm.rankopt" ng-change="vm.rankData(vm.rankopt)" ng-if="!vm.searchError">
+ <option value="Rank-SVM">Default (Machine Learning Ranking)</option>
+ <option value="Rank-AllTimePopularity">Popularity (All Time)</option>
+ <option value="Rank-MonthlyPopularity">Popularity (This Month)</option>
+ <option value="Rank-UserPopularity">Popularity (Users)</option>
+ <option value="Rank-LongName-Full">Long Name (A-Z)</option>
+ <option value="Rank-ShortName-Full">Short Name (A-Z)</option>
+ <option value="Rank-GridSpatialResolution">Grid Spatial Resolution</option>
+ <option value="Rank-SatelliteSpatialResolution">Satellite Spatial Resolution</option>
+ <option value="Rank-StartTimeLong-Long">Start Date</option>
+ <option value="Rank-StopTimeLong-Long">Stop Date</option>
+ </select>
+ <h4 class="panel-title">
+ <strong ng-if="vm.pager.pages.length > 1" class="title">Showing {{vm.items.length}} of {{vm.pager.totalItems}} total match(es)</strong>
+ <strong ng-if="vm.pager.pages.length <= 1" class="title">Showing {{vm.items.length}} total match(es)</strong>
+ <strong ng-if="vm.searchError" class="title">No matches</strong>
+ </h4>
+ </div>
+ <div class="panel-body">
+
+ <!-- pager -->
+ <ul ng-if="vm.pager.pages.length > 1" class="pagination" style="margin-top: 0">
+ <li ng-class="{disabled:vm.pager.currentPage === 1}">
+ <a ng-click="vm.setPage(1)">First</a>
+ </li>
+ <li ng-class="{disabled:vm.pager.currentPage === 1}">
+ <a ng-click="vm.setPage(vm.pager.currentPage - 1)">Previous</a>
+ </li>
+ <li ng-repeat="page in vm.pager.pages" ng-class="{active:vm.pager.currentPage === page}">
+ <a ng-click="vm.setPage(page)">{{page}}</a>
+ </li>
+ <li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
+ <a ng-click="vm.setPage(vm.pager.currentPage + 1)">Next</a>
+ </li>
+ <li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
+ <a ng-click="vm.setPage(vm.pager.totalPages)">Last</a>
+ </li>
+ </ul>
+ <hr style="clear:both; margin: 0; border: 0; border-bottom: 1px solid #c3c3c3;">
+ <div ng-repeat="pdresult in vm.items">
+ <article class="post">
+ <a href="#/datasetView?shortname={{pdresult['Short Name'] | urlencode}}&query={{vm.query | urlencode}}&opt={{vm.opt | urlencode}}">
+ <strong>Name:</strong> {{pdresult['Short Name']}}
+ </a>
+ <br><strong>Long Name:</strong> {{pdresult['Long Name']}}
+ <br><strong>Topic:</strong>
+ <span style="color:green" ng-click="vm.searchTopic(pdresult.Topic)">{{pdresult.Topic}}</span>
+ <br><strong>Platform/Sensors:</strong> {{pdresult['Sensor']}}
+ <br><strong>Processing Level:</strong> {{pdresult['Processing Level']}}
+ <br><strong>Start/End Date:</strong> {{pdresult['Start/End Date']}}
+ <br><strong>Description:</strong>
+ <div ng-init="limit = 150; moreShown = false">
+ {{pdresult.Description | limitTo: limit}}{{pdresult.Description.length > limit ? '...' : ''}}
+ <a ng-show="pdresult.Description.length > limit"
+ href ng-click="limit=pdresult.Description.length; moreShown = true"> More
+ </a>
+ <a ng-show="moreShown" href ng-click="limit=150; moreShown = false"> Less </a>
+ </div>
+ </article>
+ </div>
+ <!-- pager -->
+ <ul ng-if="vm.pager.pages.length > 1" class="pagination">
+ <li ng-class="{disabled:vm.pager.currentPage === 1}">
+ <a ng-click="vm.setPage(1)">First</a>
+ </li>
+ <li ng-class="{disabled:vm.pager.currentPage === 1}">
+ <a ng-click="vm.setPage(vm.pager.currentPage - 1)">Previous</a>
+ </li>
+ <li ng-repeat="page in vm.pager.pages" ng-class="{active:vm.pager.currentPage === page}">
+ <a ng-click="vm.setPage(page)">{{page}}</a>
+ </li>
+ <li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
+ <a ng-click="vm.setPage(vm.pager.currentPage + 1)">Next</a>
+ </li>
+ <li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
+ <a ng-click="vm.setPage(vm.pager.totalPages)">Last</a>
+ </li>
+ </ul>
+
+ <div ng-show="!vm.searchError && !vm.items.length">
+ <article class="post">
+ Your search did not match any dataset.
+ <br>Suggestion
+ <ul>
+ <li>Make sure all words are spelled correctly</li>
+ <li>Try different keywords</li>
+ <li>Try different search options</li>
+ </ul>
+ </article>
+ </div>
+
+ <div ng-show="vm.searchError">
+ <article class="post">
+ There was an error while executing your search.
+ <br>Suggestion
+ <ul>
+ <li>Make sure all words are spelled correctly</li>
+ <li>Try different keywords</li>
+ <li>Try different search options</li>
+ </ul>
+ <br>
+
+ <a ng-show="!showErrorDetails" ng-click="showErrorDetails = true;">Show error details</a>
+ <div ng-show="showErrorDetails" class="animate-show">
+ <span>Error details:</span>
+ <br>
+ <pre>{{vm.searchError | json}}</pre>
+ <br>
+ <a ng-click="showErrorDetails = false;">Hide error details</a>
+ </div>
+ </article>
+ </div>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/partials/search.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/partials/search.html b/web/META-INF/resources/partials/search.html
new file mode 100644
index 0000000..5844cd1
--- /dev/null
+++ b/web/META-INF/resources/partials/search.html
@@ -0,0 +1,58 @@
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+<div ng-include src="'partials/navbar-plain.html'"></div>
+
+<div id="container" class="container view-area-scroll">
+ <div class="landing-dialog">
+ <div class="landing-dialog-header">
+ <h2>Oceanographic Data Discovery</h2>
+ </div>
+ <div class="searchBox toolbar">
+ <div class="landing-toolbar-content">
+ <form id="searchForm" class="search-form" autocomplete="off" ng-controller="searchCtrl">
+ <div class="form-group" style="position: relative">
+
+ <input id="query" type="search" class="form-control" ng-model="options.query" ng-keyup="complete(options.query)"
+ placeholder="Enter ocean concepts (e.g. ocean wind) to search">
+ <button id="search-btn" ng-click="search(options)"
+ type="submit">
+ <span class="ico-search"></span>
+ </button>
+ <div style="position: absolute; padding-top: 1em;">
+ <label for="searchOption" style="padding-right: 1em;">Search Operator:</label>
+ <div id="searchOption" class="btn-group" data-toggle="buttons">
+ <label class="radio-inline">
+ <input type="radio" ng-model="options.opt" value="Or">Or
+ </label>
+ <label class="radio-inline">
+ <input type="radio" ng-model="options.opt" value="Phrase">Phrase
+ </label>
+ <label class="radio-inline">
+ <input type="radio" ng-model="options.opt" value="And">And
+ </label>
+ </div>
+ </div>
+ <ul class="list-group autocomplete" ng-model="hidethis" ng-hide="hidethis">
+ <li class="list-group-item" ng-repeat="searchdata in filterSearch" ng-click="fillTextbox(searchdata.value)">{{searchdata.value}}</li>
+ </ul>
+ </div>
+ </form>
+
+ </div>
+ </div>
+
+
+ </div>
+
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/pom.xml
----------------------------------------------------------------------
diff --git a/web/pom.xml b/web/pom.xml
new file mode 100644
index 0000000..95b7c99
--- /dev/null
+++ b/web/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>gov.nasa.jpl.mudrod</groupId>
+ <artifactId>mudrod-web</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <build>
+ <resources>
+ <resource>
+ <directory>${project.basedir}/META-INF</directory>
+ <targetPath>META-INF</targetPath>
+ </resource>
+ </resources>
+ </build>
+ <packaging>jar</packaging>
+
+ <name>Mudrod :: Web</name>
+ <url>https://github.com/mudrod/mudrod.git</url>
+ <description>MUDROD: Mining and Utilizing Dataset Relevancy from
+ Oceanographic Datasets
+ to Improve Data Discovery and Access. MUDROD is a semantic discovery and
+ search project
+ funded by NASA AIST (NNX15AM85G).
+ </description>
+
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+
+
+</project>
[13/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/test/java/gov/nasa/jpl/mudrod/main/TestMudrodEngine.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/gov/nasa/jpl/mudrod/main/TestMudrodEngine.java b/core/src/test/java/gov/nasa/jpl/mudrod/main/TestMudrodEngine.java
new file mode 100644
index 0000000..ff15415
--- /dev/null
+++ b/core/src/test/java/gov/nasa/jpl/mudrod/main/TestMudrodEngine.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.main;
+
+import static org.junit.Assert.fail;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Initial test case for {@link gov.nasa.jpl.mudrod.main.MudrodEngine}, currently no
+ * tests are implemented, this is merely in place to get the JaCoCo test reporting to
+ * work.
+ */
+public class TestMudrodEngine {
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#MudrodEngine()}.
+ */
+ @Ignore
+ @Test
+ public final void testMudrodEngine() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#startESDriver()}.
+ */
+ @Ignore
+ @Test
+ public final void testStartESDriver() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#startSparkDriver()}.
+ */
+ @Ignore
+ @Test
+ public final void testStartSparkDriver() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#getConfig()}.
+ */
+ @Ignore
+ @Test
+ public final void testGetConfig() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#getESDriver()}.
+ */
+ @Ignore
+ @Test
+ public final void testGetESDriver() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#setESDriver(gov.nasa.jpl.mudrod.driver.ESDriver)}.
+ */
+ @Ignore
+ @Test
+ public final void testSetESDriver() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#loadConfig()}.
+ */
+ @Ignore
+ @Test
+ public final void testLoadConfig() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#startLogIngest()}.
+ */
+ @Ignore
+ @Test
+ public final void testStartLogIngest() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#startMetaIngest()}.
+ */
+ @Ignore
+ @Test
+ public final void testStartMetaIngest() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#startFullIngest()}.
+ */
+ @Ignore
+ @Test
+ public final void testStartFullIngest() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#startProcessing()}.
+ */
+ @Ignore
+ @Test
+ public final void testStartProcessing() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#end()}.
+ */
+ @Ignore
+ @Test
+ public final void testEnd() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#main(java.lang.String[])}.
+ */
+ @Ignore
+ @Test
+ public final void testMain() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#getSparkDriver()}.
+ */
+ @Ignore
+ @Test
+ public final void testGetSparkDriver() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.main.MudrodEngine#setSparkDriver(gov.nasa.jpl.mudrod.driver.SparkDriver)}.
+ */
+ @Ignore
+ @Test
+ public final void testSetSparkDriver() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#Object()}.
+ */
+ @Ignore
+ @Test
+ public final void testObject() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#getClass()}.
+ */
+ @Ignore
+ @Test
+ public final void testGetClass() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#hashCode()}.
+ */
+ @Ignore
+ @Test
+ public final void testHashCode() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#equals(java.lang.Object)}.
+ */
+ @Ignore
+ @Test
+ public final void testEquals() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#clone()}.
+ */
+ @Ignore
+ @Test
+ public final void testClone() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#toString()}.
+ */
+ @Ignore
+ @Test
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#notify()}.
+ */
+ @Ignore
+ @Test
+ public final void testNotify() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#notifyAll()}.
+ */
+ @Ignore
+ @Test
+ public final void testNotifyAll() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#wait(long)}.
+ */
+ @Ignore
+ @Test
+ public final void testWaitLong() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#wait(long, int)}.
+ */
+ @Ignore
+ @Test
+ public final void testWaitLongInt() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#wait()}.
+ */
+ @Ignore
+ @Test
+ public final void testWait() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link java.lang.Object#finalize()}.
+ */
+ @Ignore
+ @Test
+ public final void testFinalize() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java b/core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java
new file mode 100644
index 0000000..994f4ed
--- /dev/null
+++ b/core/src/test/java/gov/nasa/jpl/mudrod/ontology/process/TestLocalOntology.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Test cases for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology}
+ */
+public class TestLocalOntology {
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ private LocalOntology lOnt;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ lOnt = new LocalOntology();
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void tearDown() throws Exception {
+ lOnt = null;
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#LocalOntology()}.
+ */
+ @Test
+ public final void testLocalOntology() {
+ assertNotNull("Test setUp should create a new instance of LocalOntology.", lOnt);
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#getInstance()}.
+ */
+ @Test
+ public final void testGetInstance() {
+ assertSame("Ontology instance should be of type LocalOntology", LocalOntology.class, lOnt.getInstance().getClass());
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#load()}.
+ * @throws IOException
+ */
+ @Ignore
+ @Test
+ public final void testLoad() throws IOException {
+ lOnt.load();
+ assertTrue("Resource list should have a minimum of one resource.", lOnt.getLoadedOntologyResources().size() == 1);
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#load(java.lang.String[])}.
+ */
+ @Ignore
+ @Test
+ public final void testLoadStringArray() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#getParser()}.
+ */
+ @Ignore
+ @Test
+ public final void testGetParser() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#getModel()}.
+ */
+ @Ignore
+ @Test
+ public final void testGetModel() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#merge(gov.nasa.jpl.mudrod.ontology.Ontology)}.
+ */
+ @Ignore
+ @Test
+ public final void testMerge() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#subclasses(java.lang.String)}.
+ */
+ @Ignore
+ @Test
+ public final void testSubclasses() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#synonyms(java.lang.String)}.
+ */
+ @Ignore
+ @Test
+ public final void testSynonyms() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#addSearchTerm(java.lang.String, org.apache.jena.ontology.OntResource)}.
+ */
+ @Ignore
+ @Test
+ public final void testAddSearchTerm() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#retrieve(java.lang.String)}.
+ */
+ @Ignore
+ @Test
+ public final void testRetrieve() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderHierarchy(java.io.PrintStream, org.apache.jena.ontology.OntClass, java.util.List, int)}.
+ */
+ @Ignore
+ @Test
+ public final void testRenderHierarchy() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderClassDescription(java.io.PrintStream, org.apache.jena.ontology.OntClass, int)}.
+ */
+ @Ignore
+ @Test
+ public final void testRenderClassDescription() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderRestriction(java.io.PrintStream, org.apache.jena.ontology.Restriction)}.
+ */
+ @Ignore
+ @Test
+ public final void testRenderRestriction() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderURI(java.io.PrintStream, org.apache.jena.shared.PrefixMapping, java.lang.String)}.
+ */
+ @Ignore
+ @Test
+ public final void testRenderURI() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#renderAnonymous(java.io.PrintStream, org.apache.jena.rdf.model.Resource, java.lang.String)}.
+ */
+ @Ignore
+ @Test
+ public final void testRenderAnonymous() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#indent(java.io.PrintStream, int)}.
+ */
+ @Ignore
+ @Test
+ public final void testIndent() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link gov.nasa.jpl.mudrod.ontology.process.LocalOntology#main(java.lang.String[])}.
+ */
+ @Ignore
+ @Test
+ public final void testMain() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/docker/Dockerfile
----------------------------------------------------------------------
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..289bf29
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,105 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0 Unless
+#
+# required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS"
+# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language
+# governing permissions and limitations under the License.
+
+# This Dockerfile will build the required environment and software
+# stack to easily get up and running with mudrod
+# For more documentation please see https://github.com/mudrod/mudrod
+
+FROM ubuntu:16.04
+
+MAINTAINER Mudrod Team <mu...@jpl.nasa.gov>
+
+# Get the package containing apt-add-repository installed for adding repositories
+RUN apt-get update && apt-get install -y software-properties-common
+
+# Install openJDK 1.8
+RUN apt-get install -y openjdk-8-jdk
+
+# Install various dependencies
+RUN apt-get install -y \
+ build-essential \
+ git \
+ maven \
+ openssh-client \
+ openssh-server \
+ vim \
+ wget
+
+RUN echo "JAVA_HOME=/usr/bin" >> /etc/environment
+
+RUN echo 'PATH=$PATH:HOME/bin:$JAVA_HOME/bin' >> /etc/profile &&\
+ echo 'export JAVA_HOME' >> /etc/profile &&\
+ echo 'export PATH' >> /etc/profile
+
+USER root
+
+WORKDIR /tmp
+
+########################
+# Apache Spark 1.6.2 #
+########################
+ENV SPARK_PKG_NAME spark-1.6.2
+RUN wget http://archive.apache.org/dist/spark/$SPARK_PKG_NAME/$SPARK_PKG_NAME-bin-without-hadoop.tgz && \
+ tar -xvzf $SPARK_PKG_NAME-bin-without-hadoop.tgz && \
+ rm -f $SPARK_PKG_NAME-bin-without-hadoop.tgz && \
+ mv $SPARK_PKG_NAME-bin-without-hadoop /usr/local/spark
+
+WORKDIR /usr/local
+
+# ENV needs to be used, as the above doesn't seem to be visible from cli
+ENV JAVA_HOME /usr
+ENV SPARK_HOME /usr/local/spark
+
+# so you can call 'spark-class', 'spark-shell', 'spark-sql', 'spark-submit', etc.
+ENV PATH $PATH:$SPARK_HOME/bin
+
+#######################
+# Elasticsearch 2.3.4 #
+#######################
+ENV ES_PKG_NAME elasticsearch-2.3.4
+RUN wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.3.4/$ES_PKG_NAME.tar.gz && \
+ tar -xvzf $ES_PKG_NAME.tar.gz && \
+ rm -f $ES_PKG_NAME.tar.gz && \
+ mv $ES_PKG_NAME /usr/local/elasticsearch
+
+# Define mountable directories.
+VOLUME ["/data"]
+
+# Mount elasticsearch.yml config
+ADD config/elasticsearch.yml /usr/local/elasticsearch/config/elasticsearch.yml
+
+# Expose ports.
+# - 9200: HTTP
+# - 9300: transport
+EXPOSE 9200
+EXPOSE 9300
+
+#########################
+# Mudrod Master Branch #
+#########################
+WORKDIR /usr/local
+RUN git clone https://github.com/mudrod/mudrod.git
+ENV MUDROD_HOME /usr/local/mudrod
+WORKDIR $MUDROD_HOME
+# So you can call 'mudrod'
+ENV PATH $PATH:$MUDROD_HOME/bin
+RUN mvn clean install
+
+# Expose ports.
+# - 8080: HTTP Jetty Port
+EXPOSE 8080
+
+# Ensure that all of the services are running
+CMD sh $MUDROD_HOME/docker/run_services.sh
+
+# Set entry point to the Mudrod executable
+ENTRYPOINT ["/usr/local/mudrod/bin/mudrod"]
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/docker/README.md
----------------------------------------------------------------------
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000..f84ace1
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,52 @@
+# MUDROD Dockerfile
+
+[](https://hub.docker.com/r/mudrod/mudrod/)
+[](https://hub.docker.com/r/mudrod/mudrod/)
+
+# Pulling from Dockerhub
+Mudrod is available on Dockerhub for rapid deployment and prototyping.
+To get the Mudrod application and environment make sure you have [Docker](https://www.docker.com/) installed then simply execute:
+```
+$ docker pull mudrod/mudrod
+$ docker run -t -i mudrod/mudrod /bin/bash
+
+N.B. If you are on MacOSX you may need to run the following two commands first
+$ boot2docker start
+$ $(boot2docker shellinit)
+```
+You can test it by visiting http://container-ip:8080 in a browser or, if you need access outside the host, on port 8888:
+```
+$ docker run -it --rm -p 8888:8080 mudrod:latest
+```
+
+# Building the Docker Container Manually
+Simply execute the following
+```
+$ cd docker
+$ docker build -t mudrod/mudrod:latest .
+$ docker run -t -i -d --name mudrodcontainer mudrod/mudrod /bin/bash
+$ docker attach --sig-proxy=false mudrodcontainer
+```
+You will now be within the Mudrod environment with all of the tools required to use the software stack, as mentioned in the [Software Requirements](https://github.com/mudrod/mudrod#software-requirements).
+You can run mudrod as follows
+```
+root@e4e137838adc:/usr/local# mudrod
+ _____ .___ .___
+ / \ __ __ __| _/______ ____ __| _/
+ / \ / \| | \/ __ |\_ __ \/ _ \ / __ |
+/ Y \ | / /_/ | | | \( <_> ) /_/ |
+\____|__ /____/\____ | |__| \____/\____ |
+ \/ \/ \/ v0.0.1
+Mining and Utilizing Dataset Relevancy from Oceanographic"
+Datasets to Improve Data Discovery and Access."
+Usage: run COMMAND"
+where COMMAND is one of:"
+ logingest ingest logs into Mudrod"
+ ...
+Most commands print help when invoked w/o parameters."
+```
+
+# Support and Development
+If you require help with this file, or you have some suggestions
+for improving it, please [file an issue](https://github.com/mudrod/mudrod/issues)
+and use the **docker** tag.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/docker/config/elasticsearch.yml
----------------------------------------------------------------------
diff --git a/docker/config/elasticsearch.yml b/docker/config/elasticsearch.yml
new file mode 100644
index 0000000..72be0f9
--- /dev/null
+++ b/docker/config/elasticsearch.yml
@@ -0,0 +1,5 @@
+path:
+ data: /data/data
+ logs: /data/log
+ plugins: /data/plugins
+ work: /data/work
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/docker/run_services.sh
----------------------------------------------------------------------
diff --git a/docker/run_services.sh b/docker/run_services.sh
new file mode 100755
index 0000000..d88dfba
--- /dev/null
+++ b/docker/run_services.sh
@@ -0,0 +1,17 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0 Unless
+#
+# required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS"
+# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language
+# governing permissions and limitations under the License.
+
+service sshd start &
+/usr/local/spark/sbin/start-all.sh &
+/usr/local/elasticsearch/bin/elasticsearch &
+cd /usr/local/mudrod/service &
+mvn jetty:run
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/eclipse-codeformat.xml
----------------------------------------------------------------------
diff --git a/eclipse-codeformat.xml b/eclipse-codeformat.xml
new file mode 100644
index 0000000..eadcaee
--- /dev/null
+++ b/eclipse-codeformat.xml
@@ -0,0 +1,773 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<profiles version="11">
+ <profile kind="CodeFormatterProfile" name="Mudrod" version="11">
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field"
+ value="0"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line"
+ value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression"
+ value="80"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.continuation_indentation"
+ value="2"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package"
+ value="0"/>
+ <setting id="org.eclipse.jdt.core.compiler.source" value="1.5"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.format_line_comments"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.align_type_members_on_columns"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment"
+ value="false"/>
+ <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="200"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration"
+ value="0"/>
+ <setting id="org.eclipse.jdt.core.formatter.indentation.size"
+ value="2"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration"
+ value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment"
+ value="0"/>
+ <setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier"
+ value="error"/>
+ <setting id="org.eclipse.jdt.core.formatter.tabulation.char"
+ value="space"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body"
+ value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier"
+ value="error"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration"
+ value="end_of_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.compact_else_if"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant"
+ value="end_of_line"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="2"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.indent_empty_lines"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression"
+ value="16"/>
+ <setting id="org.eclipse.jdt.core.compiler.compliance" value="1.5"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer"
+ value="2"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode"
+ value="enabled"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments"
+ value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.line_length"
+ value="80"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body"
+ value="0"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration"
+ value="16"/>
+ <setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports"
+ value="1"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_html"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator"
+ value="do not insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_source_code"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration"
+ value="16"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform"
+ value="1.5"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.comment.format_header"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.comment.format_block_comments"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants"
+ value="0"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration"
+ value="end_of_line"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments"
+ value="insert"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports"
+ value="1"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header"
+ value="true"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for"
+ value="insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments"
+ value="do not insert"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column"
+ value="false"/>
+ <setting
+ id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line"
+ value="false"/>
+ </profile>
+</profiles>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..9bf3f7f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,556 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>gov.nasa.jpl.mudrod</groupId>
+ <artifactId>mudrod-parent</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <name>Mudrod :: Parent</name>
+ <url>https://github.com/mudrod/mudrod.git</url>
+ <description>MUDROD: Mining and Utilizing Dataset Relevancy from
+ Oceanographic Datasets
+ to Improve Data Discovery and Access. MUDROD is a semantic discovery and
+ search project
+ funded by NASA AIST (NNX15AM85G).
+ </description>
+
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+
+ <organization>
+ <name>George Mason University</name>
+ <url>https://www2.gmu.edu/</url>
+ </organization>
+
+ <developers>
+ <developer>
+ <id>lewismc</id>
+ <name>Lewis John McGibbney</name>
+ <email>lewis[dot]j[dot]mcgibbney[at]jpl[dot]nasa[dot]gov</email>
+ <roles>
+ <role>Committer</role>
+ </roles>
+ <organization>NASA Jet Propulsion Laboratory</organization>
+ </developer>
+ <developer>
+ <id>Yongyao</id>
+ <name>Yongyao Jiang</name>
+ <email>J[dot]yongyao11[at]gmail[dot]com</email>
+ <roles>
+ <role>Committer</role>
+ </roles>
+ <organization>NSF Spatiotemporal Innovation Center, George Mason
+ University
+ </organization>
+ </developer>
+ <developer>
+ <id>quintinali</id>
+ <name>Yun Li</name>
+ <email>yli38[at]gmu[dot]edu</email>
+ <roles>
+ <role>Committer</role>
+ </roles>
+ <organization>NSF Spatiotemporal Innovation Center, George Mason
+ University
+ </organization>
+ </developer>
+ </developers>
+
+ <issueManagement>
+ <system>Github Issues</system>
+ <url>https://github.com/mudrod/mudrod/issues</url>
+ </issueManagement>
+ <ciManagement>
+ <system>TravisCI</system>
+ <url>https://travis-ci.org/mudrod/mudrod</url>
+ </ciManagement>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <implementation.build>${scmBranch}@r${buildNumber}
+ </implementation.build>
+ <implementation.build.tstamp>${maven.build.timestamp}
+ </implementation.build.tstamp>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ <spark.version>2.1.0</spark.version>
+ <findbugs.version>3.0.4</findbugs.version>
+ <xml.maven.version>1.0.1</xml.maven.version>
+ <jacoco.version>0.7.10-SNAPSHOT</jacoco.version>
+ <jena.version>3.3.0</jena.version>
+ <project.reporting.outputEncoding>UTF-8
+ </project.reporting.outputEncoding>
+ <elastic.version>5.2.0</elastic.version>
+ <!--argLine>-Xmx4096m ${itCoverageAgent}</argLine-->
+ </properties>
+
+ <scm>
+ <developerConnection>scm:git:https://github.com/mudrod/mudrod.git
+ </developerConnection>
+ <connection>scm:git:http://github.com/mudrod/mudrod.git</connection>
+ <url>https://github.com/mudrod/mudrod.git</url>
+ <tag>HEAD</tag>
+ </scm>
+
+ <distributionManagement>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+ </snapshotRepository>
+ <repository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/
+ </url>
+ </repository>
+ </distributionManagement>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <modules>
+ <module>core</module>
+ <module>service</module>
+ <module>web</module>
+ </modules>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>buildnumber-maven-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <phase>validate</phase>
+ <goals>
+ <goal>create</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <doCheck>false</doCheck>
+ <doUpdate>false</doUpdate>
+ <!-- Use committed revision so it does not change every time svn
+ update is run -->
+ <useLastCommittedRevision>true</useLastCommittedRevision>
+ <!-- default revision number if unavailable -->
+ <revisionOnScmFailure>??????</revisionOnScmFailure>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19.1</version>
+ <configuration>
+ <forkCount>1</forkCount>
+ <reuseForks>true</reuseForks>
+ <argLine>${argLine} -Xmx2048m</argLine>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default-test</id>
+ <phase>test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.19.1</version>
+ <configuration>
+ <reuseForks>true</reuseForks>
+ <argLine>${argLine} -Xmx4096m ${itCoverageAgent}
+ </argLine>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <inherited>true</inherited>
+ <executions>
+ <execution>
+ <id>copy</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>lib</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>${jacoco.version}</version>
+ <configuration>
+ <destFile>
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+ </destFile>
+ <dataFile>
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+ </dataFile>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default-prepare-agent</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>prepare-unit-tests</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <!-- prepare agent for measuring integration tests -->
+ <execution>
+ <id>prepare-integration-tests</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ <phase>pre-integration-test</phase>
+ <configuration>
+ <propertyName>itCoverageAgent</propertyName>
+ </configuration>
+ </execution>
+ <execution>
+ <id>jacoco-site</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>report</id>
+ <phase>test</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>3.0.0</version>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>${basedir}/lib</directory>
+ <followSymlinks>false</followSymlinks>
+ <useDefaultExcludes>true</useDefaultExcludes>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <version>0.12</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <excludes>
+ <exclude>**/tmp/**</exclude>
+ <exclude>**/META-INF/**</exclude>
+ <exclude>**/resources/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ <profiles>
+ <profile>
+ <id>only-eclipse</id>
+ <activation>
+ <property>
+ <name>m2e.version</name>
+ </property>
+ </activation>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <!--This plugin's configuration is used to store Eclipse m2e
+ settings only. It has no influence on the Maven build itself. -->
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.codehaus.mojo
+ </groupId>
+ <artifactId>
+ buildnumber-maven-plugin
+ </artifactId>
+ <versionRange>
+ [${buildnumber-maven-plugin.version},)
+ </versionRange>
+ <goals>
+ <goal>create</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+ </profiles>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <version>${findbugs.version}</version>
+ <configuration>
+ <findbugsXmlOutputDirectory>
+ ${project.build.directory}/findbugs
+ </findbugsXmlOutputDirectory>
+ <failOnError>false</failOnError>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>xml-maven-plugin</artifactId>
+ <version>${xml.maven.version}</version>
+ <configuration>
+ <transformationSets>
+ <transformationSet>
+ <dir>${project.build.directory}/findbugs</dir>
+ <outputDir>${project.build.directory}/findbugs
+ </outputDir>
+ <stylesheet>fancy-hist.xsl</stylesheet>
+ <!--<stylesheet>default.xsl</stylesheet>-->
+ <!--<stylesheet>plain.xsl</stylesheet>-->
+ <!--<stylesheet>fancy.xsl</stylesheet>-->
+ <!--<stylesheet>summary.xsl</stylesheet>-->
+ <fileMappers>
+ <fileMapper
+ implementation="org.codehaus.plexus.components.io.filemappers.FileExtensionMapper">
+ <targetExtension>.html</targetExtension>
+ </fileMapper>
+ </fileMappers>
+ </transformationSet>
+ </transformationSets>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <dependencyManagement>
+ <dependencies>
+
+ <!-- Elasticsearch dependencies -->
+ <dependency>
+ <groupId>org.elasticsearch</groupId>
+ <artifactId>elasticsearch</artifactId>
+ <version>${elastic.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.elasticsearch.client</groupId>
+ <artifactId>transport</artifactId>
+ <version>${elastic.version}</version>
+ <scope>compile</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.elasticsearch.plugin</groupId>
+ <artifactId>transport-netty4-client</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.elasticsearch</groupId>
+ <artifactId>elasticsearch-spark-20_2.11</artifactId>
+ <version>${elastic.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ <version>2.9.4</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.carrotsearch</groupId>
+ <artifactId>hppc</artifactId>
+ <version>0.7.1</version>
+ <scope>compile</scope>
+ </dependency>
+ <!-- End of Elasticsearch dependencies -->
+
+ <!-- Spark dependencies -->
+ <dependency>
+ <groupId>org.apache.spark</groupId>
+ <artifactId>spark-core_2.11</artifactId>
+ <version>${spark.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.spark</groupId>
+ <artifactId>spark-sql_2.11</artifactId>
+ <version>${spark.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.spark</groupId>
+ <artifactId>spark-mllib_2.11</artifactId>
+ <version>${spark.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.github.fommil.netlib</groupId>
+ <artifactId>all</artifactId>
+ <version>1.1.2</version>
+ <scope>runtime</scope>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ <version>2.11.8</version>
+ <scope>compile</scope>
+ </dependency>
+ <!-- End of Spark dependencies -->
+
+ <!-- Jena dependencies -->
+ <dependency>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-core</artifactId>
+ <version>${jena.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <!-- End of Jena dependencies -->
+
+ <!-- Misc dependencies -->
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.5</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jdom</groupId>
+ <artifactId>jdom</artifactId>
+ <version>2.0.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <!-- End of Misc dependencies -->
+
+ <!-- Logging dependencies -->
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ <version>2.6.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>2.6.2</version>
+ <scope>runtime</scope>
+ </dependency>
+ <!-- End of Logging dependencies -->
+
+ <!-- Webservices Dependencies -->
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ <version>3.1.7</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-client</artifactId>
+ <version>3.1.7</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <!-- Testing dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <!-- End of Testing Dependencies -->
+
+ </dependencies>
+ </dependencyManagement>
+</project>
[06/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/angular-mocks.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/angular-mocks.js b/web/META-INF/resources/js/libs/angular-mocks.js
new file mode 100755
index 0000000..3430bb7
--- /dev/null
+++ b/web/META-INF/resources/js/libs/angular-mocks.js
@@ -0,0 +1,2382 @@
+/**
+ * @license AngularJS v1.3.7
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular, undefined) {
+
+'use strict';
+
+/**
+ * @ngdoc object
+ * @name angular.mock
+ * @description
+ *
+ * Namespace from 'angular-mocks.js' which contains testing related code.
+ */
+angular.mock = {};
+
+/**
+ * ! This is a private undocumented service !
+ *
+ * @name $browser
+ *
+ * @description
+ * This service is a mock implementation of {@link ng.$browser}. It provides fake
+ * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
+ * cookies, etc...
+ *
+ * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
+ * that there are several helper methods available which can be used in tests.
+ */
+angular.mock.$BrowserProvider = function() {
+ this.$get = function() {
+ return new angular.mock.$Browser();
+ };
+};
+
+angular.mock.$Browser = function() {
+ var self = this;
+
+ this.isMock = true;
+ self.$$url = "http://server/";
+ self.$$lastUrl = self.$$url; // used by url polling fn
+ self.pollFns = [];
+
+ // TODO(vojta): remove this temporary api
+ self.$$completeOutstandingRequest = angular.noop;
+ self.$$incOutstandingRequestCount = angular.noop;
+
+
+ // register url polling fn
+
+ self.onUrlChange = function(listener) {
+ self.pollFns.push(
+ function() {
+ if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
+ self.$$lastUrl = self.$$url;
+ self.$$lastState = self.$$state;
+ listener(self.$$url, self.$$state);
+ }
+ }
+ );
+
+ return listener;
+ };
+
+ self.$$checkUrlChange = angular.noop;
+
+ self.cookieHash = {};
+ self.lastCookieHash = {};
+ self.deferredFns = [];
+ self.deferredNextId = 0;
+
+ self.defer = function(fn, delay) {
+ delay = delay || 0;
+ self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
+ self.deferredFns.sort(function(a, b) { return a.time - b.time;});
+ return self.deferredNextId++;
+ };
+
+
+ /**
+ * @name $browser#defer.now
+ *
+ * @description
+ * Current milliseconds mock time.
+ */
+ self.defer.now = 0;
+
+
+ self.defer.cancel = function(deferId) {
+ var fnIndex;
+
+ angular.forEach(self.deferredFns, function(fn, index) {
+ if (fn.id === deferId) fnIndex = index;
+ });
+
+ if (fnIndex !== undefined) {
+ self.deferredFns.splice(fnIndex, 1);
+ return true;
+ }
+
+ return false;
+ };
+
+
+ /**
+ * @name $browser#defer.flush
+ *
+ * @description
+ * Flushes all pending requests and executes the defer callbacks.
+ *
+ * @param {number=} number of milliseconds to flush. See {@link #defer.now}
+ */
+ self.defer.flush = function(delay) {
+ if (angular.isDefined(delay)) {
+ self.defer.now += delay;
+ } else {
+ if (self.deferredFns.length) {
+ self.defer.now = self.deferredFns[self.deferredFns.length - 1].time;
+ } else {
+ throw new Error('No deferred tasks to be flushed');
+ }
+ }
+
+ while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
+ self.deferredFns.shift().fn();
+ }
+ };
+
+ self.$$baseHref = '/';
+ self.baseHref = function() {
+ return this.$$baseHref;
+ };
+};
+angular.mock.$Browser.prototype = {
+
+/**
+ * @name $browser#poll
+ *
+ * @description
+ * run all fns in pollFns
+ */
+ poll: function poll() {
+ angular.forEach(this.pollFns, function(pollFn) {
+ pollFn();
+ });
+ },
+
+ addPollFn: function(pollFn) {
+ this.pollFns.push(pollFn);
+ return pollFn;
+ },
+
+ url: function(url, replace, state) {
+ if (angular.isUndefined(state)) {
+ state = null;
+ }
+ if (url) {
+ this.$$url = url;
+ // Native pushState serializes & copies the object; simulate it.
+ this.$$state = angular.copy(state);
+ return this;
+ }
+
+ return this.$$url;
+ },
+
+ state: function() {
+ return this.$$state;
+ },
+
+ cookies: function(name, value) {
+ if (name) {
+ if (angular.isUndefined(value)) {
+ delete this.cookieHash[name];
+ } else {
+ if (angular.isString(value) && //strings only
+ value.length <= 4096) { //strict cookie storage limits
+ this.cookieHash[name] = value;
+ }
+ }
+ } else {
+ if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
+ this.lastCookieHash = angular.copy(this.cookieHash);
+ this.cookieHash = angular.copy(this.cookieHash);
+ }
+ return this.cookieHash;
+ }
+ },
+
+ notifyWhenNoOutstandingRequests: function(fn) {
+ fn();
+ }
+};
+
+
+/**
+ * @ngdoc provider
+ * @name $exceptionHandlerProvider
+ *
+ * @description
+ * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
+ * passed to the `$exceptionHandler`.
+ */
+
+/**
+ * @ngdoc service
+ * @name $exceptionHandler
+ *
+ * @description
+ * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
+ * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
+ * information.
+ *
+ *
+ * ```js
+ * describe('$exceptionHandlerProvider', function() {
+ *
+ * it('should capture log messages and exceptions', function() {
+ *
+ * module(function($exceptionHandlerProvider) {
+ * $exceptionHandlerProvider.mode('log');
+ * });
+ *
+ * inject(function($log, $exceptionHandler, $timeout) {
+ * $timeout(function() { $log.log(1); });
+ * $timeout(function() { $log.log(2); throw 'banana peel'; });
+ * $timeout(function() { $log.log(3); });
+ * expect($exceptionHandler.errors).toEqual([]);
+ * expect($log.assertEmpty());
+ * $timeout.flush();
+ * expect($exceptionHandler.errors).toEqual(['banana peel']);
+ * expect($log.log.logs).toEqual([[1], [2], [3]]);
+ * });
+ * });
+ * });
+ * ```
+ */
+
+angular.mock.$ExceptionHandlerProvider = function() {
+ var handler;
+
+ /**
+ * @ngdoc method
+ * @name $exceptionHandlerProvider#mode
+ *
+ * @description
+ * Sets the logging mode.
+ *
+ * @param {string} mode Mode of operation, defaults to `rethrow`.
+ *
+ * - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
+ * is a bug in the application or test, so this mock will make these tests fail.
+ * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
+ * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
+ * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
+ * {@link ngMock.$log#reset reset()}
+ */
+ this.mode = function(mode) {
+ switch (mode) {
+ case 'rethrow':
+ handler = function(e) {
+ throw e;
+ };
+ break;
+ case 'log':
+ var errors = [];
+
+ handler = function(e) {
+ if (arguments.length == 1) {
+ errors.push(e);
+ } else {
+ errors.push([].slice.call(arguments, 0));
+ }
+ };
+
+ handler.errors = errors;
+ break;
+ default:
+ throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
+ }
+ };
+
+ this.$get = function() {
+ return handler;
+ };
+
+ this.mode('rethrow');
+};
+
+
+/**
+ * @ngdoc service
+ * @name $log
+ *
+ * @description
+ * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
+ * (one array per logging level). These arrays are exposed as `logs` property of each of the
+ * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
+ *
+ */
+angular.mock.$LogProvider = function() {
+ var debug = true;
+
+ function concat(array1, array2, index) {
+ return array1.concat(Array.prototype.slice.call(array2, index));
+ }
+
+ this.debugEnabled = function(flag) {
+ if (angular.isDefined(flag)) {
+ debug = flag;
+ return this;
+ } else {
+ return debug;
+ }
+ };
+
+ this.$get = function() {
+ var $log = {
+ log: function() { $log.log.logs.push(concat([], arguments, 0)); },
+ warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
+ info: function() { $log.info.logs.push(concat([], arguments, 0)); },
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); },
+ debug: function() {
+ if (debug) {
+ $log.debug.logs.push(concat([], arguments, 0));
+ }
+ }
+ };
+
+ /**
+ * @ngdoc method
+ * @name $log#reset
+ *
+ * @description
+ * Reset all of the logging arrays to empty.
+ */
+ $log.reset = function() {
+ /**
+ * @ngdoc property
+ * @name $log#log.logs
+ *
+ * @description
+ * Array of messages logged using {@link ng.$log#log `log()`}.
+ *
+ * @example
+ * ```js
+ * $log.log('Some Log');
+ * var first = $log.log.logs.unshift();
+ * ```
+ */
+ $log.log.logs = [];
+ /**
+ * @ngdoc property
+ * @name $log#info.logs
+ *
+ * @description
+ * Array of messages logged using {@link ng.$log#info `info()`}.
+ *
+ * @example
+ * ```js
+ * $log.info('Some Info');
+ * var first = $log.info.logs.unshift();
+ * ```
+ */
+ $log.info.logs = [];
+ /**
+ * @ngdoc property
+ * @name $log#warn.logs
+ *
+ * @description
+ * Array of messages logged using {@link ng.$log#warn `warn()`}.
+ *
+ * @example
+ * ```js
+ * $log.warn('Some Warning');
+ * var first = $log.warn.logs.unshift();
+ * ```
+ */
+ $log.warn.logs = [];
+ /**
+ * @ngdoc property
+ * @name $log#error.logs
+ *
+ * @description
+ * Array of messages logged using {@link ng.$log#error `error()`}.
+ *
+ * @example
+ * ```js
+ * $log.error('Some Error');
+ * var first = $log.error.logs.unshift();
+ * ```
+ */
+ $log.error.logs = [];
+ /**
+ * @ngdoc property
+ * @name $log#debug.logs
+ *
+ * @description
+ * Array of messages logged using {@link ng.$log#debug `debug()`}.
+ *
+ * @example
+ * ```js
+ * $log.debug('Some Error');
+ * var first = $log.debug.logs.unshift();
+ * ```
+ */
+ $log.debug.logs = [];
+ };
+
+ /**
+ * @ngdoc method
+ * @name $log#assertEmpty
+ *
+ * @description
+ * Assert that all of the logging methods have no logged messages. If any messages are present,
+ * an exception is thrown.
+ */
+ $log.assertEmpty = function() {
+ var errors = [];
+ angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
+ angular.forEach($log[logLevel].logs, function(log) {
+ angular.forEach(log, function(logItem) {
+ errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
+ (logItem.stack || ''));
+ });
+ });
+ });
+ if (errors.length) {
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " +
+ "an expected log message was not checked and removed:");
+ errors.push('');
+ throw new Error(errors.join('\n---------\n'));
+ }
+ };
+
+ $log.reset();
+ return $log;
+ };
+};
+
+
+/**
+ * @ngdoc service
+ * @name $interval
+ *
+ * @description
+ * Mock implementation of the $interval service.
+ *
+ * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
+ * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
+ * time.
+ *
+ * @param {function()} fn A function that should be called repeatedly.
+ * @param {number} delay Number of milliseconds between each function call.
+ * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
+ * indefinitely.
+ * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
+ * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
+ * @returns {promise} A promise which will be notified on each iteration.
+ */
+angular.mock.$IntervalProvider = function() {
+ this.$get = ['$browser', '$rootScope', '$q', '$$q',
+ function($browser, $rootScope, $q, $$q) {
+ var repeatFns = [],
+ nextRepeatId = 0,
+ now = 0;
+
+ var $interval = function(fn, delay, count, invokeApply) {
+ var iteration = 0,
+ skipApply = (angular.isDefined(invokeApply) && !invokeApply),
+ deferred = (skipApply ? $$q : $q).defer(),
+ promise = deferred.promise;
+
+ count = (angular.isDefined(count)) ? count : 0;
+ promise.then(null, null, fn);
+
+ promise.$$intervalId = nextRepeatId;
+
+ function tick() {
+ deferred.notify(iteration++);
+
+ if (count > 0 && iteration >= count) {
+ var fnIndex;
+ deferred.resolve(iteration);
+
+ angular.forEach(repeatFns, function(fn, index) {
+ if (fn.id === promise.$$intervalId) fnIndex = index;
+ });
+
+ if (fnIndex !== undefined) {
+ repeatFns.splice(fnIndex, 1);
+ }
+ }
+
+ if (skipApply) {
+ $browser.defer.flush();
+ } else {
+ $rootScope.$apply();
+ }
+ }
+
+ repeatFns.push({
+ nextTime:(now + delay),
+ delay: delay,
+ fn: tick,
+ id: nextRepeatId,
+ deferred: deferred
+ });
+ repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
+
+ nextRepeatId++;
+ return promise;
+ };
+ /**
+ * @ngdoc method
+ * @name $interval#cancel
+ *
+ * @description
+ * Cancels a task associated with the `promise`.
+ *
+ * @param {promise} promise A promise from calling the `$interval` function.
+ * @returns {boolean} Returns `true` if the task was successfully cancelled.
+ */
+ $interval.cancel = function(promise) {
+ if (!promise) return false;
+ var fnIndex;
+
+ angular.forEach(repeatFns, function(fn, index) {
+ if (fn.id === promise.$$intervalId) fnIndex = index;
+ });
+
+ if (fnIndex !== undefined) {
+ repeatFns[fnIndex].deferred.reject('canceled');
+ repeatFns.splice(fnIndex, 1);
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @ngdoc method
+ * @name $interval#flush
+ * @description
+ *
+ * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
+ *
+ * @param {number=} millis maximum timeout amount to flush up until.
+ *
+ * @return {number} The amount of time moved forward.
+ */
+ $interval.flush = function(millis) {
+ now += millis;
+ while (repeatFns.length && repeatFns[0].nextTime <= now) {
+ var task = repeatFns[0];
+ task.fn();
+ task.nextTime += task.delay;
+ repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
+ }
+ return millis;
+ };
+
+ return $interval;
+ }];
+};
+
+
+/* jshint -W101 */
+/* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
+ * This directive should go inside the anonymous function but a bug in JSHint means that it would
+ * not be enacted early enough to prevent the warning.
+ */
+var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
+
+function jsonStringToDate(string) {
+ var match;
+ if (match = string.match(R_ISO8061_STR)) {
+ var date = new Date(0),
+ tzHour = 0,
+ tzMin = 0;
+ if (match[9]) {
+ tzHour = int(match[9] + match[10]);
+ tzMin = int(match[9] + match[11]);
+ }
+ date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
+ date.setUTCHours(int(match[4] || 0) - tzHour,
+ int(match[5] || 0) - tzMin,
+ int(match[6] || 0),
+ int(match[7] || 0));
+ return date;
+ }
+ return string;
+}
+
+function int(str) {
+ return parseInt(str, 10);
+}
+
+function padNumber(num, digits, trim) {
+ var neg = '';
+ if (num < 0) {
+ neg = '-';
+ num = -num;
+ }
+ num = '' + num;
+ while (num.length < digits) num = '0' + num;
+ if (trim)
+ num = num.substr(num.length - digits);
+ return neg + num;
+}
+
+
+/**
+ * @ngdoc type
+ * @name angular.mock.TzDate
+ * @description
+ *
+ * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
+ *
+ * Mock of the Date type which has its timezone specified via constructor arg.
+ *
+ * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
+ * offset, so that we can test code that depends on local timezone settings without dependency on
+ * the time zone settings of the machine where the code is running.
+ *
+ * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
+ * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
+ *
+ * @example
+ * !!!! WARNING !!!!!
+ * This is not a complete Date object so only methods that were implemented can be called safely.
+ * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
+ *
+ * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
+ * incomplete we might be missing some non-standard methods. This can result in errors like:
+ * "Date.prototype.foo called on incompatible Object".
+ *
+ * ```js
+ * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
+ * newYearInBratislava.getTimezoneOffset() => -60;
+ * newYearInBratislava.getFullYear() => 2010;
+ * newYearInBratislava.getMonth() => 0;
+ * newYearInBratislava.getDate() => 1;
+ * newYearInBratislava.getHours() => 0;
+ * newYearInBratislava.getMinutes() => 0;
+ * newYearInBratislava.getSeconds() => 0;
+ * ```
+ *
+ */
+angular.mock.TzDate = function(offset, timestamp) {
+ var self = new Date(0);
+ if (angular.isString(timestamp)) {
+ var tsStr = timestamp;
+
+ self.origDate = jsonStringToDate(timestamp);
+
+ timestamp = self.origDate.getTime();
+ if (isNaN(timestamp))
+ throw {
+ name: "Illegal Argument",
+ message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
+ };
+ } else {
+ self.origDate = new Date(timestamp);
+ }
+
+ var localOffset = new Date(timestamp).getTimezoneOffset();
+ self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60;
+ self.date = new Date(timestamp + self.offsetDiff);
+
+ self.getTime = function() {
+ return self.date.getTime() - self.offsetDiff;
+ };
+
+ self.toLocaleDateString = function() {
+ return self.date.toLocaleDateString();
+ };
+
+ self.getFullYear = function() {
+ return self.date.getFullYear();
+ };
+
+ self.getMonth = function() {
+ return self.date.getMonth();
+ };
+
+ self.getDate = function() {
+ return self.date.getDate();
+ };
+
+ self.getHours = function() {
+ return self.date.getHours();
+ };
+
+ self.getMinutes = function() {
+ return self.date.getMinutes();
+ };
+
+ self.getSeconds = function() {
+ return self.date.getSeconds();
+ };
+
+ self.getMilliseconds = function() {
+ return self.date.getMilliseconds();
+ };
+
+ self.getTimezoneOffset = function() {
+ return offset * 60;
+ };
+
+ self.getUTCFullYear = function() {
+ return self.origDate.getUTCFullYear();
+ };
+
+ self.getUTCMonth = function() {
+ return self.origDate.getUTCMonth();
+ };
+
+ self.getUTCDate = function() {
+ return self.origDate.getUTCDate();
+ };
+
+ self.getUTCHours = function() {
+ return self.origDate.getUTCHours();
+ };
+
+ self.getUTCMinutes = function() {
+ return self.origDate.getUTCMinutes();
+ };
+
+ self.getUTCSeconds = function() {
+ return self.origDate.getUTCSeconds();
+ };
+
+ self.getUTCMilliseconds = function() {
+ return self.origDate.getUTCMilliseconds();
+ };
+
+ self.getDay = function() {
+ return self.date.getDay();
+ };
+
+ // provide this method only on browsers that already have it
+ if (self.toISOString) {
+ self.toISOString = function() {
+ return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
+ padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
+ padNumber(self.origDate.getUTCDate(), 2) + 'T' +
+ padNumber(self.origDate.getUTCHours(), 2) + ':' +
+ padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
+ padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
+ padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z';
+ };
+ }
+
+ //hide all methods not implemented in this mock that the Date prototype exposes
+ var unimplementedMethods = ['getUTCDay',
+ 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
+ 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
+ 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
+ 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
+ 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
+
+ angular.forEach(unimplementedMethods, function(methodName) {
+ self[methodName] = function() {
+ throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
+ };
+ });
+
+ return self;
+};
+
+//make "tzDateInstance instanceof Date" return true
+angular.mock.TzDate.prototype = Date.prototype;
+/* jshint +W101 */
+
+angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
+
+ .config(['$provide', function($provide) {
+
+ var reflowQueue = [];
+ $provide.value('$$animateReflow', function(fn) {
+ var index = reflowQueue.length;
+ reflowQueue.push(fn);
+ return function cancel() {
+ reflowQueue.splice(index, 1);
+ };
+ });
+
+ $provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser',
+ function($delegate, $$asyncCallback, $timeout, $browser) {
+ var animate = {
+ queue: [],
+ cancel: $delegate.cancel,
+ enabled: $delegate.enabled,
+ triggerCallbackEvents: function() {
+ $$asyncCallback.flush();
+ },
+ triggerCallbackPromise: function() {
+ $timeout.flush(0);
+ },
+ triggerCallbacks: function() {
+ this.triggerCallbackEvents();
+ this.triggerCallbackPromise();
+ },
+ triggerReflow: function() {
+ angular.forEach(reflowQueue, function(fn) {
+ fn();
+ });
+ reflowQueue = [];
+ }
+ };
+
+ angular.forEach(
+ ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
+ animate[method] = function() {
+ animate.queue.push({
+ event: method,
+ element: arguments[0],
+ options: arguments[arguments.length - 1],
+ args: arguments
+ });
+ return $delegate[method].apply($delegate, arguments);
+ };
+ });
+
+ return animate;
+ }]);
+
+ }]);
+
+
+/**
+ * @ngdoc function
+ * @name angular.mock.dump
+ * @description
+ *
+ * *NOTE*: this is not an injectable instance, just a globally available function.
+ *
+ * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
+ * debugging.
+ *
+ * This method is also available on window, where it can be used to display objects on debug
+ * console.
+ *
+ * @param {*} object - any object to turn into string.
+ * @return {string} a serialized string of the argument
+ */
+angular.mock.dump = function(object) {
+ return serialize(object);
+
+ function serialize(object) {
+ var out;
+
+ if (angular.isElement(object)) {
+ object = angular.element(object);
+ out = angular.element('<div></div>');
+ angular.forEach(object, function(element) {
+ out.append(angular.element(element).clone());
+ });
+ out = out.html();
+ } else if (angular.isArray(object)) {
+ out = [];
+ angular.forEach(object, function(o) {
+ out.push(serialize(o));
+ });
+ out = '[ ' + out.join(', ') + ' ]';
+ } else if (angular.isObject(object)) {
+ if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
+ out = serializeScope(object);
+ } else if (object instanceof Error) {
+ out = object.stack || ('' + object.name + ': ' + object.message);
+ } else {
+ // TODO(i): this prevents methods being logged,
+ // we should have a better way to serialize objects
+ out = angular.toJson(object, true);
+ }
+ } else {
+ out = String(object);
+ }
+
+ return out;
+ }
+
+ function serializeScope(scope, offset) {
+ offset = offset || ' ';
+ var log = [offset + 'Scope(' + scope.$id + '): {'];
+ for (var key in scope) {
+ if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
+ log.push(' ' + key + ': ' + angular.toJson(scope[key]));
+ }
+ }
+ var child = scope.$$childHead;
+ while (child) {
+ log.push(serializeScope(child, offset + ' '));
+ child = child.$$nextSibling;
+ }
+ log.push('}');
+ return log.join('\n' + offset);
+ }
+};
+
+/**
+ * @ngdoc service
+ * @name $httpBackend
+ * @description
+ * Fake HTTP backend implementation suitable for unit testing applications that use the
+ * {@link ng.$http $http service}.
+ *
+ * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
+ * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
+ *
+ * During unit testing, we want our unit tests to run quickly and have no external dependencies so
+ * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
+ * [JSONP](http://en.wikipedia.org/wiki/JSONP) requests to a real server. All we really need is
+ * to verify whether a certain request has been sent or not, or alternatively just let the
+ * application make requests, respond with pre-trained responses and assert that the end result is
+ * what we expect it to be.
+ *
+ * This mock implementation can be used to respond with static or dynamic responses via the
+ * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
+ *
+ * When an Angular application needs some data from a server, it calls the $http service, which
+ * sends the request to a real server using $httpBackend service. With dependency injection, it is
+ * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
+ * the requests and respond with some testing data without sending a request to a real server.
+ *
+ * There are two ways to specify what test data should be returned as http responses by the mock
+ * backend when the code under test makes http requests:
+ *
+ * - `$httpBackend.expect` - specifies a request expectation
+ * - `$httpBackend.when` - specifies a backend definition
+ *
+ *
+ * # Request Expectations vs Backend Definitions
+ *
+ * Request expectations provide a way to make assertions about requests made by the application and
+ * to define responses for those requests. The test will fail if the expected requests are not made
+ * or they are made in the wrong order.
+ *
+ * Backend definitions allow you to define a fake backend for your application which doesn't assert
+ * if a particular request was made or not, it just returns a trained response if a request is made.
+ * The test will pass whether or not the request gets made during testing.
+ *
+ *
+ * <table class="table">
+ * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
+ * <tr>
+ * <th>Syntax</th>
+ * <td>.expect(...).respond(...)</td>
+ * <td>.when(...).respond(...)</td>
+ * </tr>
+ * <tr>
+ * <th>Typical usage</th>
+ * <td>strict unit tests</td>
+ * <td>loose (black-box) unit testing</td>
+ * </tr>
+ * <tr>
+ * <th>Fulfills multiple requests</th>
+ * <td>NO</td>
+ * <td>YES</td>
+ * </tr>
+ * <tr>
+ * <th>Order of requests matters</th>
+ * <td>YES</td>
+ * <td>NO</td>
+ * </tr>
+ * <tr>
+ * <th>Request required</th>
+ * <td>YES</td>
+ * <td>NO</td>
+ * </tr>
+ * <tr>
+ * <th>Response required</th>
+ * <td>optional (see below)</td>
+ * <td>YES</td>
+ * </tr>
+ * </table>
+ *
+ * In cases where both backend definitions and request expectations are specified during unit
+ * testing, the request expectations are evaluated first.
+ *
+ * If a request expectation has no response specified, the algorithm will search your backend
+ * definitions for an appropriate response.
+ *
+ * If a request didn't match any expectation or if the expectation doesn't have the response
+ * defined, the backend definitions are evaluated in sequential order to see if any of them match
+ * the request. The response from the first matched definition is returned.
+ *
+ *
+ * # Flushing HTTP requests
+ *
+ * The $httpBackend used in production always responds to requests asynchronously. If we preserved
+ * this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
+ * to follow and to maintain. But neither can the testing mock respond synchronously; that would
+ * change the execution of the code under test. For this reason, the mock $httpBackend has a
+ * `flush()` method, which allows the test to explicitly flush pending requests. This preserves
+ * the async api of the backend, while allowing the test to execute synchronously.
+ *
+ *
+ * # Unit testing with mock $httpBackend
+ * The following code shows how to setup and use the mock backend when unit testing a controller.
+ * First we create the controller under test:
+ *
+ ```js
+ // The module code
+ angular
+ .module('MyApp', [])
+ .controller('MyController', MyController);
+
+ // The controller code
+ function MyController($scope, $http) {
+ var authToken;
+
+ $http.get('/auth.py').success(function(data, status, headers) {
+ authToken = headers('A-Token');
+ $scope.user = data;
+ });
+
+ $scope.saveMessage = function(message) {
+ var headers = { 'Authorization': authToken };
+ $scope.status = 'Saving...';
+
+ $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
+ $scope.status = '';
+ }).error(function() {
+ $scope.status = 'ERROR!';
+ });
+ };
+ }
+ ```
+ *
+ * Now we setup the mock backend and create the test specs:
+ *
+ ```js
+ // testing controller
+ describe('MyController', function() {
+ var $httpBackend, $rootScope, createController, authRequestHandler;
+
+ // Set up the module
+ beforeEach(module('MyApp'));
+
+ beforeEach(inject(function($injector) {
+ // Set up the mock http service responses
+ $httpBackend = $injector.get('$httpBackend');
+ // backend definition common for all tests
+ authRequestHandler = $httpBackend.when('GET', '/auth.py')
+ .respond({userId: 'userX'}, {'A-Token': 'xxx'});
+
+ // Get hold of a scope (i.e. the root scope)
+ $rootScope = $injector.get('$rootScope');
+ // The $controller service is used to create instances of controllers
+ var $controller = $injector.get('$controller');
+
+ createController = function() {
+ return $controller('MyController', {'$scope' : $rootScope });
+ };
+ }));
+
+
+ afterEach(function() {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+
+ it('should fetch authentication token', function() {
+ $httpBackend.expectGET('/auth.py');
+ var controller = createController();
+ $httpBackend.flush();
+ });
+
+
+ it('should fail authentication', function() {
+
+ // Notice how you can change the response even after it was set
+ authRequestHandler.respond(401, '');
+
+ $httpBackend.expectGET('/auth.py');
+ var controller = createController();
+ $httpBackend.flush();
+ expect($rootScope.status).toBe('Failed...');
+ });
+
+
+ it('should send msg to server', function() {
+ var controller = createController();
+ $httpBackend.flush();
+
+ // now you don’t care about the authentication, but
+ // the controller will still send the request and
+ // $httpBackend will respond without you having to
+ // specify the expectation and response for this request
+
+ $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
+ $rootScope.saveMessage('message content');
+ expect($rootScope.status).toBe('Saving...');
+ $httpBackend.flush();
+ expect($rootScope.status).toBe('');
+ });
+
+
+ it('should send auth header', function() {
+ var controller = createController();
+ $httpBackend.flush();
+
+ $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
+ // check if the header was send, if it wasn't the expectation won't
+ // match the request and the test will fail
+ return headers['Authorization'] == 'xxx';
+ }).respond(201, '');
+
+ $rootScope.saveMessage('whatever');
+ $httpBackend.flush();
+ });
+ });
+ ```
+ */
+angular.mock.$HttpBackendProvider = function() {
+ this.$get = ['$rootScope', '$timeout', createHttpBackendMock];
+};
+
+/**
+ * General factory function for $httpBackend mock.
+ * Returns instance for unit testing (when no arguments specified):
+ * - passing through is disabled
+ * - auto flushing is disabled
+ *
+ * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
+ * - passing through (delegating request to real backend) is enabled
+ * - auto flushing is enabled
+ *
+ * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
+ * @param {Object=} $browser Auto-flushing enabled if specified
+ * @return {Object} Instance of $httpBackend mock
+ */
+function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
+ var definitions = [],
+ expectations = [],
+ responses = [],
+ responsesPush = angular.bind(responses, responses.push),
+ copy = angular.copy;
+
+ function createResponse(status, data, headers, statusText) {
+ if (angular.isFunction(status)) return status;
+
+ return function() {
+ return angular.isNumber(status)
+ ? [status, data, headers, statusText]
+ : [200, status, data, headers];
+ };
+ }
+
+ // TODO(vojta): change params to: method, url, data, headers, callback
+ function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
+ var xhr = new MockXhr(),
+ expectation = expectations[0],
+ wasExpected = false;
+
+ function prettyPrint(data) {
+ return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
+ ? data
+ : angular.toJson(data);
+ }
+
+ function wrapResponse(wrapped) {
+ if (!$browser && timeout) {
+ timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout);
+ }
+
+ return handleResponse;
+
+ function handleResponse() {
+ var response = wrapped.response(method, url, data, headers);
+ xhr.$$respHeaders = response[2];
+ callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
+ copy(response[3] || ''));
+ }
+
+ function handleTimeout() {
+ for (var i = 0, ii = responses.length; i < ii; i++) {
+ if (responses[i] === handleResponse) {
+ responses.splice(i, 1);
+ callback(-1, undefined, '');
+ break;
+ }
+ }
+ }
+ }
+
+ if (expectation && expectation.match(method, url)) {
+ if (!expectation.matchData(data))
+ throw new Error('Expected ' + expectation + ' with different data\n' +
+ 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
+
+ if (!expectation.matchHeaders(headers))
+ throw new Error('Expected ' + expectation + ' with different headers\n' +
+ 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
+ prettyPrint(headers));
+
+ expectations.shift();
+
+ if (expectation.response) {
+ responses.push(wrapResponse(expectation));
+ return;
+ }
+ wasExpected = true;
+ }
+
+ var i = -1, definition;
+ while ((definition = definitions[++i])) {
+ if (definition.match(method, url, data, headers || {})) {
+ if (definition.response) {
+ // if $browser specified, we do auto flush all requests
+ ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
+ } else if (definition.passThrough) {
+ $delegate(method, url, data, callback, headers, timeout, withCredentials);
+ } else throw new Error('No response defined !');
+ return;
+ }
+ }
+ throw wasExpected ?
+ new Error('No response defined !') :
+ new Error('Unexpected request: ' + method + ' ' + url + '\n' +
+ (expectation ? 'Expected ' + expectation : 'No more request expected'));
+ }
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#when
+ * @description
+ * Creates a new backend definition.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
+ * data string and returns true if the data is as expected.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ *
+ * - respond –
+ * `{function([status,] data[, headers, statusText])
+ * | function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can
+ * return an array containing response status (number), response data (string), response
+ * headers (Object), and the text for the status (string). The respond method returns the
+ * `requestHandler` object for possible overrides.
+ */
+ $httpBackend.when = function(method, url, data, headers) {
+ var definition = new MockHttpExpectation(method, url, data, headers),
+ chain = {
+ respond: function(status, data, headers, statusText) {
+ definition.passThrough = undefined;
+ definition.response = createResponse(status, data, headers, statusText);
+ return chain;
+ }
+ };
+
+ if ($browser) {
+ chain.passThrough = function() {
+ definition.response = undefined;
+ definition.passThrough = true;
+ return chain;
+ };
+ }
+
+ definitions.push(definition);
+ return chain;
+ };
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#whenGET
+ * @description
+ * Creates a new backend definition for GET requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#whenHEAD
+ * @description
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#whenDELETE
+ * @description
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#whenPOST
+ * @description
+ * Creates a new backend definition for POST requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
+ * data string and returns true if the data is as expected.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#whenPUT
+ * @description
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
+ * data string and returns true if the data is as expected.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#whenJSONP
+ * @description
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+ createShortMethods('when');
+
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expect
+ * @description
+ * Creates a new request expectation.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current expectation.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ *
+ * - respond –
+ * `{function([status,] data[, headers, statusText])
+ * | function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can
+ * return an array containing response status (number), response data (string), response
+ * headers (Object), and the text for the status (string). The respond method returns the
+ * `requestHandler` object for possible overrides.
+ */
+ $httpBackend.expect = function(method, url, data, headers) {
+ var expectation = new MockHttpExpectation(method, url, data, headers),
+ chain = {
+ respond: function(status, data, headers, statusText) {
+ expectation.response = createResponse(status, data, headers, statusText);
+ return chain;
+ }
+ };
+
+ expectations.push(expectation);
+ return chain;
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectGET
+ * @description
+ * Creates a new request expectation for GET requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled. See #expect for more info.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectHEAD
+ * @description
+ * Creates a new request expectation for HEAD requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectDELETE
+ * @description
+ * Creates a new request expectation for DELETE requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectPOST
+ * @description
+ * Creates a new request expectation for POST requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectPUT
+ * @description
+ * Creates a new request expectation for PUT requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectPATCH
+ * @description
+ * Creates a new request expectation for PATCH requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
+ * receives data string and returns true if the data is as expected, or Object if request body
+ * is in JSON format.
+ * @param {Object=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#expectJSONP
+ * @description
+ * Creates a new request expectation for JSONP requests. For more info see `expect()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that control how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
+ */
+ createShortMethods('expect');
+
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#flush
+ * @description
+ * Flushes all pending requests using the trained responses.
+ *
+ * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
+ * all pending requests will be flushed. If there are no pending requests when the flush method
+ * is called an exception is thrown (as this typically a sign of programming error).
+ */
+ $httpBackend.flush = function(count, digest) {
+ if (digest !== false) $rootScope.$digest();
+ if (!responses.length) throw new Error('No pending request to flush !');
+
+ if (angular.isDefined(count) && count !== null) {
+ while (count--) {
+ if (!responses.length) throw new Error('No more pending request to flush !');
+ responses.shift()();
+ }
+ } else {
+ while (responses.length) {
+ responses.shift()();
+ }
+ }
+ $httpBackend.verifyNoOutstandingExpectation(digest);
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#verifyNoOutstandingExpectation
+ * @description
+ * Verifies that all of the requests defined via the `expect` api were made. If any of the
+ * requests were not made, verifyNoOutstandingExpectation throws an exception.
+ *
+ * Typically, you would call this method following each test case that asserts requests using an
+ * "afterEach" clause.
+ *
+ * ```js
+ * afterEach($httpBackend.verifyNoOutstandingExpectation);
+ * ```
+ */
+ $httpBackend.verifyNoOutstandingExpectation = function(digest) {
+ if (digest !== false) $rootScope.$digest();
+ if (expectations.length) {
+ throw new Error('Unsatisfied requests: ' + expectations.join(', '));
+ }
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#verifyNoOutstandingRequest
+ * @description
+ * Verifies that there are no outstanding requests that need to be flushed.
+ *
+ * Typically, you would call this method following each test case that asserts requests using an
+ * "afterEach" clause.
+ *
+ * ```js
+ * afterEach($httpBackend.verifyNoOutstandingRequest);
+ * ```
+ */
+ $httpBackend.verifyNoOutstandingRequest = function() {
+ if (responses.length) {
+ throw new Error('Unflushed requests: ' + responses.length);
+ }
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name $httpBackend#resetExpectations
+ * @description
+ * Resets all request expectations, but preserves all backend definitions. Typically, you would
+ * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
+ * $httpBackend mock.
+ */
+ $httpBackend.resetExpectations = function() {
+ expectations.length = 0;
+ responses.length = 0;
+ };
+
+ return $httpBackend;
+
+
+ function createShortMethods(prefix) {
+ angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
+ $httpBackend[prefix + method] = function(url, headers) {
+ return $httpBackend[prefix](method, url, undefined, headers);
+ };
+ });
+
+ angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
+ $httpBackend[prefix + method] = function(url, data, headers) {
+ return $httpBackend[prefix](method, url, data, headers);
+ };
+ });
+ }
+}
+
+function MockHttpExpectation(method, url, data, headers) {
+
+ this.data = data;
+ this.headers = headers;
+
+ this.match = function(m, u, d, h) {
+ if (method != m) return false;
+ if (!this.matchUrl(u)) return false;
+ if (angular.isDefined(d) && !this.matchData(d)) return false;
+ if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
+ return true;
+ };
+
+ this.matchUrl = function(u) {
+ if (!url) return true;
+ if (angular.isFunction(url.test)) return url.test(u);
+ if (angular.isFunction(url)) return url(u);
+ return url == u;
+ };
+
+ this.matchHeaders = function(h) {
+ if (angular.isUndefined(headers)) return true;
+ if (angular.isFunction(headers)) return headers(h);
+ return angular.equals(headers, h);
+ };
+
+ this.matchData = function(d) {
+ if (angular.isUndefined(data)) return true;
+ if (data && angular.isFunction(data.test)) return data.test(d);
+ if (data && angular.isFunction(data)) return data(d);
+ if (data && !angular.isString(data)) {
+ return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
+ }
+ return data == d;
+ };
+
+ this.toString = function() {
+ return method + ' ' + url;
+ };
+}
+
+function createMockXhr() {
+ return new MockXhr();
+}
+
+function MockXhr() {
+
+ // hack for testing $http, $httpBackend
+ MockXhr.$$lastInstance = this;
+
+ this.open = function(method, url, async) {
+ this.$$method = method;
+ this.$$url = url;
+ this.$$async = async;
+ this.$$reqHeaders = {};
+ this.$$respHeaders = {};
+ };
+
+ this.send = function(data) {
+ this.$$data = data;
+ };
+
+ this.setRequestHeader = function(key, value) {
+ this.$$reqHeaders[key] = value;
+ };
+
+ this.getResponseHeader = function(name) {
+ // the lookup must be case insensitive,
+ // that's why we try two quick lookups first and full scan last
+ var header = this.$$respHeaders[name];
+ if (header) return header;
+
+ name = angular.lowercase(name);
+ header = this.$$respHeaders[name];
+ if (header) return header;
+
+ header = undefined;
+ angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
+ if (!header && angular.lowercase(headerName) == name) header = headerVal;
+ });
+ return header;
+ };
+
+ this.getAllResponseHeaders = function() {
+ var lines = [];
+
+ angular.forEach(this.$$respHeaders, function(value, key) {
+ lines.push(key + ': ' + value);
+ });
+ return lines.join('\n');
+ };
+
+ this.abort = angular.noop;
+}
+
+
+/**
+ * @ngdoc service
+ * @name $timeout
+ * @description
+ *
+ * This service is just a simple decorator for {@link ng.$timeout $timeout} service
+ * that adds a "flush" and "verifyNoPendingTasks" methods.
+ */
+
+angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) {
+
+ /**
+ * @ngdoc method
+ * @name $timeout#flush
+ * @description
+ *
+ * Flushes the queue of pending tasks.
+ *
+ * @param {number=} delay maximum timeout amount to flush up until
+ */
+ $delegate.flush = function(delay) {
+ $browser.defer.flush(delay);
+ };
+
+ /**
+ * @ngdoc method
+ * @name $timeout#verifyNoPendingTasks
+ * @description
+ *
+ * Verifies that there are no pending tasks that need to be flushed.
+ */
+ $delegate.verifyNoPendingTasks = function() {
+ if ($browser.deferredFns.length) {
+ throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
+ formatPendingTasksAsString($browser.deferredFns));
+ }
+ };
+
+ function formatPendingTasksAsString(tasks) {
+ var result = [];
+ angular.forEach(tasks, function(task) {
+ result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}');
+ });
+
+ return result.join(', ');
+ }
+
+ return $delegate;
+}];
+
+angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
+ var queue = [];
+ var rafFn = function(fn) {
+ var index = queue.length;
+ queue.push(fn);
+ return function() {
+ queue.splice(index, 1);
+ };
+ };
+
+ rafFn.supported = $delegate.supported;
+
+ rafFn.flush = function() {
+ if (queue.length === 0) {
+ throw new Error('No rAF callbacks present');
+ }
+
+ var length = queue.length;
+ for (var i = 0; i < length; i++) {
+ queue[i]();
+ }
+
+ queue = [];
+ };
+
+ return rafFn;
+}];
+
+angular.mock.$AsyncCallbackDecorator = ['$delegate', function($delegate) {
+ var callbacks = [];
+ var addFn = function(fn) {
+ callbacks.push(fn);
+ };
+ addFn.flush = function() {
+ angular.forEach(callbacks, function(fn) {
+ fn();
+ });
+ callbacks = [];
+ };
+ return addFn;
+}];
+
+/**
+ *
+ */
+angular.mock.$RootElementProvider = function() {
+ this.$get = function() {
+ return angular.element('<div ng-app></div>');
+ };
+};
+
+/**
+ * @ngdoc module
+ * @name ngMock
+ * @packageName angular-mocks
+ * @description
+ *
+ * # ngMock
+ *
+ * The `ngMock` module provides support to inject and mock Angular services into unit tests.
+ * In addition, ngMock also extends various core ng services such that they can be
+ * inspected and controlled in a synchronous manner within test code.
+ *
+ *
+ * <div doc-module-components="ngMock"></div>
+ *
+ */
+angular.module('ngMock', ['ng']).provider({
+ $browser: angular.mock.$BrowserProvider,
+ $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
+ $log: angular.mock.$LogProvider,
+ $interval: angular.mock.$IntervalProvider,
+ $httpBackend: angular.mock.$HttpBackendProvider,
+ $rootElement: angular.mock.$RootElementProvider
+}).config(['$provide', function($provide) {
+ $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
+ $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
+ $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
+ $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
+}]);
+
+/**
+ * @ngdoc module
+ * @name ngMockE2E
+ * @module ngMockE2E
+ * @packageName angular-mocks
+ * @description
+ *
+ * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
+ * Currently there is only one mock present in this module -
+ * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
+ */
+angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
+ $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
+}]);
+
+/**
+ * @ngdoc service
+ * @name $httpBackend
+ * @module ngMockE2E
+ * @description
+ * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
+ * applications that use the {@link ng.$http $http service}.
+ *
+ * *Note*: For fake http backend implementation suitable for unit testing please see
+ * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
+ *
+ * This implementation can be used to respond with static or dynamic responses via the `when` api
+ * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
+ * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
+ * templates from a webserver).
+ *
+ * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
+ * is being developed with the real backend api replaced with a mock, it is often desirable for
+ * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
+ * templates or static files from the webserver). To configure the backend with this behavior
+ * use the `passThrough` request handler of `when` instead of `respond`.
+ *
+ * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
+ * testing. For this reason the e2e $httpBackend flushes mocked out requests
+ * automatically, closely simulating the behavior of the XMLHttpRequest object.
+ *
+ * To setup the application to run with this http backend, you have to create a module that depends
+ * on the `ngMockE2E` and your application modules and defines the fake backend:
+ *
+ * ```js
+ * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
+ * myAppDev.run(function($httpBackend) {
+ * phones = [{name: 'phone1'}, {name: 'phone2'}];
+ *
+ * // returns the current list of phones
+ * $httpBackend.whenGET('/phones').respond(phones);
+ *
+ * // adds a new phone to the phones array
+ * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
+ * var phone = angular.fromJson(data);
+ * phones.push(phone);
+ * return [200, phone, {}];
+ * });
+ * $httpBackend.whenGET(/^\/templates\//).passThrough();
+ * //...
+ * });
+ * ```
+ *
+ * Afterwards, bootstrap your app with this new module.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#when
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition.
+ *
+ * @param {string} method HTTP method.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
+ * object and returns true if the headers match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ *
+ * - respond –
+ * `{function([status,] data[, headers, statusText])
+ * | function(function(method, url, data, headers)}`
+ * – The respond method takes a set of static data to be returned or a function that can return
+ * an array containing response status (number), response data (string), response headers
+ * (Object), and the text for the status (string).
+ * - passThrough – `{function()}` – Any request matching a backend definition with
+ * `passThrough` handler will be passed through to the real backend (an XHR request will be made
+ * to the server.)
+ * - Both methods return the `requestHandler` object for possible overrides.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenGET
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition for GET requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenHEAD
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition for HEAD requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenDELETE
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition for DELETE requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenPOST
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition for POST requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenPUT
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition for PUT requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenPATCH
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition for PATCH requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @param {(string|RegExp)=} data HTTP request body.
+ * @param {(Object|function(Object))=} headers HTTP headers.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
+
+/**
+ * @ngdoc method
+ * @name $httpBackend#whenJSONP
+ * @module ngMockE2E
+ * @description
+ * Creates a new backend definition for JSONP requests. For more info see `when()`.
+ *
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
+ * and returns true if the url match the current definition.
+ * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
+ */
+angular.mock.e2e = {};
+angular.mock.e2e.$httpBackendDecorator =
+ ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock];
+
+
+/**
+ * @ngdoc type
+ * @name $rootScope.Scope
+ * @module ngMock
+ * @description
+ * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These
+ * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when
+ * `ngMock` module is loaded.
+ *
+ * In addition to all the regular `Scope` methods, the following helper methods are available:
+ */
+angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
+
+ var $rootScopePrototype = Object.getPrototypeOf($delegate);
+
+ $rootScopePrototype.$countChildScopes = countChildScopes;
+ $rootScopePrototype.$countWatchers = countWatchers;
+
+ return $delegate;
+
+ // ------------------------------------------------------------------------------------------ //
+
+ /**
+ * @ngdoc method
+ * @name $rootScope.Scope#$countChildScopes
+ * @module ngMock
+ * @description
+ * Counts all the direct and indirect child scopes of the current scope.
+ *
+ * The current scope is excluded from the count. The count includes all isolate child scopes.
+ *
+ * @returns {number} Total number of child scopes.
+ */
+ function countChildScopes() {
+ // jshint validthis: true
+ var count = 0; // exclude the current scope
+ var pendingChildHeads = [this.$$childHead];
+ var currentScope;
+
+ while (pendingChildHeads.length) {
+ currentScope = pendingChildHeads.shift();
+
+ while (currentScope) {
+ count += 1;
+ pendingChildHeads.push(currentScope.$$childHead);
+ currentScope = currentScope.$$nextSibling;
+ }
+ }
+
+ return count;
+ }
+
+
+ /**
+ * @ngdoc method
+ * @name $rootScope.Scope#$countWatchers
+ * @module ngMock
+ * @description
+ * Counts all the watchers of direct and indirect child scopes of the current scope.
+ *
+ * The watchers of the current scope are included in the count and so are all the watchers of
+ * isolate child scopes.
+ *
+ * @returns {number} Total number of watchers.
+ */
+ function countWatchers() {
+ // jshint validthis: true
+ var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
+ var pendingChildHeads = [this.$$childHead];
+ var currentScope;
+
+ while (pendingChildHeads.length) {
+ currentScope = pendingChildHeads.shift();
+
+ while (currentScope) {
+ count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
+ pendingChildHeads.push(currentScope.$$childHead);
+ currentScope = currentScope.$$nextSibling;
+ }
+ }
+
+ return count;
+ }
+}];
+
+
+if (window.jasmine || window.mocha) {
+
+ var currentSpec = null,
+ isSpecRunning = function() {
+ return !!currentSpec;
+ };
+
+
+ (window.beforeEach || window.setup)(function() {
+ currentSpec = this;
+ });
+
+ (window.afterEach || window.teardown)(function() {
+ var injector = currentSpec.$injector;
+
+ angular.forEach(currentSpec.$modules, function(module) {
+ if (module && module.$$hashKey) {
+ module.$$hashKey = undefined;
+ }
+ });
+
+ currentSpec.$injector = null;
+ currentSpec.$modules = null;
+ currentSpec = null;
+
+ if (injector) {
+ injector.get('$rootElement').off();
+ injector.get('$browser').pollFns.length = 0;
+ }
+
+ // clean up jquery's fragment cache
+ angular.forEach(angular.element.fragments, function(val, key) {
+ delete angular.element.fragments[key];
+ });
+
+ MockXhr.$$lastInstance = null;
+
+ angular.forEach(angular.callbacks, function(val, key) {
+ delete angular.callbacks[key];
+ });
+ angular.callbacks.counter = 0;
+ });
+
+ /**
+ * @ngdoc function
+ * @name angular.mock.module
+ * @description
+ *
+ * *NOTE*: This function is also published on window for easy access.<br>
+ * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
+ *
+ * This function registers a module configuration code. It collects the configuration information
+ * which will be used when the injector is created by {@link angular.mock.inject inject}.
+ *
+ * See {@link angular.mock.inject inject} for usage example
+ *
+ * @param {...(string|Function|Object)} fns any number of modules which are represented as string
+ * aliases or as anonymous module initialization functions. The modules are used to
+ * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
+ * object literal is passed they will be registered as values in the module, the key being
+ * the module name and the value being what is returned.
+ */
+ window.module = angular.mock.module = function() {
+ var moduleFns = Array.prototype.slice.call(arguments, 0);
+ return isSpecRunning() ? workFn() : workFn;
+ /////////////////////
+ function workFn() {
+ if (currentSpec.$injector) {
+ throw new Error('Injector already created, can not register a module!');
+ } else {
+ var modules = currentSpec.$modules || (currentSpec.$modules = []);
+ angular.forEach(moduleFns, function(module) {
+ if (angular.isObject(module) && !angular.isArray(module)) {
+ modules.push(function($provide) {
+ angular.forEach(module, function(value, key) {
+ $provide.value(key, value);
+ });
+ });
+ } else {
+ modules.push(module);
+ }
+ });
+ }
+ }
+ };
+
+ /**
+ * @ngdoc function
+ * @name angular.mock.inject
+ * @description
+ *
+ * *NOTE*: This function is also published on window for easy access.<br>
+ * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
+ *
+ * The inject function wraps a function into an injectable function. The inject() creates new
+ * instance of {@link auto.$injector $injector} per test, which is then used for
+ * resolving references.
+ *
+ *
+ * ## Resolving References (Underscore Wrapping)
+ * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
+ * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
+ * that is declared in the scope of the `describe()` block. Since we would, most likely, want
+ * the variable to have the same name of the reference we have a problem, since the parameter
+ * to the `inject()` function would hide the outer variable.
+ *
+ * To help with this, the injected parameters can, optionally, be enclosed with underscores.
+ * These are ignored by the injector when the reference name is resolved.
+ *
+ * For example, the parameter `_myService_` would be resolved as the reference `myService`.
+ * Since it is available in the function body as _myService_, we can then assign it to a variable
+ * defined in an outer scope.
+ *
+ * ```
+ * // Defined out reference variable outside
+ * var myService;
+ *
+ * // Wrap the parameter in underscores
+ * beforeEach( inject( function(_myService_){
+ * myService = _myService_;
+ * }));
+ *
+ * // Use myService in a series of tests.
+ * it('makes use of myService', function() {
+ * myService.doStuff();
+ * });
+ *
+ * ```
+ *
+ * See also {@link angular.mock.module angular.mock.module}
+ *
+ * ## Example
+ * Example of what a typical jasmine tests looks like with the inject method.
+ * ```js
+ *
+ * angular.module('myApplicationModule', [])
+ * .value('mode', 'app')
+ * .value('version', 'v1.0.1');
+ *
+ *
+ * describe('MyApp', function() {
+ *
+ * // You need to load modules that you want to test,
+ * // it loads only the "ng" module by default.
+ * beforeEach(module('myApplicationModule'));
+ *
+ *
+ * // inject() is used to inject arguments of all given functions
+ * it('should provide a version', inject(function(mode, version) {
+ * expect(version).toEqual('v1.0.1');
+ * expect(mode).toEqual('app');
+ * }));
+ *
+ *
+ * // The inject and module method can also be used inside of the it or beforeEach
+ * it('should override a version and test the new version is injected', function() {
+ * // module() takes functions or strings (module aliases)
+ * module(function($provide) {
+ * $provide.value('version', 'overridden'); // override version here
+ * });
+ *
+ * inject(function(version) {
+ * expect(version).toEqual('overridden');
+ * });
+ * });
+ * });
+ *
+ * ```
+ *
+ * @param {...Function} fns any number of functions which will be injected using the injector.
+ */
+
+
+
+ var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
+ this.message = e.message;
+ this.name = e.name;
+ if (e.line) this.line = e.line;
+ if (e.sourceId) this.sourceId = e.sourceId;
+ if (e.stack && errorForStack)
+ this.stack = e.stack + '\n' + errorForStack.stack;
+ if (e.stackArray) this.stackArray = e.stackArray;
+ };
+ ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
+
+ window.inject = angular.mock.inject = function() {
+ var blockFns = Array.prototype.slice.call(arguments, 0);
+ var errorForStack = new Error('Declaration Location');
+ return isSpecRunning() ? workFn.call(currentSpec) : workFn;
+ /////////////////////
+ function workFn() {
+ var modules = currentSpec.$modules || [];
+ var strictDi = !!currentSpec.$injectorStrict;
+ modules.unshift('ngMock');
+ modules.unshift('ng');
+ var injector = currentSpec.$injector;
+ if (!injector) {
+ if (strictDi) {
+ // If strictDi is enabled, annotate the providerInjector blocks
+ angular.forEach(modules, function(moduleFn) {
+ if (typeof moduleFn === "function") {
+ angular.injector.$$annotate(moduleFn);
+ }
+ });
+ }
+ injector = currentSpec.$injector = angular.injector(modules, strictDi);
+ currentSpec.$injectorStrict = strictDi;
+ }
+ for (var i = 0, ii = blockFns.length; i < ii; i++) {
+ if (currentSpec.$injectorStrict) {
+ // If the injector is strict / strictDi, and the spec wants to inject using automatic
+ // annotation, then annotate the function here.
+ injector.annotate(blockFns[i]);
+ }
+ try {
+ /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
+ injector.invoke(blockFns[i] || angular.noop, this);
+ /* jshint +W040 */
+ } catch (e) {
+ if (e.stack && errorForStack) {
+ throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
+ }
+ throw e;
+ } finally {
+ errorForStack = null;
+ }
+ }
+ }
+ };
+
+
+ angular.mock.inject.strictDi = function(value) {
+ value = arguments.length ? !!value : true;
+ return isSpecRunning() ? workFn() : workFn;
+
+ function workFn() {
+ if (value !== currentSpec.$injectorStrict) {
+ if (currentSpec.$injector) {
+ throw new Error('Injector already created, can not modify strict annotations');
+ } else {
+ currentSpec.$injectorStrict = value;
+ }
+ }
+ }
+ };
+}
+
+
+})(window, window.angular);
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/angular-resource.min.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/angular-resource.min.js b/web/META-INF/resources/js/libs/angular-resource.min.js
new file mode 100755
index 0000000..dcb65a5
--- /dev/null
+++ b/web/META-INF/resources/js/libs/angular-resource.min.js
@@ -0,0 +1,13 @@
+/*
+ AngularJS v1.3.7
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(I,d,B){'use strict';function D(f,q){q=q||{};d.forEach(q,function(d,h){delete q[h]});for(var h in f)!f.hasOwnProperty(h)||"$"===h.charAt(0)&&"$"===h.charAt(1)||(q[h]=f[h]);return q}var w=d.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;d.module("ngResource",["ng"]).provider("$resource",function(){var f=this;this.defaults={stripTrailingSlashes:!0,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}};
+this.$get=["$http","$q",function(q,h){function t(d,g){this.template=d;this.defaults=s({},f.defaults,g);this.urlParams={}}function v(x,g,l,m){function c(b,k){var c={};k=s({},g,k);r(k,function(a,k){u(a)&&(a=a());var d;if(a&&a.charAt&&"@"==a.charAt(0)){d=b;var e=a.substr(1);if(null==e||""===e||"hasOwnProperty"===e||!C.test("."+e))throw w("badmember",e);for(var e=e.split("."),n=0,g=e.length;n<g&&d!==B;n++){var h=e[n];d=null!==d?d[h]:B}}else d=a;c[k]=d});return c}function F(b){return b.resource}function e(b){D(b||
+{},this)}var G=new t(x,m);l=s({},f.defaults.actions,l);e.prototype.toJSON=function(){var b=s({},this);delete b.$promise;delete b.$resolved;return b};r(l,function(b,k){var g=/^(POST|PUT|PATCH)$/i.test(b.method);e[k]=function(a,y,m,x){var n={},f,l,z;switch(arguments.length){case 4:z=x,l=m;case 3:case 2:if(u(y)){if(u(a)){l=a;z=y;break}l=y;z=m}else{n=a;f=y;l=m;break}case 1:u(a)?l=a:g?f=a:n=a;break;case 0:break;default:throw w("badargs",arguments.length);}var t=this instanceof e,p=t?f:b.isArray?[]:new e(f),
+A={},v=b.interceptor&&b.interceptor.response||F,C=b.interceptor&&b.interceptor.responseError||B;r(b,function(b,a){"params"!=a&&"isArray"!=a&&"interceptor"!=a&&(A[a]=H(b))});g&&(A.data=f);G.setUrlParams(A,s({},c(f,b.params||{}),n),b.url);n=q(A).then(function(a){var c=a.data,g=p.$promise;if(c){if(d.isArray(c)!==!!b.isArray)throw w("badcfg",k,b.isArray?"array":"object",d.isArray(c)?"array":"object");b.isArray?(p.length=0,r(c,function(a){"object"===typeof a?p.push(new e(a)):p.push(a)})):(D(c,p),p.$promise=
+g)}p.$resolved=!0;a.resource=p;return a},function(a){p.$resolved=!0;(z||E)(a);return h.reject(a)});n=n.then(function(a){var b=v(a);(l||E)(b,a.headers);return b},C);return t?n:(p.$promise=n,p.$resolved=!1,p)};e.prototype["$"+k]=function(a,b,c){u(a)&&(c=b,b=a,a={});a=e[k].call(this,a,this,b,c);return a.$promise||a}});e.bind=function(b){return v(x,s({},g,b),l)};return e}var E=d.noop,r=d.forEach,s=d.extend,H=d.copy,u=d.isFunction;t.prototype={setUrlParams:function(f,g,l){var m=this,c=l||m.template,h,
+e,q=m.urlParams={};r(c.split(/\W/),function(b){if("hasOwnProperty"===b)throw w("badname");!/^\d+$/.test(b)&&b&&(new RegExp("(^|[^\\\\]):"+b+"(\\W|$)")).test(c)&&(q[b]=!0)});c=c.replace(/\\:/g,":");g=g||{};r(m.urlParams,function(b,k){h=g.hasOwnProperty(k)?g[k]:m.defaults[k];d.isDefined(h)&&null!==h?(e=encodeURIComponent(h).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),c=c.replace(new RegExp(":"+
+k+"(\\W|$)","g"),function(b,a){return e+a})):c=c.replace(new RegExp("(/?):"+k+"(\\W|$)","g"),function(b,a,c){return"/"==c.charAt(0)?c:a+c})});m.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/");c=c.replace(/\/\.(?=\w+($|\?))/,".");f.url=c.replace(/\/\\\./,"/.");r(g,function(b,c){m.urlParams[c]||(f.params=f.params||{},f.params[c]=b)})}};return v}]})})(window,window.angular);
+//# sourceMappingURL=angular-resource.min.js.map
[14/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RequestUrl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RequestUrl.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RequestUrl.java
new file mode 100644
index 0000000..bbfb79c
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RequestUrl.java
@@ -0,0 +1,294 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ClassName: RequestUrl Function: request url relate operations
+ */
+public class RequestUrl {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RequestUrl.class);
+
+ /**
+ * Default Constructor
+ */
+ public RequestUrl() {
+ /* Default Constructor */
+ }
+
+ /**
+ * UrlPage: Get url page from url link
+ *
+ * @param strURL request url
+ * @return page name
+ */
+ public static String urlPage(String strURL) {
+ String strPage = null;
+ String[] arrSplit = null;
+
+ String newURL = strURL.trim().toLowerCase();
+
+ arrSplit = newURL.split("[?]");
+ if (newURL.length() > 0 && arrSplit.length > 1 && arrSplit[0] != null) {
+ strPage = arrSplit[0];
+ }
+
+ return strPage;
+ }
+
+ /**
+ * TruncateUrlPage: Get url params from url link
+ *
+ * @param strURL
+ * @return url params
+ */
+ private static String truncateUrlPage(String strURL) {
+ String strAllParam = null;
+ String[] arrSplit = null;
+
+ strURL = strURL.trim().toLowerCase(); // keep this in mind
+
+ arrSplit = strURL.split("[?]");
+ if (strURL.length() > 1) {
+ if (arrSplit.length > 1) {
+ if (arrSplit[1] != null) {
+ strAllParam = arrSplit[1];
+ }
+ }
+ }
+
+ return strAllParam;
+ }
+
+ /**
+ * URLRequest: Get url params from url link in a map format
+ *
+ * @param URL request url
+ * @return url params key value map
+ */
+ public static Map<String, String> uRLRequest(String URL) {
+ Map<String, String> mapRequest = new HashMap<String, String>();
+
+ String[] arrSplit = null;
+
+ String strUrlParam = truncateUrlPage(URL);
+ if (strUrlParam == null) {
+ return mapRequest;
+ }
+
+ arrSplit = strUrlParam.split("[&]");
+ for (String strSplit : arrSplit) {
+ String[] arrSplitEqual = null;
+ arrSplitEqual = strSplit.split("[=]");
+
+ if (arrSplitEqual.length > 1) {
+
+ mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
+
+ } else {
+ if (arrSplitEqual[0] != "") {
+
+ mapRequest.put(arrSplitEqual[0], "");
+ }
+ }
+ }
+ return mapRequest;
+ }
+
+ /**
+ * GetSearchInfo: Get search information from url link
+ *
+ * @param URL request url
+ * @return search params
+ * @throws UnsupportedEncodingException UnsupportedEncodingException
+ */
+ public String getSearchInfo(String URL) throws UnsupportedEncodingException {
+ List<String> info = new ArrayList<String>();
+ String keyword = "";
+ Map<String, String> mapRequest = RequestUrl.uRLRequest(URL);
+ if (mapRequest.get("search") != null) {
+ try {
+ keyword = mapRequest.get("search");
+
+ keyword = URLDecoder.decode(keyword.replaceAll("%(?![0-9a-fA-F]{2})", "%25"), "UTF-8");
+ if (keyword.contains("%2b") || keyword.contains("%20") || keyword.contains("%25")) {
+ keyword = keyword.replace("%2b", " ");
+ keyword = keyword.replace("%20", " ");
+ keyword = keyword.replace("%25", " ");
+ }
+
+ keyword = keyword.replaceAll("[-+^:,*_\"]", " ").replace("\\", " ").replaceAll("\\s+", " ").trim();
+
+ } catch (UnsupportedEncodingException e) {
+ LOG.error(mapRequest.get("search"));
+ e.printStackTrace();
+ }
+ if (!"".equals(keyword)) {
+ info.add(keyword);
+ }
+
+ }
+
+ if (mapRequest.get("ids") != null && mapRequest.get("values") != null) {
+ String id_raw = URLDecoder.decode(mapRequest.get("ids"), "UTF-8");
+ String value_raw = URLDecoder.decode(mapRequest.get("values"), "UTF-8");
+ String[] ids = id_raw.split(":");
+ String[] values = value_raw.split(":");
+
+ int a = ids.length;
+ int b = values.length;
+ int l = a < b ? a : b;
+
+ for (int i = 0; i < l; i++) {
+ if (ids[i].equals("collections") || ids[i].equals("measurement") || ids[i].equals("sensor") || ids[i].equals("platform") || ids[i].equals("variable") || ids[i].equals("spatialcoverage")) {
+ try {
+ values[i] = values[i].replaceAll("%(?![0-9a-fA-F]{2})", "%25");
+ if (!URLDecoder.decode(values[i], "UTF-8").equals(keyword) && !URLDecoder.decode(values[i], "UTF-8").equals("")) {
+ String item = URLDecoder.decode(values[i], "UTF-8").trim();
+ if (item.contains("%2b") || item.contains("%20") || item.contains("%25")) {
+ item = item.replace("%2b", " ");
+ item = item.replace("%20", " ");
+ item = item.replace("%25", " ");
+ }
+ item = item.replaceAll("[-+^:,*_\"]", " ").replace("\\", " ").replaceAll("\\s+", " ").trim();
+ info.add(item);
+ }
+ } catch (Exception e) {
+ LOG.error(values[i]);
+ e.printStackTrace();
+ }
+ }
+
+ }
+ }
+
+ return String.join(",", info);
+ }
+
+ /**
+ * GetSearchWord: Get search words from url link
+ *
+ * @param url request url
+ * @return query
+ */
+ public static String getSearchWord(String url) {
+ String keyword = "";
+
+ Map<String, String> mapRequest = RequestUrl.uRLRequest(url);
+ if (mapRequest.get("search") != null) {
+ try {
+ keyword = mapRequest.get("search");
+
+ keyword = URLDecoder.decode(keyword.replaceAll("%(?![0-9a-fA-F]{2})", "%25"), "UTF-8");
+ if (keyword.contains("%2b") || keyword.contains("%20") || keyword.contains("%25")) {
+ keyword = keyword.replace("%2b", " ");
+ keyword = keyword.replace("%20", " ");
+ keyword = keyword.replace("%25", " ");
+ }
+ keyword = keyword.replaceAll("[-+^:,*_\"]", " ").replace("\\", " ").replaceAll("\\s+", " ").trim();
+ } catch (UnsupportedEncodingException e) {
+ LOG.error(mapRequest.get("search"));
+ e.printStackTrace();
+ }
+ }
+
+ return keyword;
+ }
+
+ /**
+ * GetFilterInfo: Get filter params from url link
+ *
+ * @param url request url
+ * @return filter facet key pair map
+ * @throws UnsupportedEncodingException UnsupportedEncodingException
+ */
+ public static Map<String, String> getFilterInfo(String url) throws UnsupportedEncodingException {
+ List<String> info = new ArrayList<>();
+ Map<String, String> filterValues = new HashMap<>();
+
+ String keyword = "";
+ Map<String, String> mapRequest = RequestUrl.uRLRequest(url);
+ if (mapRequest.get("search") != null) {
+ try {
+ keyword = mapRequest.get("search");
+
+ keyword = URLDecoder.decode(keyword.replaceAll("%(?![0-9a-fA-F]{2})", "%25"), "UTF-8");
+ if (keyword.contains("%2b") || keyword.contains("%20") || keyword.contains("%25")) {
+ keyword = keyword.replace("%2b", " ");
+ keyword = keyword.replace("%20", " ");
+ keyword = keyword.replace("%25", " ");
+ }
+ keyword = keyword.replaceAll("[-+^:,*_\"]", " ").replace("\\", " ").replaceAll("\\s+", " ").trim();
+
+ } catch (UnsupportedEncodingException e) {
+ LOG.error(mapRequest.get("search"));
+ e.printStackTrace();
+ }
+ if (!"".equals(keyword)) {
+ info.add(keyword);
+ }
+
+ }
+
+ if (mapRequest.get("ids") != null && mapRequest.get("values") != null) {
+ String idRaw = URLDecoder.decode(mapRequest.get("ids"), "UTF-8");
+ String valueRaw = URLDecoder.decode(mapRequest.get("values"), "UTF-8");
+ String[] ids = idRaw.split(":");
+ String[] values = valueRaw.split(":");
+
+ int a = ids.length;
+ int b = values.length;
+ int l = a < b ? a : b;
+
+ for (int i = 0; i < l; i++) {
+ try {
+ values[i] = values[i].replaceAll("%(?![0-9a-fA-F]{2})", "%25");
+ if (!URLDecoder.decode(values[i], "UTF-8").equals(keyword) && !URLDecoder.decode(values[i], "UTF-8").equals("")) {
+ String item = URLDecoder.decode(values[i], "UTF-8").trim();
+ if (item.contains("%2b") || item.contains("%20") || item.contains("%25")) {
+ item = item.replace("%2b", " ");
+ item = item.replace("%20", " ");
+ item = item.replace("%25", " ");
+ }
+ item = item.replaceAll("[-+^:,*_\"]", " ").replace("\\", " ").replaceAll("\\s+", " ").trim();
+ filterValues.put(ids[i], item);
+ }
+ } catch (Exception e) {
+ LOG.error(values[i]);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ if (mapRequest.get("temporalsearch") != null) {
+ String temporalsearch = mapRequest.get("temporalsearch");
+ temporalsearch = URLDecoder.decode(temporalsearch.replaceAll("%(?![0-9a-fA-F]{2})", "%25"), "UTF-8");
+
+ filterValues.put("temporalsearch", temporalsearch);
+ }
+
+ return filterValues;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Session.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Session.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Session.java
new file mode 100644
index 0000000..93f4288
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Session.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.sort.SortOrder;
+import org.joda.time.Seconds;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * ClassName: Session Function: Session operations.
+ */
+public class Session /*extends MudrodAbstract*/ implements Comparable<Session> {
+ private static final Logger LOG = LoggerFactory.getLogger(Session.class);
+ // start: start time of session
+ private String start;
+ // end: end time of session
+ private String end;
+ // id: original session ID
+ private String id;
+ // newid: new session ID
+ private String newid = null;
+ // fmt: time formatter
+ private DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+
+ private ESDriver es;
+ private Properties props;
+
+ /**
+ * Creates a new instance of Session.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch drive
+ * @param start start time of session
+ * @param end end time of session
+ * @param id session ID
+ */
+ public Session(Properties props, ESDriver es, String start, String end, String id) {
+ this.start = start;
+ this.end = end;
+ this.id = id;
+
+ this.props = props;
+ this.es = es;
+ }
+
+ /**
+ * Creates a new instance of Session.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch drive
+ */
+ public Session(Properties props, ESDriver es) {
+ this.props = props;
+ this.es = es;
+ }
+
+ /**
+ * getID: Get original session ID
+ *
+ * @return session id
+ */
+ public String getID() {
+ return id;
+ }
+
+ /**
+ * getNewID: Get new session ID
+ *
+ * @return new session id
+ */
+ public String getNewID() {
+ return newid;
+ }
+
+ /**
+ * setNewID: Set new session ID
+ *
+ * @param str: session ID
+ * @return new session id
+ */
+ public String setNewID(String str) {
+ return newid = str;
+ }
+
+ /**
+ * getStartTime:Get start time of current session
+ *
+ * @return start time of session
+ */
+ public String getStartTime() {
+ return start;
+ }
+
+ /**
+ * getEndTime:Get end time of current session
+ *
+ * @return end time of session
+ */
+ public String getEndTime() {
+ return end;
+ }
+
+ /**
+ * Compare current session with another session
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(Session o) {
+ fmt.parseDateTime(this.end);
+ fmt.parseDateTime(o.end);
+ // ascending order
+ return Seconds.secondsBetween(fmt.parseDateTime(o.end), fmt.parseDateTime(this.end)).getSeconds();
+
+ }
+
+ /**
+ * getSessionDetail:Get detail of current session, which is used for session
+ * tree reconstruct
+ *
+ * @param indexName name of index from which you wish to obtain session detail.
+ * @param type: Session type name in Elasticsearch
+ * @param sessionID: Session ID
+ * @return Session details in Json format
+ */
+ public JsonObject getSessionDetail(String indexName, String type, String sessionID) {
+ JsonObject sessionResults = new JsonObject();
+ // for session tree
+ SessionTree tree = null;
+ JsonElement jsonRequest = null;
+ try {
+ tree = this.getSessionTree(indexName, type, sessionID);
+ JsonObject jsonTree = tree.treeToJson(tree.root);
+ sessionResults.add("treeData", jsonTree);
+
+ jsonRequest = this.getRequests(type, sessionID);
+ sessionResults.add("RequestList", jsonRequest);
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Encoding error detected.", e);
+
+ }
+
+ return sessionResults;
+ }
+
+ /**
+ * getClickStreamList: Extracted click stream list from current session.
+ *
+ * @param indexName an index from which to query for a session list
+ * @param type: Session type name in Elasticsearch
+ * @param sessionID: Session ID
+ * @return Click stram data list
+ * {@link ClickStream}
+ */
+ public List<ClickStream> getClickStreamList(String indexName, String type, String sessionID) {
+ SessionTree tree = null;
+ try {
+ tree = this.getSessionTree(indexName, type, sessionID);
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Erro whilst obtaining the Session Tree: {}", e);
+ }
+
+ List<ClickStream> clickthroughs = tree.getClickStreamList();
+ return clickthroughs;
+ }
+
+ /**
+ * Method of converting a given session to a tree structure
+ *
+ * @param type session type name in Elasticsearch
+ * @param sessionID ID of session
+ * @return an instance of session tree structure
+ * @throws UnsupportedEncodingException UnsupportedEncodingException
+ */
+ private SessionTree getSessionTree(String indexName, String type, String sessionID) throws UnsupportedEncodingException {
+
+ SearchResponse response = es.getClient().prepareSearch(indexName).setTypes(type).setQuery(QueryBuilders.termQuery("SessionID", sessionID)).setSize(100).addSort("Time", SortOrder.ASC)
+ .execute().actionGet();
+
+ SessionTree tree = new SessionTree(this.props, this.es, sessionID, type);
+ int seq = 1;
+ for (SearchHit hit : response.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String request = (String) result.get("Request");
+ String time = (String) result.get("Time");
+ String logType = (String) result.get("LogType");
+ String referer = (String) result.get("Referer");
+
+ SessionNode node = new SessionNode(request, logType, referer, time, seq);
+ tree.insert(node);
+ seq++;
+ }
+
+ return tree;
+ }
+
+ /**
+ * Method of getting all requests from a given current session
+ *
+ * @param cleanuptype Session type name in Elasticsearch
+ * @param sessionID Session ID
+ * @return all of these requests in JSON
+ * @throws UnsupportedEncodingException UnsupportedEncodingException
+ */
+ private JsonElement getRequests(String cleanuptype, String sessionID) throws UnsupportedEncodingException {
+ SearchResponse response = es.getClient().prepareSearch(props.getProperty("indexName")).setTypes(cleanuptype).setQuery(QueryBuilders.termQuery("SessionID", sessionID)).setSize(100)
+ .addSort("Time", SortOrder.ASC).execute().actionGet();
+
+ Gson gson = new Gson();
+ List<JsonObject> requestList = new ArrayList<>();
+ int seq = 1;
+ for (SearchHit hit : response.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String request = (String) result.get("Request");
+ String requestUrl = (String) result.get("RequestUrl");
+ String time = (String) result.get("Time");
+ String logType = (String) result.get("LogType");
+ String referer = (String) result.get("Referer");
+
+ JsonObject req = new JsonObject();
+ req.addProperty("Time", time);
+ req.addProperty("Request", request);
+ req.addProperty("RequestURL", requestUrl);
+ req.addProperty("LogType", logType);
+ req.addProperty("Referer", referer);
+ req.addProperty("Seq", seq);
+ requestList.add(req);
+
+ seq++;
+ }
+ return gson.toJsonTree(requestList);
+ }
+
+ /**
+ * getClickStreamList: Extracted ranking training data from current session.
+ *
+ * @param indexName an index from which to obtain ranked training data.
+ * @param cleanuptype: Session type name in Elasticsearch
+ * @param sessionID: Session ID
+ * @return Click stram data list
+ * {@link ClickStream}
+ */
+ public List<RankingTrainData> getRankingTrainData(String indexName, String cleanuptype, String sessionID) {
+ SessionTree tree = null;
+ try {
+ tree = this.getSessionTree(indexName, cleanuptype, sessionID);
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Error whilst retreiving Session Tree: {}", e);
+ }
+
+ List<RankingTrainData> trainData = new ArrayList<>();
+ try {
+ trainData = tree.getRankingTrainData(indexName, sessionID);
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Error whilst retreiving ranking training data: {}", e);
+ }
+
+ return trainData;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionExtractor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionExtractor.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionExtractor.java
new file mode 100644
index 0000000..edba32e
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionExtractor.java
@@ -0,0 +1,532 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.api.java.Optional;
+import org.apache.spark.api.java.function.FlatMapFunction;
+import org.apache.spark.api.java.function.Function;
+import org.apache.spark.api.java.function.Function2;
+import org.apache.spark.api.java.function.PairFunction;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import scala.Tuple2;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * ClassName: SessionExtractor Function: Extract sessions details from
+ * reconstructed sessions.
+ */
+public class SessionExtractor implements Serializable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SessionExtractor.class);
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public SessionExtractor() {
+ // default constructor
+ }
+
+ /**
+ * extractClickStreamFromES:Extract click streams from logs stored in
+ * Elasticsearch
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch drive
+ * @param spark
+ * the spark driver
+ * @return clickstream list in JavaRDD format {@link ClickStream}
+ */
+ public JavaRDD<ClickStream> extractClickStreamFromES(Properties props, ESDriver es, SparkDriver spark) {
+ switch (props.getProperty(MudrodConstants.PROCESS_TYPE)) {
+ case "sequential":
+ List<ClickStream> queryList = this.getClickStreamList(props, es);
+ return spark.sc.parallelize(queryList);
+ case "parallel":
+ return getClickStreamListInParallel(props, spark, es);
+ default:
+ LOG.error("Error finding processing type for '{}'. Please check your config.xml.", props.getProperty(MudrodConstants.PROCESS_TYPE));
+ }
+ return null;
+ }
+
+ /**
+ * getClickStreamList:Extract click streams from logs stored in Elasticsearch.
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch driver
+ * @return clickstream list {@link ClickStream}
+ */
+ protected List<ClickStream> getClickStreamList(Properties props, ESDriver es) {
+ List<String> logIndexList = es.getIndexListWithPrefix(props.getProperty(MudrodConstants.LOG_INDEX));
+
+ List<ClickStream> result = new ArrayList<>();
+ for (int n = 0; n < logIndexList.size(); n++) {
+ String logIndex = logIndexList.get(n);
+ List<String> sessionIdList;
+ try {
+ sessionIdList = this.getSessions(props, es, logIndex);
+ Session session = new Session(props, es);
+ int sessionNum = sessionIdList.size();
+ for (int i = 0; i < sessionNum; i++) {
+ String[] sArr = sessionIdList.get(i).split(",");
+ List<ClickStream> datas = session.getClickStreamList(sArr[1], sArr[2], sArr[0]);
+ result.addAll(datas);
+ }
+ } catch (Exception e) {
+ LOG.error("Error during extraction of Clickstreams from log index. {}", e);
+ }
+ }
+
+ return result;
+ }
+
+ protected JavaRDD<ClickStream> getClickStreamListInParallel(Properties props, SparkDriver spark, ESDriver es) {
+
+ List<String> logIndexList = es.getIndexListWithPrefix(props.getProperty(MudrodConstants.LOG_INDEX));
+
+ LOG.info("Retrieved {}", logIndexList.toString());
+
+ List<String> sessionIdList = new ArrayList<>();
+ for (int n = 0; n < logIndexList.size(); n++) {
+ String logIndex = logIndexList.get(n);
+ List<String> tmpsessionList = this.getSessions(props, es, logIndex);
+ sessionIdList.addAll(tmpsessionList);
+ }
+
+ JavaRDD<String> sessionRDD = spark.sc.parallelize(sessionIdList, 16);
+
+ JavaRDD<ClickStream> clickStreamRDD = sessionRDD.mapPartitions(new FlatMapFunction<Iterator<String>, ClickStream>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Iterator<ClickStream> call(Iterator<String> arg0) throws Exception {
+ ESDriver tmpES = new ESDriver(props);
+ tmpES.createBulkProcessor();
+
+ Session session = new Session(props, tmpES);
+ List<ClickStream> clickstreams = new ArrayList<>();
+ while (arg0.hasNext()) {
+ String s = arg0.next();
+ String[] sArr = s.split(",");
+ List<ClickStream> clicks = session.getClickStreamList(sArr[1], sArr[2], sArr[0]);
+ clickstreams.addAll(clicks);
+ }
+ tmpES.destroyBulkProcessor();
+ tmpES.close();
+ return clickstreams.iterator();
+ }
+ });
+
+ LOG.info("Clickstream number: {}", clickStreamRDD.count());
+
+ return clickStreamRDD;
+ }
+
+ // This function is reserved and not being used for now
+
+ /**
+ * loadClickStremFromTxt:Load click stream form txt file
+ *
+ * @param clickthroughFile
+ * txt file
+ * @param sc
+ * the spark context
+ * @return clickstream list in JavaRDD format {@link ClickStream}
+ */
+ public JavaRDD<ClickStream> loadClickStremFromTxt(String clickthroughFile, JavaSparkContext sc) {
+ return sc.textFile(clickthroughFile).flatMap(new FlatMapFunction<String, ClickStream>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Iterator<ClickStream> call(String line) throws Exception {
+ List<ClickStream> clickthroughs = (List<ClickStream>) ClickStream.parseFromTextLine(line);
+ return (Iterator<ClickStream>) clickthroughs;
+ }
+ });
+ }
+
+ /**
+ * bulidDataQueryRDD: convert click stream list to data set queries pairs.
+ *
+ * @param clickstreamRDD:
+ * click stream data
+ * @param downloadWeight:
+ * weight of download behavior
+ * @return JavaPairRDD, key is short name of data set, and values are queries
+ */
+ public JavaPairRDD<String, List<String>> bulidDataQueryRDD(JavaRDD<ClickStream> clickstreamRDD, int downloadWeight) {
+ return clickstreamRDD.mapToPair(new PairFunction<ClickStream, String, List<String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, List<String>> call(ClickStream click) throws Exception {
+ List<String> query = new ArrayList<>();
+ // important! download behavior is given higher weights
+ // than viewing
+ // behavior
+ boolean download = click.isDownload();
+ int weight = 1;
+ if (download) {
+ weight = downloadWeight;
+ }
+ for (int i = 0; i < weight; i++) {
+ query.add(click.getKeyWords());
+ }
+
+ return new Tuple2<>(click.getViewDataset(), query);
+ }
+ }).reduceByKey(new Function2<List<String>, List<String>, List<String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public List<String> call(List<String> v1, List<String> v2) throws Exception {
+ List<String> list = new ArrayList<>();
+ list.addAll(v1);
+ list.addAll(v2);
+ return list;
+ }
+ });
+ }
+
+ /**
+ * getSessions: Get sessions from logs
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch driver
+ * @param logIndex
+ * a log index name
+ * @return list of session names
+ */
+ protected List<String> getSessions(Properties props, ESDriver es, String logIndex) {
+
+ String cleanupPrefix = props.getProperty(MudrodConstants.CLEANUP_TYPE_PREFIX);
+ String sessionStatPrefix = props.getProperty(MudrodConstants.SESSION_STATS_PREFIX);
+
+ List<String> sessions = new ArrayList<>();
+ SearchResponse scrollResp = es.getClient().prepareSearch(logIndex).setTypes(sessionStatPrefix).setScroll(new TimeValue(60000)).setQuery(QueryBuilders.matchAllQuery()).setSize(100).execute()
+ .actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> session = hit.getSource();
+ String sessionID = (String) session.get("SessionID");
+ sessions.add(sessionID + "," + logIndex + "," + cleanupPrefix);
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ return sessions;
+ }
+
+ public JavaPairRDD<String, Double> bulidUserItermRDD(JavaRDD<ClickStream> clickstreamRDD) {
+ return clickstreamRDD.mapToPair(new PairFunction<ClickStream, String, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Double> call(ClickStream click) throws Exception {
+ double rate = 1;
+ boolean download = click.isDownload();
+ if (download) {
+ rate = 2;
+ }
+
+ String sessionID = click.getSessionID();
+ String user = sessionID.split("@")[0];
+
+ return new Tuple2<>(user + "," + click.getViewDataset(), rate);
+ }
+ }).reduceByKey(new Function2<Double, Double, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Double call(Double v1, Double v2) throws Exception {
+ return v1 >= v2 ? v1 : v2;
+
+ }
+ });
+ }
+
+ public JavaPairRDD<String, Double> bulidSessionItermRDD(JavaRDD<ClickStream> clickstreamRDD) {
+ JavaPairRDD<String, String> sessionItemRDD = clickstreamRDD.mapToPair(new PairFunction<ClickStream, String, String>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, String> call(ClickStream click) throws Exception {
+
+ String sessionID = click.getSessionID();
+ return new Tuple2<>(sessionID, click.getViewDataset());
+ }
+ }).distinct();
+
+ // remove some sessions
+ JavaPairRDD<String, Double> sessionItemNumRDD = sessionItemRDD.keys().mapToPair(new PairFunction<String, String, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Double> call(String item) throws Exception {
+ return new Tuple2<>(item, 1.0);
+ }
+ }).reduceByKey(new Function2<Double, Double, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Double call(Double v1, Double v2) throws Exception {
+ return v1 + v2;
+ }
+ }).filter(new Function<Tuple2<String, Double>, Boolean>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Boolean call(Tuple2<String, Double> arg0) throws Exception {
+ Boolean b = true;
+ if (arg0._2 < 2) {
+ b = false;
+ }
+ return b;
+ }
+ });
+
+ return sessionItemNumRDD.leftOuterJoin(sessionItemRDD).mapToPair(new PairFunction<Tuple2<String, Tuple2<Double, Optional<String>>>, String, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Double> call(Tuple2<String, Tuple2<Double, Optional<String>>> arg0) throws Exception {
+
+ Tuple2<Double, Optional<String>> test = arg0._2;
+ Optional<String> optStr = test._2;
+ String item = "";
+ if (optStr.isPresent()) {
+ item = optStr.get();
+ }
+ return new Tuple2<>(arg0._1 + "," + item, 1.0);
+ }
+
+ });
+ }
+
+ public JavaPairRDD<String, List<String>> bulidSessionDatasetRDD(Properties props, ESDriver es, SparkDriver spark) {
+
+ List<String> result = new ArrayList<>();
+ List<String> logIndexList = es.getIndexListWithPrefix(props.getProperty(MudrodConstants.LOG_INDEX));
+ for (int n = 0; n < logIndexList.size(); n++) {
+ String logIndex = logIndexList.get(n);
+ SearchResponse scrollResp = es.getClient().prepareSearch(logIndex).setTypes(props.getProperty(MudrodConstants.SESSION_STATS_PREFIX)).setScroll(new TimeValue(60000)).setQuery(QueryBuilders.matchAllQuery())
+ .setSize(100).execute().actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> session = hit.getSource();
+ String sessionID = (String) session.get("SessionID");
+ String views = (String) session.get("views");
+ if (views != null && !"".equals(views)) {
+ String sessionItems = sessionID + ":" + views;
+ result.add(sessionItems);
+ }
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+ }
+
+ JavaRDD<String> sessionRDD = spark.sc.parallelize(result);
+
+ return sessionRDD.mapToPair(new PairFunction<String, String, List<String>>() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, List<String>> call(String sessionitem) throws Exception {
+ String[] splits = sessionitem.split(":");
+ String sessionId = splits[0];
+ List<String> itemList = new ArrayList<>();
+
+ String items = splits[1];
+ String[] itemArr = items.split(",");
+ int size = itemArr.length;
+ for (int i = 0; i < size; i++) {
+ String item = itemArr[i];
+ if (!itemList.contains(item))
+ itemList.add(itemArr[i]);
+ }
+
+ return new Tuple2<>(sessionId, itemList);
+ }
+ });
+ }
+
+ /**
+ * extractClickStreamFromES:Extract click streams from logs stored in
+ * Elasticsearch
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch drive
+ * @param spark
+ * the spark driver
+ * @return clickstream list in JavaRDD format {@link ClickStream}
+ */
+ public JavaRDD<RankingTrainData> extractRankingTrainData(Properties props, ESDriver es, SparkDriver spark) {
+
+ List<RankingTrainData> queryList = this.extractRankingTrainData(props, es);
+ return spark.sc.parallelize(queryList);
+
+ }
+
+ /**
+ * getClickStreamList:Extract click streams from logs stored in Elasticsearch.
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch driver
+ * @return clickstream list {@link ClickStream}
+ */
+ protected List<RankingTrainData> extractRankingTrainData(Properties props, ESDriver es) {
+ List<String> logIndexList = es.getIndexListWithPrefix(props.getProperty(MudrodConstants.LOG_INDEX));
+
+ LOG.info(logIndexList.toString());
+
+ List<RankingTrainData> result = new ArrayList<>();
+ for (int n = 0; n < logIndexList.size(); n++) {
+ String logIndex = logIndexList.get(n);
+ List<String> sessionIdList;
+ try {
+ sessionIdList = this.getSessions(props, es, logIndex);
+ Session session = new Session(props, es);
+ int sessionNum = sessionIdList.size();
+ for (int i = 0; i < sessionNum; i++) {
+ String[] sArr = sessionIdList.get(i).split(",");
+ List<RankingTrainData> datas = session.getRankingTrainData(sArr[1], sArr[2], sArr[0]);
+ result.addAll(datas);
+ }
+ } catch (Exception e) {
+ LOG.error("Error which extracting ranking train data: {}", e);
+ }
+ }
+
+ return result;
+ }
+
+ protected JavaRDD<RankingTrainData> extractRankingTrainDataInParallel(Properties props, SparkDriver spark, ESDriver es) {
+
+ List<String> logIndexList = es.getIndexListWithPrefix(props.getProperty(MudrodConstants.LOG_INDEX));
+
+ LOG.info(logIndexList.toString());
+
+ List<String> sessionIdList = new ArrayList<>();
+ for (int n = 0; n < logIndexList.size(); n++) {
+ String logIndex = logIndexList.get(n);
+ List<String> tmpsessionList = this.getSessions(props, es, logIndex);
+ sessionIdList.addAll(tmpsessionList);
+ }
+
+ JavaRDD<String> sessionRDD = spark.sc.parallelize(sessionIdList, 16);
+
+ JavaRDD<RankingTrainData> clickStreamRDD = sessionRDD.mapPartitions(new FlatMapFunction<Iterator<String>, RankingTrainData>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Iterator<RankingTrainData> call(Iterator<String> arg0) throws Exception {
+ ESDriver tmpES = new ESDriver(props);
+ tmpES.createBulkProcessor();
+
+ Session session = new Session(props, tmpES);
+ List<RankingTrainData> clickstreams = new ArrayList<>();
+ while (arg0.hasNext()) {
+ String s = arg0.next();
+ String[] sArr = s.split(",");
+ List<RankingTrainData> clicks = session.getRankingTrainData(sArr[1], sArr[2], sArr[0]);
+ clickstreams.addAll(clicks);
+ }
+ tmpES.destroyBulkProcessor();
+ tmpES.close();
+ return clickstreams.iterator();
+ }
+ });
+
+ LOG.info("Clickstream number: {}", clickStreamRDD.count());
+
+ return clickStreamRDD;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionNode.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionNode.java
new file mode 100644
index 0000000..958e184
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionNode.java
@@ -0,0 +1,344 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * ClassName: SessionNode Function: Functions related to a node in a session
+ * tree sturcture.
+ */
+public class SessionNode {
+ // id: Node ID
+ protected String id;
+ // value: Node value
+ protected String value;
+ // parent: Parent node of this node
+ protected SessionNode parent;
+ // children: Child nodes of this node
+ protected List<SessionNode> children = new ArrayList<>();
+ // time: request time of node
+ protected String time;
+ // request: request url of this node
+ protected String request;
+ // referer: previous request url of this node
+ protected String referer;
+ // seq: sequence of this node
+ protected int seq;
+ // key: type of this node extracted from url, including three types -
+ // dataset,datasetlist,ftp
+ protected String key;
+ // logType: log types of this node, including two types - po.dacc, ftp
+ protected String logType;
+ // search: query extracted from this node
+ protected String search;
+ // filter: filter facets extracted from this node
+ protected Map<String, String> filter;
+ // datasetId: viewed/downloaded data set ID
+ protected String datasetId;
+
+ public SessionNode() {
+
+ }
+
+ /**
+ * Creates a new instance of SessionNode.
+ *
+ * @param request: request url
+ * @param logType: including two types - po.dacc, ftp
+ * @param referer: previous request url
+ * @param time: request time of node
+ * @param seq: sequence of this node
+ */
+ public SessionNode(String request, String logType, String referer, String time, int seq) {
+ this.logType = logType;
+ this.time = time;
+ this.seq = seq;
+ this.setRequest(request);
+ this.setReferer(referer);
+ this.setKey(request, logType);
+ }
+
+ /**
+ * setReferer: Set previous request url of this node
+ *
+ * @param referer previous request url
+ */
+ public void setReferer(String referer) {
+ if (referer == null) {
+ this.referer = "";
+ return;
+ }
+ this.referer = referer.toLowerCase().replace("http://podaac.jpl.nasa.gov", "");
+ }
+
+ /**
+ * setRequest: Set request url of this node
+ *
+ * @param req request url
+ */
+ public void setRequest(String req) {
+ this.request = req;
+ if (this.logType.equals("PO.DAAC")) {
+ this.parseRequest(req);
+ }
+ }
+
+ /**
+ * getChildren:Get child nodes of this node
+ *
+ * @return child nodes
+ */
+ public List<SessionNode> getChildren() {
+ return this.children;
+ }
+
+ /**
+ * setChildren: Set child nodes of this node
+ *
+ * @param children child nodes of this node
+ */
+ public void setChildren(List<SessionNode> children) {
+ this.children = children;
+ }
+
+ /**
+ * addChildren: Add a children node
+ *
+ * @param node session node
+ */
+ public void addChildren(SessionNode node) {
+ this.children.add(node);
+ }
+
+ /**
+ * getId:Get node ID
+ *
+ * @return node ID of this node
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * bSame:Compare this node with another node
+ *
+ * @param node {@link SessionNode}
+ * @return boolean value, true mean the two nodes are same
+ */
+ public Boolean bSame(SessionNode node) {
+ Boolean bsame = false;
+ if (this.request.equals(node.request)) {
+ bsame = true;
+ }
+ return bsame;
+ }
+
+ /**
+ * setKey:Set request type which contains three categories -
+ * dataset,datasetlist,ftp
+ *
+ * @param request request url
+ * @param logType url type
+ */
+ public void setKey(String request, String logType) {
+ this.key = "";
+ String datasetlist = "/datasetlist?";
+ String dataset = "/dataset/";
+ if (logType.equals("ftp")) {
+ this.key = "ftp";
+ } else if (logType.equals("root")) {
+ this.key = "root";
+ } else {
+ if (request.contains(datasetlist)) {
+ this.key = "datasetlist";
+ } else if (request.contains(dataset) /* || request.contains(granule) */) {
+ this.key = "dataset";
+ }
+ }
+ }
+
+ /**
+ * getKey:Get request type which contains three categories -
+ * dataset,datasetlist,ftp
+ *
+ * @return request url type of this node
+ */
+ public String getKey() {
+ return this.key;
+ }
+
+ /**
+ * getRequest:Get node request
+ *
+ * @return request url of this node
+ */
+ public String getRequest() {
+ return this.request;
+ }
+
+ /**
+ * getReferer:Get previous request url of this node
+ *
+ * @return previous request url of this node
+ */
+ public String getReferer() {
+ return this.referer;
+ }
+
+ /**
+ * getParent:Get parent node of this node
+ *
+ * @return parent node of this node
+ */
+ public SessionNode getParent() {
+ return this.parent;
+ }
+
+ /**
+ * setParent: Set parent node of this node
+ *
+ * @param parent the previous request node of this node
+ */
+ public void setParent(SessionNode parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * getSearch:Get query of this node
+ *
+ * @return search query of this node
+ */
+ public String getSearch() {
+ return this.search;
+ }
+
+ /**
+ * getFilter:Get filter facets of this node
+ *
+ * @return filter values of this node
+ */
+ public Map<String, String> getFilter() {
+ return this.filter;
+ }
+
+ /**
+ * getDatasetId:Get data set ID of this node
+ *
+ * @return viewing/downloading data set of this node
+ */
+ public String getDatasetId() {
+ return this.datasetId;
+ }
+
+ /**
+ * getSeq:Get sequence of this node
+ *
+ * @return request sequence of this node
+ */
+ public int getSeq() {
+ return this.seq;
+ }
+
+ /**
+ * getFilterStr:Get filter facets of this node
+ *
+ * @return filters values of this node
+ */
+ public String getFilterStr() {
+ String filter = "";
+ if (this.filter.size() > 0) {
+ Iterator iter = this.filter.keySet().iterator();
+ while (iter.hasNext()) {
+ String key = (String) iter.next();
+ String val = this.filter.get(key);
+ filter += key + "=" + val + ",";
+ }
+
+ filter = filter.substring(0, filter.length() - 1);
+ }
+
+ return filter;
+ }
+
+ /**
+ * parseRequest:Parse request to extract request type
+ *
+ * @param request request url of this node
+ */
+ public void parseRequest(String request) {
+ Pattern pattern = Pattern.compile("get (.*?) http/*");
+ Matcher matcher = pattern.matcher(request.trim().toLowerCase());
+ while (matcher.find()) {
+ request = matcher.group(1);
+ }
+ if (request.contains("/dataset/")) {
+ this.parseDatasetId(request);
+ }
+
+ this.request = request.toLowerCase();
+ }
+
+ /**
+ * parseFilterParams:Parse filter facets information
+ *
+ * @param params filter key value pairs of this node
+ */
+ private void parseFilterParams(Map<String, String> params) {
+ this.filter = new HashMap<String, String>();
+ if (params.containsKey("ids")) {
+ String idsStr = params.get("ids");
+ if (!idsStr.equals("")) {
+ idsStr = URLDecoder.decode(idsStr);
+ String[] ids = idsStr.split(":");
+ String valueStr = params.get("values");
+ if (valueStr != null) {
+ valueStr = URLDecoder.decode(valueStr);
+ String[] values = valueStr.split(":");
+ int size = ids.length;
+ for (int i = 0; i < size; i++) {
+ this.filter.put(ids[i], values[i]);
+ }
+ }
+ }
+ }
+
+ if (!this.search.equals("")) {
+ this.filter.put("search", this.search);
+ }
+ }
+
+ /**
+ * parseDatasetId:Parse Request to extract data set ID
+ *
+ * @param request request url
+ */
+ public void parseDatasetId(String request) {
+ try {
+ request = URLDecoder.decode(request, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ String[] twoparts = request.split("[?]");
+ String[] parts = twoparts[0].split("/");
+ if (parts.length <= 2) {
+ return;
+ }
+ this.datasetId = parts[2];
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionTree.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionTree.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionTree.java
new file mode 100644
index 0000000..46c8d0c
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/SessionTree.java
@@ -0,0 +1,521 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * ClassName: SessionTree Function: Convert request list in a session to a tree
+ */
+public class SessionTree extends MudrodAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(SessionTree.class);
+ // size: node numbers in the session tree
+ public int size = 0;
+ // root: root node of session tree
+ protected SessionNode root = null;
+ // binsert: indicates inserting a node or not
+ public boolean binsert = false;
+ // tmpnode: tempt node
+ public SessionNode tmpnode;
+ // latestDatasetnode: the latest inserted node whose key is "dataset"
+ public SessionNode latestDatasetnode;
+ // sessionID: session ID
+ private String sessionID;
+ // cleanupType: session type in Elasticsearch
+ private String cleanupType;
+
+ /**
+ * Creates a new instance of SessionTree.
+ *
+ * @param props: the Mudrod configuration
+ * @param es: the Elasticsearch drive
+ * @param rootData: root node of the tree
+ * @param sessionID: session ID
+ * @param cleanupType: session type
+ */
+ public SessionTree(Properties props, ESDriver es, SessionNode rootData, String sessionID, String cleanupType) {
+ super(props, es, null);
+ root = new SessionNode("root", "root", "", "", 0);
+ tmpnode = root;
+ this.sessionID = sessionID;
+ this.cleanupType = cleanupType;
+ }
+
+ /**
+ * Creates a new instance of SessionTree.
+ *
+ * @param props: the Mudrod configuration
+ * @param es: the Elasticsearch drive
+ * @param sessionID: session ID
+ * @param cleanupType: session type
+ */
+ public SessionTree(Properties props, ESDriver es, String sessionID, String cleanupType) {
+ super(props, es, null);
+ root = new SessionNode("root", "root", "", "", 0);
+ root.setParent(root);
+ tmpnode = root;
+ this.sessionID = sessionID;
+ this.cleanupType = cleanupType;
+ }
+
+ /**
+ * insert: insert a node into the session tree.
+ *
+ * @param node {@link SessionNode}
+ * @return session node
+ */
+ public SessionNode insert(SessionNode node) {
+ // begin with datasetlist
+ if (node.getKey().equals("datasetlist")) {
+ this.binsert = true;
+ }
+ if (!this.binsert) {
+ return null;
+ }
+ // remove unrelated node
+ if (!node.getKey().equals("datasetlist") && !node.getKey().equals("dataset") && !node.getKey().equals("ftp")) {
+ return null;
+ }
+ // remove dumplicated click
+ if (node.getRequest().equals(tmpnode.getRequest())) {
+ return null;
+ }
+ // search insert node
+ SessionNode parentnode = this.searchParentNode(node);
+ if (parentnode == null) {
+ return null;
+ }
+ node.setParent(parentnode);
+ parentnode.addChildren(node);
+
+ // record insert node
+ tmpnode = node;
+ if ("dataset".equals(node.getKey())) {
+ latestDatasetnode = node;
+ }
+
+ size++;
+ return node;
+ }
+
+ /**
+ * printTree: Print session tree
+ *
+ * @param node root node of the session tree
+ */
+ public void printTree(SessionNode node) {
+ LOG.info("node: {} \n", node.getRequest());
+ if (node.children.isEmpty()) {
+ for (int i = 0; i < node.children.size(); i++) {
+ printTree(node.children.get(i));
+ }
+ }
+ }
+
+ /**
+ * TreeToJson: Convert the session tree to Json object
+ *
+ * @param node node of the session tree
+ * @return tree content in Json format
+ */
+ public JsonObject treeToJson(SessionNode node) {
+ Gson gson = new Gson();
+ JsonObject json = new JsonObject();
+
+ json.addProperty("seq", node.getSeq());
+ if ("datasetlist".equals(node.getKey())) {
+ json.addProperty("icon", "./resources/images/searching.png");
+ json.addProperty("name", node.getRequest());
+ } else if ("dataset".equals(node.getKey())) {
+ json.addProperty("icon", "./resources/images/viewing.png");
+ json.addProperty("name", node.getDatasetId());
+ } else if ("ftp".equals(node.getKey())) {
+ json.addProperty("icon", "./resources/images/downloading.png");
+ json.addProperty("name", node.getRequest());
+ } else if ("root".equals(node.getKey())) {
+ json.addProperty("name", "");
+ json.addProperty("icon", "./resources/images/users.png");
+ }
+
+ if (!node.children.isEmpty()) {
+ List<JsonObject> jsonChildren = new ArrayList<>();
+ for (int i = 0; i < node.children.size(); i++) {
+ JsonObject jsonChild = treeToJson(node.children.get(i));
+ jsonChildren.add(jsonChild);
+ }
+ JsonElement jsonElement = gson.toJsonTree(jsonChildren);
+ json.add("children", jsonElement);
+ }
+
+ return json;
+ }
+
+ /**
+ * getClickStreamList: Get click stream list in the session
+ *
+ * @return {@link ClickStream}
+ */
+ public List<ClickStream> getClickStreamList() {
+
+ List<ClickStream> clickthroughs = new ArrayList<>();
+ List<SessionNode> viewnodes = this.getViewNodes(this.root);
+ for (int i = 0; i < viewnodes.size(); i++) {
+
+ SessionNode viewnode = viewnodes.get(i);
+ SessionNode parent = viewnode.getParent();
+ List<SessionNode> children = viewnode.getChildren();
+
+ if (!"datasetlist".equals(parent.getKey())) {
+ continue;
+ }
+
+ RequestUrl requestURL = new RequestUrl();
+ String viewquery = "";
+ try {
+ String infoStr = requestURL.getSearchInfo(viewnode.getRequest());
+ viewquery = es.customAnalyzing(props.getProperty("indexName"), infoStr);
+ } catch (UnsupportedEncodingException | InterruptedException | ExecutionException e) {
+ LOG.warn("Exception getting search info. Ignoring...", e);
+ }
+
+ String dataset = viewnode.getDatasetId();
+ boolean download = false;
+ for (int j = 0; j < children.size(); j++) {
+ SessionNode child = children.get(j);
+ if ("ftp".equals(child.getKey())) {
+ download = true;
+ break;
+ }
+ }
+
+ if (viewquery != null && !"".equals(viewquery)) {
+ String[] queries = viewquery.trim().split(",");
+ if (queries.length > 0) {
+ for (int k = 0; k < queries.length; k++) {
+ ClickStream data = new ClickStream(queries[k], dataset, download);
+ data.setSessionId(this.sessionID);
+ data.setType(this.cleanupType);
+ clickthroughs.add(data);
+ }
+ }
+ }
+ }
+
+ return clickthroughs;
+ }
+
+ /**
+ * searchParentNode:Get parent node of a session node
+ *
+ * @param node {@link SessionNode}
+ * @return node {@link SessionNode}
+ */
+ private SessionNode searchParentNode(SessionNode node) {
+
+ String nodeKey = node.getKey();
+
+ if ("datasetlist".equals(nodeKey)) {
+ if ("-".equals(node.getReferer())) {
+ return root;
+ } else {
+ SessionNode tmp = this.findLatestRefer(tmpnode, node.getReferer());
+ if (tmp == null) {
+ return root;
+ } else {
+ return tmp;
+ }
+ }
+ } else if ("dataset".equals(nodeKey)) {
+ if ("-".equals(node.getReferer())) {
+ return null;
+ } else {
+ return this.findLatestRefer(tmpnode, node.getReferer());
+ }
+ } else if ("ftp".equals(nodeKey)) {
+ return latestDatasetnode;
+ }
+
+ return tmpnode;
+ }
+
+ /**
+ * findLatestRefer: Find parent node whose visiting url is equal to the refer
+ * url of a session node
+ *
+ * @param node: {@link SessionNode}
+ * @param refer: request url
+ * @return
+ */
+ private SessionNode findLatestRefer(SessionNode node, String refer) {
+ while (true) {
+ if ("root".equals(node.getKey())) {
+ return null;
+ }
+ SessionNode parentNode = node.getParent();
+ if (refer.equals(parentNode.getRequest())) {
+ return parentNode;
+ }
+
+ SessionNode tmp = this.iterChild(parentNode, refer);
+ if (tmp == null) {
+ node = parentNode;
+ continue;
+ } else {
+ return tmp;
+ }
+ }
+ }
+
+ /**
+ * iterChild:
+ *
+ * @param start
+ * @param refer
+ * @return
+ */
+ private SessionNode iterChild(SessionNode start, String refer) {
+ List<SessionNode> children = start.getChildren();
+ for (int i = children.size() - 1; i >= 0; i--) {
+ SessionNode tmp = children.get(i);
+ if (tmp.getChildren().isEmpty()) {
+ if (refer.equals(tmp.getRequest())) {
+ return tmp;
+ } else {
+ continue;
+ }
+ } else {
+ iterChild(tmp, refer);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * check:
+ *
+ * @param children
+ * @param str
+ * @return
+ */
+ private boolean check(List<SessionNode> children, String str) {
+ for (int i = 0; i < children.size(); i++) {
+ if (children.get(i).key.equals(str)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * insertHelperChildren:
+ *
+ * @param entry
+ * @param children
+ * @return
+ */
+ private boolean insertHelperChildren(SessionNode entry, List<SessionNode> children) {
+ for (int i = 0; i < children.size(); i++) {
+ boolean result = insertHelper(entry, children.get(i));
+ if (result) {
+ return result;
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * insertHelper:
+ *
+ * @param entry
+ * @param node
+ * @return
+ */
+ private boolean insertHelper(SessionNode entry, SessionNode node) {
+ if ("datasetlist".equals(entry.key) || "dataset".equals(entry.key)) {
+ if ("datasetlist".equals(node.key)) {
+ if (node.children.isEmpty()) {
+ node.children.add(entry);
+ return true;
+ } else {
+ boolean flag = check(node.children, "datasetlist");
+ if (!flag) {
+ node.children.add(entry);
+ return true;
+ } else {
+ insertHelperChildren(entry, node.children);
+ }
+ }
+ } else {
+ insertHelperChildren(entry, node.children);
+ }
+ } else if ("ftp".equals(entry.key)) {
+ if ("dataset".equals(node.key)) {
+ if (node.children.isEmpty()) {
+ node.children.add(entry);
+ return true;
+ } else {
+ boolean flag = check(node.children, "dataset");
+ if (!flag) {
+ node.children.add(entry);
+ return true;
+ } else {
+ insertHelperChildren(entry, node.children);
+ }
+ }
+ } else {
+ insertHelperChildren(entry, node.children);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * getViewNodes: Get a session node's child nodes whose key is "dataset".
+ *
+ * @param node
+ * @return a list of session node
+ */
+ private List<SessionNode> getViewNodes(SessionNode node) {
+
+ List<SessionNode> viewnodes = new ArrayList<>();
+ if ("dataset".equals(node.getKey())) {
+ viewnodes.add(node);
+ }
+
+ if (!node.children.isEmpty()) {
+ for (int i = 0; i < node.children.size(); i++) {
+ SessionNode childNode = node.children.get(i);
+ viewnodes.addAll(getViewNodes(childNode));
+ }
+ }
+
+ return viewnodes;
+ }
+
+ private List<SessionNode> getQueryNodes(SessionNode node) {
+ return this.getNodes(node, "datasetlist");
+ }
+
+ private List<SessionNode> getNodes(SessionNode node, String nodeKey) {
+
+ List<SessionNode> nodes = new ArrayList<>();
+ if (node.getKey().equals(nodeKey)) {
+ nodes.add(node);
+ }
+
+ if (!node.children.isEmpty()) {
+ for (int i = 0; i < node.children.size(); i++) {
+ SessionNode childNode = node.children.get(i);
+ nodes.addAll(getNodes(childNode, nodeKey));
+ }
+ }
+
+ return nodes;
+ }
+
+ /**
+ * Obtain the ranking training data.
+ *
+ * @param indexName the index from whcih to obtain the data
+ * @param sessionID a valid session identifier
+ * @return {@link ClickStream}
+ * @throws UnsupportedEncodingException if there is an error whilst
+ * processing the ranking training data.
+ */
+ public List<RankingTrainData> getRankingTrainData(String indexName, String sessionID) throws UnsupportedEncodingException {
+
+ List<RankingTrainData> trainDatas = new ArrayList<>();
+
+ List<SessionNode> queryNodes = this.getQueryNodes(this.root);
+ for (int i = 0; i < queryNodes.size(); i++) {
+ SessionNode querynode = queryNodes.get(i);
+ List<SessionNode> children = querynode.getChildren();
+
+ LinkedHashMap<String, Boolean> datasetOpt = new LinkedHashMap<>();
+ int ndownload = 0;
+ for (int j = 0; j < children.size(); j++) {
+ SessionNode node = children.get(j);
+ if ("dataset".equals(node.getKey())) {
+ Boolean bDownload = false;
+ List<SessionNode> nodeChildren = node.getChildren();
+ int childSize = nodeChildren.size();
+ for (int k = 0; k < childSize; k++) {
+ if ("ftp".equals(nodeChildren.get(k).getKey())) {
+ bDownload = true;
+ ndownload += 1;
+ break;
+ }
+ }
+ datasetOpt.put(node.datasetId, bDownload);
+ }
+ }
+
+ // method 1: The priority of download data are higher
+ if (datasetOpt.size() > 1 && ndownload > 0) {
+ // query
+ RequestUrl requestURL = new RequestUrl();
+ String queryUrl = querynode.getRequest();
+ String infoStr = requestURL.getSearchInfo(queryUrl);
+ String query = null;
+ try {
+ query = es.customAnalyzing(props.getProperty("indexName"), infoStr);
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException("Error performing custom analyzing", e);
+ }
+ Map<String, String> filter = RequestUrl.getFilterInfo(queryUrl);
+
+ for (String datasetA : datasetOpt.keySet()) {
+ Boolean bDownloadA = datasetOpt.get(datasetA);
+ if (bDownloadA) {
+ for (String datasetB : datasetOpt.keySet()) {
+ Boolean bDownloadB = datasetOpt.get(datasetB);
+ if (!bDownloadB) {
+
+ String[] queries = query.split(",");
+ for (int l = 0; l < queries.length; l++) {
+ RankingTrainData trainData = new RankingTrainData(queries[l], datasetA, datasetB);
+
+ trainData.setSessionId(this.sessionID);
+ trainData.setIndex(indexName);
+ trainData.setFilter(filter);
+ trainDatas.add(trainData);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return trainDatas;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/WebLog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/WebLog.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/WebLog.java
new file mode 100644
index 0000000..e3392e4
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/WebLog.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import java.io.Serializable;
+
+/**
+ * This class represents an Apache access log line. See
+ * http://httpd.apache.org/docs/2.2/logs.html for more details.
+ */
+public class WebLog implements Serializable {
+ String LogType;
+ String IP;
+ String Time;
+ String Request;
+ double Bytes;
+
+ public String getLogType() {
+ return this.LogType;
+ }
+
+ public String getIP() {
+ return this.IP;
+ }
+
+ public String getTime() {
+ return this.Time;
+ }
+
+ public String getRequest() {
+ return this.Request;
+ }
+
+ public double getBytes() {
+ return this.Bytes;
+ }
+
+ public WebLog() {
+
+ }
+
+ public static String SwithtoNum(String time) {
+ if (time.contains("Jan")) {
+ time = time.replace("Jan", "1");
+ } else if (time.contains("Feb")) {
+ time = time.replace("Feb", "2");
+ } else if (time.contains("Mar")) {
+ time = time.replace("Mar", "3");
+ } else if (time.contains("Apr")) {
+ time = time.replace("Apr", "4");
+ } else if (time.contains("May")) {
+ time = time.replace("May", "5");
+ } else if (time.contains("Jun")) {
+ time = time.replace("Jun", "6");
+ } else if (time.contains("Jul")) {
+ time = time.replace("Jul", "7");
+ } else if (time.contains("Aug")) {
+ time = time.replace("Aug", "8");
+ } else if (time.contains("Sep")) {
+ time = time.replace("Sep", "9");
+ } else if (time.contains("Oct")) {
+ time = time.replace("Oct", "10");
+ } else if (time.contains("Nov")) {
+ time = time.replace("Nov", "11");
+ } else if (time.contains("Dec")) {
+ time = time.replace("Dec", "12");
+ }
+ return time;
+ }
+
+ public static boolean checknull(String s) {
+ if (s.equals("{}")) {
+ return false;
+ }
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/package-info.java
new file mode 100644
index 0000000..7aa9898
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes data structure needed for web log analysis
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/config.xml
----------------------------------------------------------------------
diff --git a/core/src/main/resources/config.xml b/core/src/main/resources/config.xml
new file mode 100644
index 0000000..62ac7a6
--- /dev/null
+++ b/core/src/main/resources/config.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<Config>
+ <para name="Cleanup_type_prefix">cleanupLog</para>
+
+ <para name="clickStreamLinkageType">ClickStreamLinkage</para>
+
+ <para name="clickStreamMatrixType">clickstreamMatrix</para>
+
+ <para name="clickstreamSVDDimension">50</para>
+
+ <para name="clickStream_w">2</para>
+
+ <para name="commentType">comment</para>
+
+ <para name="downloadf">100</para>
+
+ <para name="downloadWeight">3</para>
+
+ <para name="clusterName">MudrodES</para>
+
+ <para name="ES_Transport_TCP_Port">9300</para>
+
+ <para name="ES_unicast_hosts">127.0.0.1</para>
+
+ <para name="ES_HTTP_port">9200</para>
+
+ <para name="indexName">mudrod</para>
+
+ <para name="ftpPrefix">FTP.</para>
+
+ <para name="FTP_type_prefix">rawftp</para>
+
+ <para name="HTTP_type_prefix">rawhttp</para>
+
+ <para name="httpPrefix">WWW.</para>
+
+ <para name="logIndexName">podaaclog</para>
+
+ <para name="metadataLinkageType">MetadataLinkage</para>
+
+ <para name="metadataSVDDimension">50</para>
+
+ <para name="metadataurl">null</para>
+
+ <para name="metadata_w">1</para>
+
+ <para name="mini_userHistory">5</para>
+
+ <!--
+ The ontology service implementation. Possible values include
+ EsipPortal - EsipPortalOntology
+ EsipCOR - EsipCOROntology
+ Local - gov.nasa.jpl.mudrod.ontology.process.Local
+ -->
+ <para name="mudrod.ontology.implementation">Local</para>
+
+ <para name="ontologyLinkageType">SWEETLinkage</para>
+
+ <para name="ontology_w">2</para>
+
+ <!--
+ Log processing type. Possible values include
+ 'sequential' or 'parallel'.
+ -->
+ <para name="processingType">parallel</para>
+
+ <para name="raw_metadataType">RawMetadata</para>
+
+ <para name="searchf">100</para>
+
+ <para name="sendingrate">30</para>
+
+ <para name="SessionPort">8080</para>
+
+ <para name="SessionStats_prefix">sessionstats</para>
+
+ <para name="SessionUrl">/mudrod-service/session.html</para>
+
+ <!-- The name of your application. This will appear in the UI and in log data.-->
+ <para name="spark.app.name">MudrodSparkApp</para>
+
+ <!--
+ The default Spark cluster manager to connect to. See the list of allowed master URL's.
+ For more information, consult http://spark.apache.org/docs/latest/submitting-applications.html#master-urls
+ -->
+ <para name="spark.master">local[4]</para>
+
+ <!-- ${svmSgdModel.value} is resolved at build time. See the property in core/pom.xml for the value -->
+ <para name="svmSgdModel">${svmSgdModel.value}.zip</para>
+
+ <para name="timegap">600</para>
+
+ <para name="userHistoryLinkageType">UserHistoryLinkage</para>
+
+ <para name="userHistory_w">2</para>
+
+ <para name="viewf">200</para>
+
+
+
+ <!-- FOLLOWING NEEDS TO BE ADDED TO MudrodConstants.java -->
+ <para name="recom_metadataType">RecomMetadata</para>
+ <!-- recommendation -->
+ <para name="metadataTermTFIDFSimType">MetadataTermTFIDFSim</para>
+ <para name="metadataWordTFIDFSimType">MetadataWordTFIDFSim</para>
+ <para name="metadataCodeSimType">MetadataCodeSim</para>
+ <para name="metadataSessionBasedSimType">MetadataSBSim</para>
+ <para name="metadataTopicSimType">MetadataTBSim</para>
+ <!--
+ Log processing parallel optimization type. Possible values include
+ default - MudrodConstants.PARALLEL_OPTIMIZATION_DEFAULT
+ repartition - MudrodConstants.PARALLEL_OPTIMIZATION_REPARTITION
+ -->
+ <para name="parallelOptimization">repartition</para>
+
+</Config>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/elastic_mappings.json
----------------------------------------------------------------------
diff --git a/core/src/main/resources/elastic_mappings.json b/core/src/main/resources/elastic_mappings.json
new file mode 100644
index 0000000..685f49e
--- /dev/null
+++ b/core/src/main/resources/elastic_mappings.json
@@ -0,0 +1,68 @@
+{
+ "_default_": {
+ "properties": {
+ "keywords": {
+ "type": "text",
+ "analyzer": "csv",
+ "fielddata": true
+ },
+ "views": {
+ "type": "string",
+ "analyzer": "csv"
+ },
+ "downloads": {
+ "type": "string",
+ "analyzer": "csv"
+ },
+ "RequestUrl": {
+ "type": "string",
+ "include_in_all": false,
+ "index": "no"
+ },
+ "IP": {
+ "type": "keyword",
+ "index": "not_analyzed"
+ },
+ "Browser": {
+ "type": "string",
+ "include_in_all": false,
+ "index": "no"
+ },
+ "SessionURL": {
+ "type": "string",
+ "include_in_all": false,
+ "index": "no"
+ },
+ "Referer": {
+ "type": "string",
+ "index": "not_analyzed"
+ },
+ "SessionID": {
+ "type": "string",
+ "index": "not_analyzed"
+ },
+ "Response": {
+ "type": "string",
+ "include_in_all": false,
+ "index": "no"
+ },
+ "Request": {
+ "type": "string",
+ "include_in_all": false,
+ "index": "no"
+ },
+ "Coordinates": {
+ "type": "geo_point",
+ "include_in_all": false,
+ "index": "no"
+ },
+ "LogType": {
+ "type": "string",
+ "index": "not_analyzed"
+ },
+ "Dataset-Metadata": {
+ "type": "completion"
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/elastic_settings.json
----------------------------------------------------------------------
diff --git a/core/src/main/resources/elastic_settings.json b/core/src/main/resources/elastic_settings.json
new file mode 100644
index 0000000..f5faa3e
--- /dev/null
+++ b/core/src/main/resources/elastic_settings.json
@@ -0,0 +1,36 @@
+{
+ "index": {
+ "number_of_replicas": 0,
+ "refresh_interval": "-1",
+ "number_of_shards": "5",
+ "translog.flush_threshold_size": "1g",
+ "translog.sync_interval": "30s",
+ "warmer.enabled": "false"
+ },
+ "analysis": {
+ "filter": {
+ "cody_stop": {
+ "type": "stop",
+ "stopwords": "_english_"
+ },
+ "cody_stemmer": {
+ "type": "stemmer",
+ "language": "light_english"
+ }
+ },
+ "analyzer": {
+ "cody": {
+ "tokenizer": "standard",
+ "filter": [
+ "lowercase",
+ "cody_stop",
+ "cody_stemmer"
+ ]
+ },
+ "csv": {
+ "type": "pattern",
+ "pattern": ","
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/javaSVMWithSGDModel/data/_SUCCESS
----------------------------------------------------------------------
diff --git a/core/src/main/resources/javaSVMWithSGDModel/data/_SUCCESS b/core/src/main/resources/javaSVMWithSGDModel/data/_SUCCESS
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/javaSVMWithSGDModel/data/_common_metadata
----------------------------------------------------------------------
diff --git a/core/src/main/resources/javaSVMWithSGDModel/data/_common_metadata b/core/src/main/resources/javaSVMWithSGDModel/data/_common_metadata
new file mode 100644
index 0000000..cafbf1b
Binary files /dev/null and b/core/src/main/resources/javaSVMWithSGDModel/data/_common_metadata differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/javaSVMWithSGDModel/data/_metadata
----------------------------------------------------------------------
diff --git a/core/src/main/resources/javaSVMWithSGDModel/data/_metadata b/core/src/main/resources/javaSVMWithSGDModel/data/_metadata
new file mode 100644
index 0000000..6bfec98
Binary files /dev/null and b/core/src/main/resources/javaSVMWithSGDModel/data/_metadata differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/javaSVMWithSGDModel/data/part-r-00000-e008ae03-6b61-4931-ba29-27304de5a584.gz.parquet
----------------------------------------------------------------------
diff --git a/core/src/main/resources/javaSVMWithSGDModel/data/part-r-00000-e008ae03-6b61-4931-ba29-27304de5a584.gz.parquet b/core/src/main/resources/javaSVMWithSGDModel/data/part-r-00000-e008ae03-6b61-4931-ba29-27304de5a584.gz.parquet
new file mode 100644
index 0000000..5033301
Binary files /dev/null and b/core/src/main/resources/javaSVMWithSGDModel/data/part-r-00000-e008ae03-6b61-4931-ba29-27304de5a584.gz.parquet differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/javaSVMWithSGDModel/metadata/_SUCCESS
----------------------------------------------------------------------
diff --git a/core/src/main/resources/javaSVMWithSGDModel/metadata/_SUCCESS b/core/src/main/resources/javaSVMWithSGDModel/metadata/_SUCCESS
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/javaSVMWithSGDModel/metadata/part-00000
----------------------------------------------------------------------
diff --git a/core/src/main/resources/javaSVMWithSGDModel/metadata/part-00000 b/core/src/main/resources/javaSVMWithSGDModel/metadata/part-00000
new file mode 100644
index 0000000..c972cbe
--- /dev/null
+++ b/core/src/main/resources/javaSVMWithSGDModel/metadata/part-00000
@@ -0,0 +1 @@
+{"class":"org.apache.spark.mllib.classification.SVMModel","version":"1.0","numFeatures":6,"numClasses":2}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/log4j.properties b/core/src/main/resources/log4j.properties
new file mode 100644
index 0000000..1e6e84d
--- /dev/null
+++ b/core/src/main/resources/log4j.properties
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0 Unless
+#
+# required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS"
+# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language
+# governing permissions and limitations under the License.
+# Define some default values that can be overridden by system properties
+# Logging Threshold
+mudrod.root.logger=INFO,DRFA, stdout
+mudrod.log.dir=.
+mudrod.log.file=mudrod.log
+log4j.threshhold=ALL
+# RootLogger - DailyRollingFileAppender
+log4j.rootLogger=${mudrod.root.logger}
+#special logging requirements for some commandline tools
+log4j.logger.MudrodEngine=INFO,cmdstdout
+#
+# Daily Rolling File Appender
+#
+log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.DRFA.File=${mudrod.log.dir}/${mudrod.log.file}
+# Rollver at midnight
+log4j.appender.DRFA.DatePattern=.yyyy-MM-dd
+# 30-day backup
+#log4j.appender.DRFA.MaxBackupIndex=30
+log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} - %m%n
+# Debugging Pattern format: Date LogLevel LoggerName (FileName:MethodName:LineNo) LogMessage
+#log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+#
+# stdout
+# Add *stdout* to rootlogger above if you want to use this
+#
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+#
+# plain layout used for commandline tools to output to console
+#
+log4j.appender.cmdstdout=org.apache.log4j.ConsoleAppender
+log4j.appender.cmdstdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.cmdstdout.layout.ConversionPattern=%m%n
+#
+# Rolling File Appender
+#
+#log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+#log4j.appender.RFA.File=${hadoop.log.dir}/${hadoop.log.file}
+# Logfile size and and 30-day backups
+#log4j.appender.RFA.MaxFileSize=1MB
+#log4j.appender.RFA.MaxBackupIndex=30
+#log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} - %m%n
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+# Custom Logging levels
+log4j.logger.akka=WARN
+log4j.logger.org.apache=WARN
+log4j.logger.gov.nasa.jpl.mudrod=INFO
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/resources/log4j2.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/log4j2.properties b/core/src/main/resources/log4j2.properties
new file mode 100644
index 0000000..1e6e84d
--- /dev/null
+++ b/core/src/main/resources/log4j2.properties
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0 Unless
+#
+# required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS"
+# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language
+# governing permissions and limitations under the License.
+# Define some default values that can be overridden by system properties
+# Logging Threshold
+mudrod.root.logger=INFO,DRFA, stdout
+mudrod.log.dir=.
+mudrod.log.file=mudrod.log
+log4j.threshhold=ALL
+# RootLogger - DailyRollingFileAppender
+log4j.rootLogger=${mudrod.root.logger}
+#special logging requirements for some commandline tools
+log4j.logger.MudrodEngine=INFO,cmdstdout
+#
+# Daily Rolling File Appender
+#
+log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.DRFA.File=${mudrod.log.dir}/${mudrod.log.file}
+# Rollver at midnight
+log4j.appender.DRFA.DatePattern=.yyyy-MM-dd
+# 30-day backup
+#log4j.appender.DRFA.MaxBackupIndex=30
+log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} - %m%n
+# Debugging Pattern format: Date LogLevel LoggerName (FileName:MethodName:LineNo) LogMessage
+#log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+#
+# stdout
+# Add *stdout* to rootlogger above if you want to use this
+#
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+#
+# plain layout used for commandline tools to output to console
+#
+log4j.appender.cmdstdout=org.apache.log4j.ConsoleAppender
+log4j.appender.cmdstdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.cmdstdout.layout.ConversionPattern=%m%n
+#
+# Rolling File Appender
+#
+#log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+#log4j.appender.RFA.File=${hadoop.log.dir}/${hadoop.log.file}
+# Logfile size and and 30-day backups
+#log4j.appender.RFA.MaxFileSize=1MB
+#log4j.appender.RFA.MaxBackupIndex=30
+#log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} - %m%n
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+# Custom Logging levels
+log4j.logger.akka=WARN
+log4j.logger.org.apache=WARN
+log4j.logger.gov.nasa.jpl.mudrod=INFO
[19/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodConstants.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodConstants.java b/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodConstants.java
new file mode 100644
index 0000000..ee7cbfa
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodConstants.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.main;
+
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+
+/**
+ * Class contains static constant keys and values relating to Mudrod
+ * configuration properties. Property values are read from <a href=
+ * "https://github.com/mudrod/mudrod/blob/master/core/src/main/resources/config.xml">config.xml</a>
+ */
+public interface MudrodConstants {
+
+ public static final String CLEANUP_TYPE_PREFIX = "Cleanup_type_prefix";
+
+ public static final String CLICK_STREAM_LINKAGE_TYPE = "clickStreamLinkageType";
+
+ public static final String CLICK_STREAM_MATRIX_TYPE = "clickStreamMatrixType";
+
+ public static final String CLICKSTREAM_SVD_DIM = "clickstreamSVDDimension";
+
+ public static final String CLICKSTREAM_W = "clickStream_w";
+
+ public static final String COMMENT_TYPE = "commentType";
+
+ /** Defined on CLI */
+ public static final String DATA_DIR = "dataDir";
+
+ public static final String DOWNLOAD_F = "downloadf";
+
+ public static final String DOWNLOAD_WEIGHT = "downloadWeight";
+
+ public static final String ES_CLUSTER = "clusterName";
+
+ public static final String ES_TRANSPORT_TCP_PORT = "ES_Transport_TCP_Port";
+
+ public static final String ES_UNICAST_HOSTS = "ES_unicast_hosts";
+
+ public static final String ES_HTTP_PORT = "ES_HTTP_port";
+
+ public static final String ES_INDEX_NAME = "indexName";
+
+ public static final String FTP_PREFIX = "ftpPrefix";
+
+ public static final String FTP_TYPE_PREFIX = "FTP_type_prefix";
+
+ public static final String HTTP_PREFIX = "httpPrefix";
+
+ public static final String HTTP_TYPE_PREFIX = "HTTP_type_prefix";
+
+ public static final String LOG_INDEX = "logIndexName";
+
+ public static final String METADATA_LINKAGE_TYPE = "metadataLinkageType";
+
+ public static final String METADATA_SVD_DIM = "metadataSVDDimension";
+
+ public static final String METADATA_URL = "metadataurl";
+
+ public static final String METADATA_W = "metadata_w";
+
+ public static final String MINI_USER_HISTORY = "mini_userHistory";
+
+ public static final String MUDROD = "mudrod";
+
+ /** Defined on CLI */
+ public static final String MUDROD_CONFIG = "MUDROD_CONFIG";
+ /**
+ * An {@link Ontology} implementation.
+ */
+ public static final String ONTOLOGY_IMPL = MUDROD + "ontology.implementation";
+
+ public static final String ONTOLOGY_LINKAGE_TYPE = "ontologyLinkageType";
+
+ public static final String ONTOLOGY_W = "ontology_w";
+
+ public static final String PROCESS_TYPE = "processingType";
+
+ /** Defined on CLI */
+ public static final String RAW_METADATA_PATH = "raw_metadataPath";
+
+ public static final String RAW_METADATA_TYPE = "raw_metadataType";
+
+ public static final String SEARCH_F = "searchf";
+
+ public static final String SENDING_RATE = "sendingrate";
+
+ public static final String SESSION_PORT = "SessionPort";
+
+ public static final String SESSION_STATS_PREFIX = "SessionStats_prefix";
+
+ public static final String SESSION_URL = "SessionUrl";
+
+ public static final String SPARK_APP_NAME = "spark.app.name";
+
+ public static final String SPARK_MASTER = "spark.master";
+ /**
+ * Absolute local location of javaSVMWithSGDModel directory. This is typically
+ * <code>file:///usr/local/mudrod/core/src/main/resources/javaSVMWithSGDModel</code>
+ */
+ public static final String SVM_SGD_MODEL = "svmSgdModel";
+
+ public static final String TIMEGAP = "timegap";
+
+ public static final String TIME_SUFFIX = "TimeSuffix";
+
+ public static final String USE_HISTORY_LINKAGE_TYPE = "userHistoryLinkageType";
+
+ public static final String USER_HISTORY_W = "userHistory_w";
+
+ public static final String VIEW_F = "viewf";
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java b/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java
new file mode 100644
index 0000000..27dba84
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/main/MudrodEngine.java
@@ -0,0 +1,457 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.main;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryEngineAbstract;
+import gov.nasa.jpl.mudrod.discoveryengine.MetadataDiscoveryEngine;
+import gov.nasa.jpl.mudrod.discoveryengine.OntologyDiscoveryEngine;
+import gov.nasa.jpl.mudrod.discoveryengine.RecommendEngine;
+import gov.nasa.jpl.mudrod.discoveryengine.WeblogDiscoveryEngine;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.integration.LinkageIntegration;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.jdom2.input.SAXBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import static gov.nasa.jpl.mudrod.main.MudrodConstants.DATA_DIR;
+
+/**
+ * Main entry point for Running the Mudrod system. Invocation of this class is
+ * tightly linked to the primary Mudrod configuration which can be located at
+ * <a href=
+ * "https://github.com/mudrod/mudrod/blob/master/core/src/main/resources/config.xml">config.xml</a>.
+ */
+public class MudrodEngine {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MudrodEngine.class);
+ private Properties props = new Properties();
+ private ESDriver es = null;
+ private SparkDriver spark = null;
+ private static final String LOG_INGEST = "logIngest";
+ private static final String META_INGEST = "metaIngest";
+ private static final String FULL_INGEST = "fullIngest";
+ private static final String PROCESSING = "processingWithPreResults";
+ private static final String ES_HOST = "esHost";
+ private static final String ES_TCP_PORT = "esTCPPort";
+ private static final String ES_HTTP_PORT = "esPort";
+
+ /**
+ * Public constructor for this class.
+ */
+ public MudrodEngine() {
+ // default constructor
+ }
+
+ /**
+ * Start the {@link ESDriver}. Should only be called after call to
+ * {@link MudrodEngine#loadConfig()}
+ *
+ * @return fully provisioned {@link ESDriver}
+ */
+ public ESDriver startESDriver() {
+ return new ESDriver(props);
+ }
+
+ /**
+ * Start the {@link SparkDriver}. Should only be called after call to
+ * {@link MudrodEngine#loadConfig()}
+ *
+ * @return fully provisioned {@link SparkDriver}
+ */
+ public SparkDriver startSparkDriver() {
+ return new SparkDriver(props);
+ }
+
+ /**
+ * Retreive the Mudrod configuration as a Properties Map containing K, V of
+ * type String.
+ *
+ * @return a {@link java.util.Properties} object
+ */
+ public Properties getConfig() {
+ return props;
+ }
+
+ /**
+ * Retreive the Mudrod {@link ESDriver}
+ *
+ * @return the {@link ESDriver} instance.
+ */
+ public ESDriver getESDriver() {
+ return this.es;
+ }
+
+ /**
+ * Set the Elasticsearch driver for MUDROD
+ *
+ * @param es
+ * an ES driver instance
+ */
+ public void setESDriver(ESDriver es) {
+ this.es = es;
+ }
+
+ private InputStream locateConfig() {
+
+ String configLocation = System.getenv(MudrodConstants.MUDROD_CONFIG) == null ? "" : System.getenv(MudrodConstants.MUDROD_CONFIG);
+ File configFile = new File(configLocation);
+
+ try {
+ InputStream configStream = new FileInputStream(configFile);
+ LOG.info("Loaded config file from " + configFile.getAbsolutePath());
+ return configStream;
+ } catch (IOException e) {
+ LOG.info("File specified by environment variable " + MudrodConstants.MUDROD_CONFIG + "=\'" + configLocation + "\' could not be loaded. " + e.getMessage());
+ }
+
+ InputStream configStream = MudrodEngine.class.getClassLoader().getResourceAsStream("config.xml");
+
+ if (configStream != null) {
+ LOG.info("Loaded config file from {}", MudrodEngine.class.getClassLoader().getResource("config.xml").getPath());
+ }
+
+ return configStream;
+ }
+
+ /**
+ * Load the configuration provided at <a href=
+ * "https://github.com/mudrod/mudrod/blob/master/core/src/main/resources/config.xml">config.xml</a>.
+ *
+ * @return a populated {@link java.util.Properties} object.
+ */
+ public Properties loadConfig() {
+ SAXBuilder saxBuilder = new SAXBuilder();
+
+ InputStream configStream = locateConfig();
+
+ Document document;
+ try {
+ document = saxBuilder.build(configStream);
+ Element rootNode = document.getRootElement();
+ List<Element> paraList = rootNode.getChildren("para");
+
+ for (int i = 0; i < paraList.size(); i++) {
+ Element paraNode = paraList.get(i);
+ String attributeName = paraNode.getAttributeValue("name");
+ if (MudrodConstants.SVM_SGD_MODEL.equals(attributeName)) {
+ props.put(attributeName, decompressSVMWithSGDModel(paraNode.getTextTrim()));
+ } else {
+ props.put(attributeName, paraNode.getTextTrim());
+ }
+ }
+ } catch (JDOMException | IOException e) {
+ LOG.error("Exception whilst retrieving or processing XML contained within 'config.xml'!", e);
+ }
+ return getConfig();
+
+ }
+
+ private String decompressSVMWithSGDModel(String archiveName) throws IOException {
+
+ URL scmArchive = getClass().getClassLoader().getResource(archiveName);
+ if (scmArchive == null) {
+ throw new IOException("Unable to locate " + archiveName + " as a classpath resource.");
+ }
+ File tempDir = Files.createTempDirectory("mudrod").toFile();
+ assert tempDir.setWritable(true);
+ File archiveFile = new File(tempDir, archiveName);
+ FileUtils.copyURLToFile(scmArchive, archiveFile);
+
+ // Decompress archive
+ int BUFFER_SIZE = 512000;
+ ZipInputStream zipIn = new ZipInputStream(new FileInputStream(archiveFile));
+ ZipEntry entry;
+ while ((entry = zipIn.getNextEntry()) != null) {
+ File f = new File(tempDir, entry.getName());
+ // If the entry is a directory, create the directory.
+ if (entry.isDirectory() && !f.exists()) {
+ boolean created = f.mkdirs();
+ if (!created) {
+ LOG.error("Unable to create directory '{}', during extraction of archive contents.", f.getAbsolutePath());
+ }
+ } else if (!entry.isDirectory()) {
+ boolean created = f.getParentFile().mkdirs();
+ if (!created && !f.getParentFile().exists()) {
+ LOG.error("Unable to create directory '{}', during extraction of archive contents.", f.getParentFile().getAbsolutePath());
+ }
+ int count;
+ byte data[] = new byte[BUFFER_SIZE];
+ FileOutputStream fos = new FileOutputStream(new File(tempDir, entry.getName()), false);
+ try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
+ while ((count = zipIn.read(data, 0, BUFFER_SIZE)) != -1) {
+ dest.write(data, 0, count);
+ }
+ }
+ }
+ }
+
+ return new File(tempDir, StringUtils.removeEnd(archiveName, ".zip")).toURI().toString();
+ }
+
+ /**
+ * Preprocess and process logs {@link DiscoveryEngineAbstract} implementations
+ * for weblog
+ */
+ public void startLogIngest() {
+ DiscoveryEngineAbstract wd = new WeblogDiscoveryEngine(props, es, spark);
+ wd.preprocess();
+ wd.process();
+ LOG.info("*****************logs have been ingested successfully******************");
+ }
+
+ /**
+ * updating and analysing metadata to metadata similarity results
+ */
+ public void startMetaIngest() {
+ DiscoveryEngineAbstract md = new MetadataDiscoveryEngine(props, es, spark);
+ md.preprocess();
+ md.process();
+
+ DiscoveryEngineAbstract recom = new RecommendEngine(props, es, spark);
+ recom.preprocess();
+ recom.process();
+ LOG.info("Metadata has been ingested successfully.");
+ }
+
+ public void startFullIngest() {
+ DiscoveryEngineAbstract wd = new WeblogDiscoveryEngine(props, es, spark);
+ wd.preprocess();
+ wd.process();
+
+ DiscoveryEngineAbstract md = new MetadataDiscoveryEngine(props, es, spark);
+ md.preprocess();
+ md.process();
+
+ DiscoveryEngineAbstract recom = new RecommendEngine(props, es, spark);
+ recom.preprocess();
+ recom.process();
+ LOG.info("Full ingest has finished successfully.");
+ }
+
+ /**
+ * Only preprocess various {@link DiscoveryEngineAbstract} implementations for
+ * weblog, ontology and metadata, linkage discovery and integration.
+ */
+ public void startProcessing() {
+ DiscoveryEngineAbstract wd = new WeblogDiscoveryEngine(props, es, spark);
+ wd.process();
+
+ DiscoveryEngineAbstract od = new OntologyDiscoveryEngine(props, es, spark);
+ od.preprocess();
+ od.process();
+
+ DiscoveryEngineAbstract md = new MetadataDiscoveryEngine(props, es, spark);
+ md.preprocess();
+ md.process();
+
+ LinkageIntegration li = new LinkageIntegration(props, es, spark);
+ li.execute();
+
+ DiscoveryEngineAbstract recom = new RecommendEngine(props, es, spark);
+ recom.process();
+ }
+
+ /**
+ * Close the connection to the {@link ESDriver} instance.
+ */
+ public void end() {
+ if (es != null) {
+ es.close();
+ }
+ }
+
+ /**
+ * Main program invocation. Accepts one argument denoting location (on disk)
+ * to a log file which is to be ingested. Help will be provided if invoked
+ * with incorrect parameters.
+ *
+ * @param args
+ * {@link java.lang.String} array contaning correct parameters.
+ */
+ public static void main(String[] args) {
+ // boolean options
+ Option helpOpt = new Option("h", "help", false, "show this help message");
+
+ // log ingest (preprocessing + processing)
+ Option logIngestOpt = new Option("l", LOG_INGEST, false, "begin log ingest");
+ // metadata ingest (preprocessing + processing)
+ Option metaIngestOpt = new Option("m", META_INGEST, false, "begin metadata ingest");
+ // ingest both log and metadata
+ Option fullIngestOpt = new Option("f", FULL_INGEST, false, "begin full ingest Mudrod workflow");
+ // processing only, assuming that preprocessing results is in dataDir
+ Option processingOpt = new Option("p", PROCESSING, false, "begin processing with preprocessing results");
+
+ // argument options
+ Option dataDirOpt = OptionBuilder.hasArg(true).withArgName("/path/to/data/directory").hasArgs(1).withDescription("the data directory to be processed by Mudrod").withLongOpt("dataDirectory")
+ .isRequired().create(DATA_DIR);
+
+ Option esHostOpt = OptionBuilder.hasArg(true).withArgName("host_name").hasArgs(1).withDescription("elasticsearch cluster unicast host").withLongOpt("elasticSearchHost").isRequired(false)
+ .create(ES_HOST);
+
+ Option esTCPPortOpt = OptionBuilder.hasArg(true).withArgName("port_num").hasArgs(1).withDescription("elasticsearch transport TCP port").withLongOpt("elasticSearchTransportTCPPort")
+ .isRequired(false).create(ES_TCP_PORT);
+
+ Option esPortOpt = OptionBuilder.hasArg(true).withArgName("port_num").hasArgs(1).withDescription("elasticsearch HTTP/REST port").withLongOpt("elasticSearchHTTPPort").isRequired(false)
+ .create(ES_HTTP_PORT);
+
+ // create the options
+ Options options = new Options();
+ options.addOption(helpOpt);
+ options.addOption(logIngestOpt);
+ options.addOption(metaIngestOpt);
+ options.addOption(fullIngestOpt);
+ options.addOption(processingOpt);
+ options.addOption(dataDirOpt);
+ options.addOption(esHostOpt);
+ options.addOption(esTCPPortOpt);
+ options.addOption(esPortOpt);
+
+ CommandLineParser parser = new GnuParser();
+ try {
+ CommandLine line = parser.parse(options, args);
+ String processingType = null;
+
+ if (line.hasOption(LOG_INGEST)) {
+ processingType = LOG_INGEST;
+ } else if (line.hasOption(PROCESSING)) {
+ processingType = PROCESSING;
+ } else if (line.hasOption(META_INGEST)) {
+ processingType = META_INGEST;
+ } else if (line.hasOption(FULL_INGEST)) {
+ processingType = FULL_INGEST;
+ }
+
+ String dataDir = line.getOptionValue(DATA_DIR).replace("\\", "/");
+ if (!dataDir.endsWith("/")) {
+ dataDir += "/";
+ }
+
+ MudrodEngine me = new MudrodEngine();
+ me.loadConfig();
+ me.props.put(DATA_DIR, dataDir);
+
+ if (line.hasOption(ES_HOST)) {
+ String esHost = line.getOptionValue(ES_HOST);
+ me.props.put(MudrodConstants.ES_UNICAST_HOSTS, esHost);
+ }
+
+ if (line.hasOption(ES_TCP_PORT)) {
+ String esTcpPort = line.getOptionValue(ES_TCP_PORT);
+ me.props.put(MudrodConstants.ES_TRANSPORT_TCP_PORT, esTcpPort);
+ }
+
+ if (line.hasOption(ES_HTTP_PORT)) {
+ String esHttpPort = line.getOptionValue(ES_HTTP_PORT);
+ me.props.put(MudrodConstants.ES_HTTP_PORT, esHttpPort);
+ }
+
+ me.es = new ESDriver(me.getConfig());
+ me.spark = new SparkDriver(me.getConfig());
+ loadFullConfig(me, dataDir);
+ if (processingType != null) {
+ switch (processingType) {
+ case PROCESSING:
+ me.startProcessing();
+ break;
+ case LOG_INGEST:
+ me.startLogIngest();
+ break;
+ case META_INGEST:
+ me.startMetaIngest();
+ break;
+ case FULL_INGEST:
+ me.startFullIngest();
+ break;
+ default:
+ break;
+ }
+ }
+ me.end();
+ } catch (Exception e) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("MudrodEngine: 'dataDir' argument is mandatory. " + "User must also provide an ingest method.", options, true);
+ LOG.error("Error whilst parsing command line.", e);
+ }
+ }
+
+ private static void loadFullConfig(MudrodEngine me, String dataDir) {
+ //TODO all of the properties defined below, which are determined are
+ //runtime need to be added to MudrodConstants.java and referenced
+ //accordingly and consistently from Properties.getProperty(MudrodConstant...);
+ me.props.put("ontologyInputDir", dataDir + "SWEET_ocean/");
+ me.props.put("oceanTriples", dataDir + "Ocean_triples.csv");
+ me.props.put("userHistoryMatrix", dataDir + "UserHistoryMatrix.csv");
+ me.props.put("clickstreamMatrix", dataDir + "ClickstreamMatrix.csv");
+ me.props.put("metadataMatrix", dataDir + "MetadataMatrix.csv");
+ me.props.put("clickstreamSVDMatrix_tmp", dataDir + "clickstreamSVDMatrix_tmp.csv");
+ me.props.put("metadataSVDMatrix_tmp", dataDir + "metadataSVDMatrix_tmp.csv");
+ me.props.put("raw_metadataPath", dataDir + me.props.getProperty(MudrodConstants.RAW_METADATA_TYPE));
+
+ me.props.put("jtopia", dataDir + "jtopiaModel");
+ me.props.put("metadata_term_tfidf_matrix", dataDir + "metadata_term_tfidf.csv");
+ me.props.put("metadata_word_tfidf_matrix", dataDir + "metadata_word_tfidf.csv");
+ me.props.put("session_metadata_Matrix", dataDir + "metadata_session_coocurrence_matrix.csv");
+
+ me.props.put("metadataOBCode", dataDir + "MetadataOHCode");
+ me.props.put("metadata_topic", dataDir + "metadata_topic");
+ me.props.put("metadata_topic_matrix", dataDir + "metadata_topic_matrix.csv");
+ }
+
+ /**
+ * Obtain the spark implementation.
+ *
+ * @return the {@link SparkDriver}
+ */
+ public SparkDriver getSparkDriver() {
+ return this.spark;
+ }
+
+ /**
+ * Set the {@link SparkDriver}
+ *
+ * @param sparkDriver
+ * a configured {@link SparkDriver}
+ */
+ public void setSparkDriver(SparkDriver sparkDriver) {
+ this.spark = sparkDriver;
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/main/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/main/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/main/package-info.java
new file mode 100644
index 0000000..44d0518
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/main/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes Main entry point for Running the Mudrod system.
+ */
+package gov.nasa.jpl.mudrod.main;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/package-info.java
new file mode 100644
index 0000000..1bb0a3c
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes metadata pre-processing, processing, and data structure
+ * classes.
+ */
+package gov.nasa.jpl.mudrod.metadata;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/ApiHarvester.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/ApiHarvester.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/ApiHarvester.java
new file mode 100644
index 0000000..bc7d187
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/ApiHarvester.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.metadata.pre;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.utils.HttpRequest;
+import org.apache.commons.io.IOUtils;
+import org.elasticsearch.action.index.IndexRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.util.Properties;
+
+/**
+ * ClassName: ApiHarvester Function: Harvest metadata from PO.DAACweb service.
+ */
+public class ApiHarvester extends DiscoveryStepAbstract {
+
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(ApiHarvester.class);
+
+ /**
+ * Creates a new instance of ApiHarvester.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch drive
+ * @param spark the spark driver
+ */
+ public ApiHarvester(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting Metadata harvesting.");
+ startTime = System.currentTimeMillis();
+ //remove old metadata from ES
+ es.deleteType(props.getProperty(MudrodConstants.ES_INDEX_NAME), props.getProperty(MudrodConstants.RAW_METADATA_TYPE));
+ //harvest new metadata using PO.DAAC web services
+ harvestMetadatafromWeb();
+ es.createBulkProcessor();
+ addMetadataMapping();
+ importToES();
+ es.destroyBulkProcessor();
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("Metadata harvesting completed. Time elapsed: {}", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ /**
+ * addMetadataMapping: Add mapping to index metadata in Elasticsearch. Please
+ * invoke this method before import metadata to Elasticsearch.
+ */
+ public void addMetadataMapping() {
+ String mappingJson = "{\r\n \"dynamic_templates\": " + "[\r\n " + "{\r\n \"strings\": " + "{\r\n \"match_mapping_type\": \"string\","
+ + "\r\n \"mapping\": {\r\n \"type\": \"text\"," + "\r\n \"fielddata\": true," + "\r\n \"analyzer\": \"english\","
+ + "\r\n \"fields\": {\r\n \"raw\": {" + "\r\n \"type\": \"string\"," + "\r\n \"index\": \"not_analyzed\"" + "\r\n }"
+ + "\r\n }\r\n " + "\r\n }" + "\r\n }\r\n }\r\n ]\r\n}";
+
+ es.getClient().admin().indices().preparePutMapping(props.getProperty(MudrodConstants.ES_INDEX_NAME)).setType(props.getProperty(MudrodConstants.RAW_METADATA_TYPE)).setSource(mappingJson).execute()
+ .actionGet();
+ }
+
+ /**
+ * importToES: Index metadata into elasticsearch from local file directory.
+ * Please make sure metadata have been harvest from web service before
+ * invoking this method.
+ */
+ private void importToES() {
+ File directory = new File(props.getProperty(MudrodConstants.RAW_METADATA_PATH));
+ if(!directory.exists())
+ directory.mkdir();
+ File[] fList = directory.listFiles();
+ for (File file : fList) {
+ InputStream is;
+ try {
+ is = new FileInputStream(file);
+ importSingleFileToES(is);
+ } catch (FileNotFoundException e) {
+ LOG.error("Error finding file!", e);
+ }
+
+ }
+ }
+
+ private void importSingleFileToES(InputStream is) {
+ try {
+ String jsonTxt = IOUtils.toString(is);
+ JsonParser parser = new JsonParser();
+ JsonElement item = parser.parse(jsonTxt);
+ IndexRequest ir = new IndexRequest(props.getProperty(MudrodConstants.ES_INDEX_NAME), props.getProperty(MudrodConstants.RAW_METADATA_TYPE)).source(item.toString());
+ es.getBulkProcessor().add(ir);
+ } catch (IOException e) {
+ LOG.error("Error indexing metadata record!", e);
+ }
+ }
+
+ /**
+ * harvestMetadatafromWeb: Harvest metadata from PO.DAAC web service.
+ */
+ private void harvestMetadatafromWeb() {
+ LOG.info("Metadata download started.");
+ int startIndex = 0;
+ int doc_length = 0;
+ JsonParser parser = new JsonParser();
+ do {
+ String searchAPI = "https://podaac.jpl.nasa.gov/api/dataset?startIndex=" + Integer.toString(startIndex) + "&entries=10&sortField=Dataset-AllTimePopularity&sortOrder=asc&id=&value=&search=";
+ HttpRequest http = new HttpRequest();
+ String response = http.getRequest(searchAPI);
+
+ JsonElement json = parser.parse(response);
+ JsonObject responseObject = json.getAsJsonObject();
+ JsonArray docs = responseObject.getAsJsonObject("response").getAsJsonArray("docs");
+
+ doc_length = docs.size();
+
+ File file = new File(props.getProperty(MudrodConstants.RAW_METADATA_PATH));
+ if (!file.exists()) {
+ if (file.mkdir()) {
+ LOG.info("Directory is created!");
+ } else {
+ LOG.error("Failed to create directory!");
+ }
+ }
+ for (int i = 0; i < doc_length; i++) {
+ JsonElement item = docs.get(i);
+ int docId = startIndex + i;
+ File itemfile = new File(props.getProperty(MudrodConstants.RAW_METADATA_PATH) + "/" + docId + ".json");
+
+ try (FileWriter fw = new FileWriter(itemfile.getAbsoluteFile()); BufferedWriter bw = new BufferedWriter(fw);) {
+ itemfile.createNewFile();
+ bw.write(item.toString());
+ } catch (IOException e) {
+ LOG.error("Error writing metadata to local file!", e);
+ }
+ }
+
+ startIndex += 10;
+
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ LOG.error("Error entering Elasticsearch Mappings!", e);
+ Thread.currentThread().interrupt();
+ }
+
+ } while (doc_length != 0);
+
+ LOG.info("Metadata downloading finished");
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/MatrixGenerator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/MatrixGenerator.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/MatrixGenerator.java
new file mode 100644
index 0000000..63677e5
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/MatrixGenerator.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.metadata.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.metadata.structure.MetadataExtractor;
+import gov.nasa.jpl.mudrod.utils.LabeledRowMatrix;
+import gov.nasa.jpl.mudrod.utils.MatrixUtil;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Generate term-metadata matrix from original metadata. Each row in
+ * the matrix is corresponding to a term, and each column is a metadata.
+ */
+public class MatrixGenerator extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(MatrixGenerator.class);
+
+ /**
+ * Creates a new instance of MatrixGenerator.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch drive
+ * @param spark the spark drive
+ */
+ public MatrixGenerator(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Generate a csv which is a term-metadata matrix genetrated from original
+ * metadata.
+ *
+ * @see DiscoveryStepAbstract#execute()
+ */
+ @Override
+ public Object execute() {
+ LOG.info("Metadata matrix started");
+ startTime = System.currentTimeMillis();
+
+ String metadataMatrixFile = props.getProperty("metadataMatrix");
+ try {
+ MetadataExtractor extractor = new MetadataExtractor();
+ JavaPairRDD<String, List<String>> metadataTermsRDD = extractor.loadMetadata(this.es, this.spark.sc, props.getProperty(MudrodConstants.ES_INDEX_NAME), props.getProperty(MudrodConstants.RAW_METADATA_TYPE));
+ LabeledRowMatrix wordDocMatrix = MatrixUtil.createWordDocMatrix(metadataTermsRDD);
+ MatrixUtil.exportToCSV(wordDocMatrix.rowMatrix, wordDocMatrix.rowkeys, wordDocMatrix.colkeys, metadataMatrixFile);
+
+ } catch (Exception e) {
+ LOG.error("Error during Metadata matrix generaion: {}", e);
+ }
+
+ endTime = System.currentTimeMillis();
+ LOG.info("Metadata matrix finished time elapsed: {}s", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/package-info.java
new file mode 100644
index 0000000..60a2429
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/pre/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes metadata pre-processing functions.
+ */
+package gov.nasa.jpl.mudrod.metadata.pre;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/MetadataAnalyzer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/MetadataAnalyzer.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/MetadataAnalyzer.java
new file mode 100644
index 0000000..67dbf2d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/MetadataAnalyzer.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.metadata.process;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.semantics.SVDAnalyzer;
+import gov.nasa.jpl.mudrod.utils.LinkageTriple;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * ClassName: MetadataAnalyzer
+ * Function: Calculate semantic relationship of vocabularies extracted from
+ * metadata.
+ */
+public class MetadataAnalyzer extends DiscoveryStepAbstract implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(MetadataAnalyzer.class);
+
+ /**
+ * Creates a new instance of MetadataAnalyzer.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch drive
+ * @param spark the spark drive
+ */
+ public MetadataAnalyzer(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ /**
+ * Calculate semantic relationship of vocabularies from a csv file which is a
+ * term-metadata matrix.
+ *
+ * @see DiscoveryStepAbstract#execute()
+ */
+ @Override
+ public Object execute() {
+ try {
+ LOG.info("*****************Metadata Analyzer starts******************");
+ startTime = System.currentTimeMillis();
+
+ SVDAnalyzer analyzer = new SVDAnalyzer(props, es, spark);
+ int svdDimension = Integer.parseInt(props.getProperty("metadataSVDDimension"));
+ String metadataMatrixFile = props.getProperty("metadataMatrix");
+ String svdMatrixFileName = props.getProperty("metadataSVDMatrix_tmp");
+
+ analyzer.getSVDMatrix(metadataMatrixFile, svdDimension, svdMatrixFileName);
+ List<LinkageTriple> triples = analyzer.calTermSimfromMatrix(svdMatrixFileName);
+
+ analyzer.saveToES(triples, props.getProperty("indexName"), props.getProperty("metadataLinkageType"));
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("*****************Metadata Analyzer ends******************Took {}s", (endTime - startTime) / 1000);
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/package-info.java
new file mode 100644
index 0000000..c988f31
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/process/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes metadata processing classes.
+ */
+package gov.nasa.jpl.mudrod.metadata.process;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/MetadataExtractor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/MetadataExtractor.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/MetadataExtractor.java
new file mode 100644
index 0000000..a79ca87
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/MetadataExtractor.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.metadata.structure;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.api.java.function.Function2;
+import org.apache.spark.api.java.function.PairFunction;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import scala.Tuple2;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+public class MetadataExtractor implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public MetadataExtractor() {
+ }
+
+ /**
+ * loadMetadata:Load all metadata from Elasticsearch and convert them to
+ * pairRDD Please make sure metadata has been already harvested from web
+ * service and stored in Elasticsearch.
+ *
+ * @param es an Elasticsearch client node instance
+ * @param sc spark context
+ * @param index index name of log processing application
+ * @param type metadata type name
+ * @return PairRDD, in each pair key is metadata short name and value is term
+ * list extracted from metadata variables.
+ */
+ public JavaPairRDD<String, List<String>> loadMetadata(ESDriver es, JavaSparkContext sc, String index, String type) {
+ List<PODAACMetadata> metadatas = this.loadMetadataFromES(es, index, type);
+ JavaPairRDD<String, List<String>> metadataTermsRDD = this.buildMetadataRDD(es, sc, index, metadatas);
+ return metadataTermsRDD;
+ }
+
+ /**
+ * loadMetadataFromES: Load all metadata from Elasticsearch.
+ *
+ * @param es an Elasticsearch client node instance
+ * @param index index name of log processing application
+ * @param type metadata type name
+ * @return metadata list
+ */
+ protected List<PODAACMetadata> loadMetadataFromES(ESDriver es, String index, String type) {
+
+ List<PODAACMetadata> metadatas = new ArrayList<PODAACMetadata>();
+ SearchResponse scrollResp = es.getClient().prepareSearch(index).setTypes(type).setQuery(QueryBuilders.matchAllQuery()).setScroll(new TimeValue(60000)).setSize(100).execute().actionGet();
+
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String shortname = (String) result.get("Dataset-ShortName");
+ List<String> topic = (List<String>) result.get("DatasetParameter-Topic");
+ List<String> term = (List<String>) result.get("DatasetParameter-Term");
+ List<String> keyword = (List<String>) result.get("Dataset-Metadata");
+ List<String> variable = (List<String>) result.get("DatasetParameter-Variable");
+ List<String> longname = (List<String>) result.get("DatasetProject-Project-LongName");
+
+ List<String> region = (List<String>) result.get("DatasetRegion-Region");
+
+ PODAACMetadata metadata = null;
+ try {
+ metadata = new PODAACMetadata(shortname, longname, es.customAnalyzing(index, topic), es.customAnalyzing(index, term), es.customAnalyzing(index, variable), es.customAnalyzing(index, keyword),
+ es.customAnalyzing(index, region));
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+
+ }
+ metadatas.add(metadata);
+ }
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ return metadatas;
+ }
+
+ /**
+ * buildMetadataRDD: Convert metadata list to JavaPairRDD
+ *
+ * @param es an Elasticsearch client node instance
+ * @param sc spark context
+ * @param index index name of log processing application
+ * @param metadatas metadata list
+ * @return PairRDD, in each pair key is metadata short name and value is term
+ * list extracted from metadata variables.
+ */
+ protected JavaPairRDD<String, List<String>> buildMetadataRDD(ESDriver es, JavaSparkContext sc, String index, List<PODAACMetadata> metadatas) {
+ JavaRDD<PODAACMetadata> metadataRDD = sc.parallelize(metadatas);
+ JavaPairRDD<String, List<String>> metadataTermsRDD = metadataRDD.mapToPair(new PairFunction<PODAACMetadata, String, List<String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, List<String>> call(PODAACMetadata metadata) throws Exception {
+ return new Tuple2<String, List<String>>(metadata.getShortName(), metadata.getAllTermList());
+ }
+ }).reduceByKey(new Function2<List<String>, List<String>, List<String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public List<String> call(List<String> v1, List<String> v2) throws Exception {
+ List<String> list = new ArrayList<String>();
+ list.addAll(v1);
+ list.addAll(v2);
+ return list;
+ }
+ });
+
+ return metadataTermsRDD;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/PODAACMetadata.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/PODAACMetadata.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/PODAACMetadata.java
new file mode 100644
index 0000000..50b17c0
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/PODAACMetadata.java
@@ -0,0 +1,337 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.metadata.structure;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ClassName: PODAACMetadata Function: PODAACMetadata setter and getter methods
+ */
+public class PODAACMetadata implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ // shortname: data set short name
+ private String shortname;
+ // abstractStr: data set abstract
+ private String abstractStr;
+ // isoTopic: data set topic
+ private String isoTopic;
+ // sensor: sensor
+ private String sensor;
+ // source: data source
+ private String source;
+ // project: data project
+ private String project;
+ // hasAbstarct: whether data set has abstract
+ boolean hasAbstarct;
+
+ // longnameList: data set long name list
+ private List<String> longnameList;
+ // keywordList:data set key word list
+ private List<String> keywordList;
+ // termList: data set term list
+ private List<String> termList;
+ // topicList: data set topic list
+ private List<String> topicList;
+ // variableList: data set variable list
+ private List<String> variableList;
+ // abstractList: data set abstract term list
+ private List<String> abstractList;
+ // isotopicList: data set iso topic list
+ private List<String> isotopicList;
+ // sensorList: data set sensor list
+ private List<String> sensorList;
+ // sourceList: data set source list
+ private List<String> sourceList;
+ // projectList: data set project list
+ private List<String> projectList;
+ // regionList: data set region list
+ private List<String> regionList;
+
+ public PODAACMetadata() {
+ // Default constructor
+ }
+
+ /**
+ * Creates a new instance of PODAACMetadata.
+ *
+ * @param shortname data set short name
+ * @param longname data set long name
+ * @param topics data set topics
+ * @param terms data set terms
+ * @param variables data set variables
+ * @param keywords data set keywords
+ * @param region list of regions
+ */
+ public PODAACMetadata(String shortname, List<String> longname, List<String> topics, List<String> terms, List<String> variables, List<String> keywords, List<String> region) {
+ this.shortname = shortname;
+ this.longnameList = longname;
+ this.keywordList = keywords;
+ this.termList = terms;
+ this.topicList = topics;
+ this.variableList = variables;
+ this.regionList = region;
+ }
+
+ /**
+ * setTerms: set term of data set
+ *
+ * @param termstr data set terms
+ */
+ public void setTerms(String termstr) {
+ this.splitString(termstr, this.termList);
+ }
+
+ /**
+ * setKeywords: set key word of data set
+ *
+ * @param keywords data set keywords
+ */
+ public void setKeywords(String keywords) {
+ this.splitString(keywords, this.keywordList);
+ }
+
+ /**
+ * setTopicList: set topic of data set
+ *
+ * @param topicStr data set topics
+ */
+ public void setTopicList(String topicStr) {
+ this.splitString(topicStr, this.topicList);
+ }
+
+ /**
+ * setVaraliableList: set varilable of data set
+ *
+ * @param varilableStr data set variables
+ */
+ public void setVaraliableList(String varilableStr) {
+ this.splitString(varilableStr, this.variableList);
+ }
+
+ /**
+ * setProjectList:set project of data set
+ *
+ * @param project data set projects
+ */
+ public void setProjectList(String project) {
+ this.splitString(project, this.projectList);
+ }
+
+ /**
+ * setSourceList: set source of data set
+ *
+ * @param source data set sources
+ */
+ public void setSourceList(String source) {
+ this.splitString(source, this.sourceList);
+ }
+
+ /**
+ * setSensorList: set sensor of data set
+ *
+ * @param sensor data set sensors
+ */
+ public void setSensorList(String sensor) {
+ this.splitString(sensor, this.sensorList);
+ }
+
+ /**
+ * setISOTopicList:set iso topic of data set
+ *
+ * @param isoTopic data set iso topics
+ */
+ public void setISOTopicList(String isoTopic) {
+ this.splitString(isoTopic, this.isotopicList);
+ }
+
+ /**
+ * getKeywordList: get key word of data set
+ *
+ * @return data set keyword list
+ */
+ public List<String> getKeywordList() {
+ return this.keywordList;
+ }
+
+ /**
+ * getTermList:get term list of data set
+ *
+ * @return data set term list
+ */
+ public List<String> getTermList() {
+ return this.termList;
+ }
+
+ /**
+ * getShortName:get short name of data set
+ *
+ * @return data set short name
+ */
+ public String getShortName() {
+ return this.shortname;
+ }
+
+ /**
+ * getKeyword:get key word of data set
+ *
+ * @return data set keyword string
+ */
+ public String getKeyword() {
+ return String.join(",", this.keywordList);
+ }
+
+ /**
+ * getTerm:get term of data set
+ *
+ * @return data set term string
+ */
+ public String getTerm() {
+ return String.join(",", this.termList);
+ }
+
+ /**
+ * getTopic:get topic of data set
+ *
+ * @return data set topic string
+ */
+ public String getTopic() {
+ return String.join(",", this.topicList);
+ }
+
+ /**
+ * getVariable:get variable of data set
+ *
+ * @return data set variable string
+ */
+ public String getVariable() {
+ return String.join(",", this.variableList);
+ }
+
+ /**
+ * getAbstract:get abstract of data set
+ *
+ * @return data set abstract
+ */
+ public String getAbstract() {
+ return this.abstractStr;
+ }
+
+ /**
+ * getProject:get project of data set
+ *
+ * @return data set project string
+ */
+ public String getProject() {
+ return this.project;
+ }
+
+ /**
+ * getSource:get source of data set
+ *
+ * @return data set source string
+ */
+ public String getSource() {
+ return this.source;
+ }
+
+ /**
+ * getSensor:get sensor of data set
+ *
+ * @return data set sensor string
+ */
+ public String getSensor() {
+ return this.sensor;
+ }
+
+ /**
+ * getISOTopic:get iso topic of data set
+ *
+ * @return data set ISO topic string
+ */
+ public String getISOTopic() {
+ return this.isoTopic;
+ }
+
+ /**
+ * getAllTermList: get all term list of data set
+ *
+ * @return data set term list
+ */
+ public List<String> getAllTermList() {
+ List<String> allterms = new ArrayList<>();
+
+ if (this.termList != null && !this.termList.isEmpty()) {
+ allterms.addAll(this.termList);
+ }
+
+ if (this.keywordList != null && !this.keywordList.isEmpty()) {
+ allterms.addAll(this.keywordList);
+ }
+
+ if (this.topicList != null && !this.topicList.isEmpty()) {
+ allterms.addAll(this.topicList);
+ }
+
+ if (this.variableList != null && !this.variableList.isEmpty()) {
+ allterms.addAll(this.variableList);
+ }
+
+ if (this.regionList != null && !this.regionList.isEmpty()) {
+ allterms.addAll(this.regionList);
+ }
+ return allterms;
+ }
+
+ /**
+ * splitString: split value of fields of data set
+ *
+ * @param oristr original string
+ * @param list result after splitting
+ */
+ private void splitString(String oristr, List<String> list) {
+ if (oristr == null) {
+ return;
+ }
+
+ if (oristr.startsWith("\"")) {
+ oristr = oristr.substring(1);
+ }
+ if (oristr.endsWith("\"")) {
+ oristr = oristr.substring(0, oristr.length() - 1);
+ }
+
+ String strs[] = oristr.trim().split(",");
+ if (strs != null) {
+ for (int i = 0; i < strs.length; i++) {
+ String str = strs[i].trim();
+ if (str.startsWith(",") || str.startsWith("\"")) {
+ str = str.substring(1);
+ }
+ if (str.endsWith(",") || str.endsWith("\"")) {
+ str = str.substring(0, str.length() - 1);
+ }
+ if (str == "") {
+ continue;
+ }
+ list.add(str);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/package-info.java
new file mode 100644
index 0000000..d7de65d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/metadata/structure/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes classes needed for metadata analysis
+ */
+package gov.nasa.jpl.mudrod.metadata.structure;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java
new file mode 100644
index 0000000..7bc76fb
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/Ontology.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology;
+
+import java.util.Iterator;
+
+/**
+ * Base class for working with ontologies. Methods indicate ability
+ * to load, merge e.g. merge relevant ontology subgraphs into a new
+ * subgraph which can be used within Mudrod, subclass retreival,
+ * synonym expansion, etc.
+ *
+ * @author lewismc
+ */
+public interface Ontology {
+
+ /**
+ * Load an array URIs which resolve to ontology resources.
+ *
+ * @param urls a {@link java.lang.String} containing ontology URIs.
+ */
+ public void load(String[] urls);
+
+ /**
+ * Load a collection of default ontology resources.
+ */
+ public void load() ;
+
+ /**
+ * merge relevant ontology subgraphs into a new subgraph which can
+ * be used within Mudrod
+ *
+ * @param o an ontology to merge with the current ontology held
+ * within Mudrod.
+ */
+ public void merge(Ontology o);
+
+ /**
+ * Retreive all subclasses for a particular entity provided within the
+ * search term e.g.subclass-based query expansion.
+ *
+ * @param entitySearchTerm an input search term
+ * @return an {@link java.util.Iterator} object containing subClass entries.
+ */
+ public Iterator<String> subclasses(String entitySearchTerm);
+
+ /**
+ * Retreive all synonyms for a particular entity provided within the
+ * search term e.g.synonym-based query expansion.
+ *
+ * @param queryKeyPhrase a phrase to undertake synonym expansion on.
+ * @return an {@link java.util.Iterator} object containing synonym entries.
+ */
+ public Iterator<String> synonyms(String queryKeyPhrase);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java
new file mode 100644
index 0000000..f0ef6cd
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/OntologyFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology;
+
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.ontology.process.EsipCOROntology;
+import gov.nasa.jpl.mudrod.ontology.process.EsipPortalOntology;
+import gov.nasa.jpl.mudrod.ontology.process.LocalOntology;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+/**
+ * The mechanism for creating an {@link Ontology}
+ * implementation. The {@link Ontology} implementation
+ * should be specified in
+ * <a href="https://github.com/mudrod/mudrod/blob/master/core/src/main/resources/config.xml">
+ * config.xml</a> with configuration key
+ * <code>mudrod.ontology.implementation</code>.
+ * This property can also be accessed via
+ * {@link MudrodConstants#ONTOLOGY_IMPL}.
+ *
+ * @author lewismc
+ */
+public class OntologyFactory {
+
+ public static final Logger LOG = LoggerFactory.getLogger(OntologyFactory.class);
+
+ private Properties props;
+
+ /**
+ * The mechanism for creating an {@link Ontology}
+ * implementation.
+ *
+ * @param props a populated Mudrod {@link java.util.Properties} object.
+ */
+ public OntologyFactory(Properties props) {
+ this.props = props;
+ }
+
+ /**
+ * Obtain the {@link Ontology}
+ * implementation for use within Mudrod.
+ *
+ * @return Returns the ontology implementation specified
+ * in <a href="https://github.com/mudrod/mudrod/blob/master/core/src/main/resources/config.xml">
+ * config.xml</a> with configuration key
+ * <code>mudrod.ontology.implementation</code>. This property can also be accessed via
+ * {@link MudrodConstants#ONTOLOGY_IMPL}.
+ */
+ public Ontology getOntology() {
+
+ String ontologyImpl = this.props.getProperty(MudrodConstants.ONTOLOGY_IMPL, "Local");
+
+ LOG.info("Using ontology extension: {}", ontologyImpl);
+ Ontology ontImpl;
+ switch (ontologyImpl) {
+ case "EsipCOR":
+ ontImpl = new EsipCOROntology();
+ break;
+ case "EsipPortal":
+ ontImpl = new EsipPortalOntology();
+ break;
+ default:
+ ontImpl = new LocalOntology();
+ break;
+ }
+ return ontImpl;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/package-info.java
new file mode 100644
index 0000000..3763634
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes ontology pre-processing and processing classes.
+ */
+package gov.nasa.jpl.mudrod.ontology;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/AggregateTriples.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/AggregateTriples.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/AggregateTriples.java
new file mode 100644
index 0000000..99de87d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/AggregateTriples.java
@@ -0,0 +1,225 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.apache.commons.io.FilenameUtils;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.jdom2.Namespace;
+import org.jdom2.filter.ElementFilter;
+import org.jdom2.input.SAXBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Supports ability to extract triples (subclassOf, equivalent class) from OWL file
+ */
+public class AggregateTriples extends DiscoveryStepAbstract {
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(AggregateTriples.class);
+
+ public AggregateTriples(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Method of executing triple aggregation
+ */
+ @Override
+ public Object execute() {
+ File file = new File(this.props.getProperty("oceanTriples"));
+ if (file.exists()) {
+ file.delete();
+ }
+ try {
+ file.createNewFile();
+ } catch (IOException e2) {
+ e2.printStackTrace();
+ }
+
+ FileWriter fw;
+ try {
+ fw = new FileWriter(file.getAbsoluteFile());
+ bw = new BufferedWriter(fw);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ File[] files = new File(this.props.getProperty("ontologyInputDir")).listFiles();
+ for (File file_in : files) {
+ String ext = FilenameUtils.getExtension(file_in.getAbsolutePath());
+ if ("owl".equals(ext)) {
+ try {
+ loadxml(file_in.getAbsolutePath());
+ getAllClass();
+ } catch (JDOMException e1) {
+ e1.printStackTrace();
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+
+ }
+ }
+
+ try {
+ bw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public Document document;
+ public Element rootNode = null;
+ final static String owl_namespace = "http://www.w3.org/2002/07/owl#";
+ final static String rdf_namespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+ final static String rdfs_namespace = "http://www.w3.org/2000/01/rdf-schema#";
+
+ BufferedWriter bw = null;
+
+ /**
+ * Load OWL file into memory
+ *
+ * @param filePathName local path of OWL file
+ * @throws JDOMException JDOMException
+ * @throws IOException IOException
+ */
+ public void loadxml(String filePathName) throws JDOMException, IOException {
+ SAXBuilder saxBuilder = new SAXBuilder();
+ File file = new File(filePathName);
+
+ document = saxBuilder.build(file);
+ rootNode = document.getRootElement();
+ }
+
+ /**
+ * Method of going through OWL structure
+ */
+ public void loopxml() {
+ Iterator<?> processDescendants = rootNode.getDescendants(new ElementFilter());
+ String text = "";
+
+ while (processDescendants.hasNext()) {
+ Element e = (Element) processDescendants.next();
+ String currentName = e.getName();
+ text = e.getTextTrim();
+ if ("".equals(text)) {
+ LOG.info(currentName);
+ } else {
+ LOG.info("{} : {}", currentName, text);
+ }
+ }
+ }
+
+ /**
+ * Method of identifying a specific child given a element name
+ *
+ * @param str element name
+ * @param ele parent element
+ * @return the element of child
+ */
+ public Element findChild(String str, Element ele) {
+ Iterator<?> processDescendants = ele.getDescendants(new ElementFilter());
+ String name = "";
+ Element result = null;
+
+ while (processDescendants.hasNext()) {
+ Element e = (Element) processDescendants.next();
+ name = e.getName();
+ if (name.equals(str)) {
+ result = e;
+ return result;
+ }
+ }
+ return result;
+
+ }
+
+ /**
+ * Method of extract triples (subclassOf, equivalent class) from OWL file
+ *
+ * @throws IOException IOException
+ */
+ public void getAllClass() throws IOException {
+ List<?> classElements = rootNode.getChildren("Class", Namespace.getNamespace("owl", owl_namespace));
+
+ for (int i = 0; i < classElements.size(); i++) {
+ Element classElement = (Element) classElements.get(i);
+ String className = classElement.getAttributeValue("about", Namespace.getNamespace("rdf", rdf_namespace));
+
+ if (className == null) {
+ className = classElement.getAttributeValue("ID", Namespace.getNamespace("rdf", rdf_namespace));
+ }
+
+ List<?> subclassElements = classElement.getChildren("subClassOf", Namespace.getNamespace("rdfs", rdfs_namespace));
+ for (int j = 0; j < subclassElements.size(); j++) {
+ Element subclassElement = (Element) subclassElements.get(j);
+ String subclassName = subclassElement.getAttributeValue("resource", Namespace.getNamespace("rdf", rdf_namespace));
+ if (subclassName == null) {
+ Element allValuesFromEle = findChild("allValuesFrom", subclassElement);
+ if (allValuesFromEle != null) {
+ subclassName = allValuesFromEle.getAttributeValue("resource", Namespace.getNamespace("rdf", rdf_namespace));
+ bw.write(cutString(className) + ",SubClassOf," + cutString(subclassName) + "\n");
+ }
+ } else {
+ bw.write(cutString(className) + ",SubClassOf," + cutString(subclassName) + "\n");
+ }
+
+ }
+
+ List equalClassElements = classElement.getChildren("equivalentClass", Namespace.getNamespace("owl", owl_namespace));
+ for (int k = 0; k < equalClassElements.size(); k++) {
+ Element equalClassElement = (Element) equalClassElements.get(k);
+ String equalClassElementName = equalClassElement.getAttributeValue("resource", Namespace.getNamespace("rdf", rdf_namespace));
+
+ if (equalClassElementName != null) {
+ bw.write(cutString(className) + ",equivalentClass," + cutString(equalClassElementName) + "\n");
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Method of cleaning up a string
+ *
+ * @param str String needed to be processed
+ * @return the processed string
+ */
+ public String cutString(String str) {
+ str = str.substring(str.indexOf("#") + 1);
+ String[] strArray = str.split("(?=[A-Z])");
+ str = Arrays.toString(strArray);
+ return str.substring(1, str.length() - 1).replace(",", "");
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/package-info.java
new file mode 100644
index 0000000..0570bc7
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/pre/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes ontology pre-processing classes.
+ */
+package gov.nasa.jpl.mudrod.ontology.pre;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipCOROntology.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipCOROntology.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipCOROntology.java
new file mode 100644
index 0000000..6194197
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipCOROntology.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
+
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+
+import java.util.Iterator;
+
+/**
+ * @author lewismc
+ */
+public class EsipCOROntology implements Ontology {
+
+ /**
+ *
+ */
+ public EsipCOROntology() {
+ //default constructor
+ }
+
+ @Override
+ public void load() {
+ // to be completed
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#load(java.lang.String[])
+ */
+ @Override
+ public void load(String[] urls) {
+ // to be completed
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#merge(Ontology)
+ */
+ @Override
+ public void merge(Ontology o) {
+ // to be completed
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#subclasses(java.lang.String)
+ */
+ @Override
+ public Iterator<String> subclasses(String entitySearchTerm) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#synonyms(java.lang.String)
+ */
+ @Override
+ public Iterator<String> synonyms(String queryKeyPhrase) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipPortalOntology.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipPortalOntology.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipPortalOntology.java
new file mode 100644
index 0000000..9c4888b
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/EsipPortalOntology.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
+
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+
+import java.util.Iterator;
+
+/**
+ * @author lewismc
+ */
+public class EsipPortalOntology implements Ontology {
+
+ /**
+ *
+ */
+ public EsipPortalOntology() {
+ //default constructor
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#load(java.lang.String[])
+ */
+ @Override
+ public void load(String[] urls) {
+ // to be completed
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#load()
+ */
+ @Override
+ public void load() {
+ // to be completed
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#merge(Ontology)
+ */
+ @Override
+ public void merge(Ontology o) {
+ // to be completed
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#subclasses(java.lang.String)
+ */
+ @Override
+ public Iterator<String> subclasses(String entitySearchTerm) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see Ontology#synonyms(java.lang.String)
+ */
+ @Override
+ public Iterator<String> synonyms(String queryKeyPhrase) {
+ return null;
+ }
+
+}
[05/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/angular-route.min.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/angular-route.min.js b/web/META-INF/resources/js/libs/angular-route.min.js
new file mode 100755
index 0000000..c6277a3
--- /dev/null
+++ b/web/META-INF/resources/js/libs/angular-route.min.js
@@ -0,0 +1,15 @@
+/*
+ AngularJS v1.3.7
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(p,d,C){'use strict';function v(r,h,g){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,y){function z(){k&&(g.cancel(k),k=null);l&&(l.$destroy(),l=null);m&&(k=g.leave(m),k.then(function(){k=null}),m=null)}function x(){var b=r.current&&r.current.locals;if(d.isDefined(b&&b.$template)){var b=a.$new(),f=r.current;m=y(b,function(b){g.enter(b,null,m||c).then(function(){!d.isDefined(t)||t&&!a.$eval(t)||h()});z()});l=f.scope=b;l.$emit("$viewContentLoaded");
+l.$eval(w)}else z()}var l,m,k,t=b.autoscroll,w=b.onload||"";a.$on("$routeChangeSuccess",x);x()}}}function A(d,h,g){return{restrict:"ECA",priority:-400,link:function(a,c){var b=g.current,f=b.locals;c.html(f.$template);var y=d(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));y(a)}}}p=d.module("ngRoute",["ng"]).provider("$route",function(){function r(a,c){return d.extend(Object.create(a),
+c)}function h(a,d){var b=d.caseInsensitiveMatch,f={originalPath:a,regexp:a},g=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,d,b,c){a="?"===c?c:null;c="*"===c?c:null;g.push({name:b,optional:!!a});d=d||"";return""+(a?"":d)+"(?:"+(a?d:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=new RegExp("^"+a+"$",b?"i":"");return f}var g={};this.when=function(a,c){var b=d.copy(c);d.isUndefined(b.reloadOnSearch)&&(b.reloadOnSearch=!0);
+d.isUndefined(b.caseInsensitiveMatch)&&(b.caseInsensitiveMatch=this.caseInsensitiveMatch);g[a]=d.extend(b,a&&h(a,b));if(a){var f="/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";g[f]=d.extend({redirectTo:a},h(f,b))}return this};this.caseInsensitiveMatch=!1;this.otherwise=function(a){"string"===typeof a&&(a={redirectTo:a});this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$templateRequest","$sce",function(a,c,b,f,h,p,x){function l(b){var e=s.current;
+(v=(n=k())&&e&&n.$$route===e.$$route&&d.equals(n.pathParams,e.pathParams)&&!n.reloadOnSearch&&!w)||!e&&!n||a.$broadcast("$routeChangeStart",n,e).defaultPrevented&&b&&b.preventDefault()}function m(){var u=s.current,e=n;if(v)u.params=e.params,d.copy(u.params,b),a.$broadcast("$routeUpdate",u);else if(e||u)w=!1,(s.current=e)&&e.redirectTo&&(d.isString(e.redirectTo)?c.path(t(e.redirectTo,e.params)).search(e.params).replace():c.url(e.redirectTo(e.pathParams,c.path(),c.search())).replace()),f.when(e).then(function(){if(e){var a=
+d.extend({},e.resolve),b,c;d.forEach(a,function(b,e){a[e]=d.isString(b)?h.get(b):h.invoke(b,null,null,e)});d.isDefined(b=e.template)?d.isFunction(b)&&(b=b(e.params)):d.isDefined(c=e.templateUrl)&&(d.isFunction(c)&&(c=c(e.params)),c=x.getTrustedResourceUrl(c),d.isDefined(c)&&(e.loadedTemplateUrl=c,b=p(c)));d.isDefined(b)&&(a.$template=b);return f.all(a)}}).then(function(c){e==s.current&&(e&&(e.locals=c,d.copy(e.params,b)),a.$broadcast("$routeChangeSuccess",e,u))},function(b){e==s.current&&a.$broadcast("$routeChangeError",
+e,u,b)})}function k(){var a,b;d.forEach(g,function(f,g){var q;if(q=!b){var h=c.path();q=f.keys;var l={};if(f.regexp)if(h=f.regexp.exec(h)){for(var k=1,m=h.length;k<m;++k){var n=q[k-1],p=h[k];n&&p&&(l[n.name]=p)}q=l}else q=null;else q=null;q=a=q}q&&(b=r(f,{params:d.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||g[null]&&r(g[null],{params:{},pathParams:{}})}function t(a,b){var c=[];d.forEach((a||"").split(":"),function(a,d){if(0===d)c.push(a);else{var f=a.match(/(\w+)(?:[?*])?(.*)/),
+g=f[1];c.push(b[g]);c.push(f[2]||"");delete b[g]}});return c.join("")}var w=!1,n,v,s={routes:g,reload:function(){w=!0;a.$evalAsync(function(){l();m()})},updateParams:function(a){if(this.current&&this.current.$$route){var b={},f=this;d.forEach(Object.keys(a),function(c){f.current.pathParams[c]||(b[c]=a[c])});a=d.extend({},this.current.params,a);c.path(t(this.current.$$route.originalPath,a));c.search(d.extend({},c.search(),b))}else throw B("norout");}};a.$on("$locationChangeStart",l);a.$on("$locationChangeSuccess",
+m);return s}]});var B=d.$$minErr("ngRoute");p.provider("$routeParams",function(){this.$get=function(){return{}}});p.directive("ngView",v);p.directive("ngView",A);v.$inject=["$route","$anchorScroll","$animate"];A.$inject=["$compile","$controller","$route"]})(window,window.angular);
+//# sourceMappingURL=angular-route.min.js.map
[08/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/fonts/glyphicons-halflings-regular.svg
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/fonts/glyphicons-halflings-regular.svg b/web/META-INF/resources/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..dcac3ae
--- /dev/null
+++ b/web/META-INF/resources/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,550 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+ <metadata></metadata>
+ <defs>
+ <font id="glyphicons_halflingsregular" horiz-adv-x="1200">
+ <font-face units-per-em="1200" ascent="960" descent="-240"/>
+ <missing-glyph horiz-adv-x="500"/>
+ <glyph horiz-adv-x="0"/>
+ <glyph horiz-adv-x="400"/>
+ <glyph unicode=" "/>
+ <glyph unicode="*"
+ d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z"/>
+ <glyph unicode="+"
+ d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=" "/>
+ <glyph unicode="¥"
+ d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z"/>
+ <glyph unicode=" " horiz-adv-x="650"/>
+ <glyph unicode=" " horiz-adv-x="1300"/>
+ <glyph unicode=" " horiz-adv-x="650"/>
+ <glyph unicode=" " horiz-adv-x="1300"/>
+ <glyph unicode=" " horiz-adv-x="433"/>
+ <glyph unicode=" " horiz-adv-x="325"/>
+ <glyph unicode=" " horiz-adv-x="216"/>
+ <glyph unicode=" " horiz-adv-x="216"/>
+ <glyph unicode=" " horiz-adv-x="162"/>
+ <glyph unicode=" " horiz-adv-x="260"/>
+ <glyph unicode=" " horiz-adv-x="72"/>
+ <glyph unicode=" " horiz-adv-x="260"/>
+ <glyph unicode=" " horiz-adv-x="325"/>
+ <glyph unicode="€"
+ d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z"/>
+ <glyph unicode="₽"
+ d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z"/>
+ <glyph unicode="−"
+ d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode="⌛"
+ d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z"/>
+ <glyph unicode="◼" horiz-adv-x="500" d="M0 0z"/>
+ <glyph unicode="☁"
+ d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z"/>
+ <glyph unicode="⛺"
+ d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z "/>
+ <glyph unicode="✉"
+ d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z"/>
+ <glyph unicode="✏"
+ d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z"/>
+ <glyph unicode=""
+ d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z"/>
+ <glyph unicode=""
+ d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z"/>
+ <glyph unicode=""
+ d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z"/>
+ <glyph unicode=""
+ d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z"/>
+ <glyph unicode=""
+ d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z"/>
+ <glyph unicode=""
+ d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z"/>
+ <glyph unicode=""
+ d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z"/>
+ <glyph unicode=""
+ d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z"/>
+ <glyph unicode=""
+ d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200
q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z"/>
+ <glyph unicode=""
+ d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z"/>
+ <glyph unicode=""
+ d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z"/>
+ <glyph unicode=""
+ d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z"/>
+ <glyph unicode=""
+ d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z"/>
+ <glyph unicode=""
+ d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z"/>
+ <glyph unicode=""
+ d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z"/>
+ <glyph unicode=""
+ d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z"/>
+ <glyph unicode=""
+ d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z"/>
+ <glyph unicode=""
+ d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z"/>
+ <glyph unicode=""
+ d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z"/>
+ <glyph unicode=""
+ d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z "/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z"/>
+ <glyph unicode=""
+ d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z"/>
+ <glyph unicode=""
+ d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z"/>
+ <glyph unicode=""
+ d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z"/>
+ <glyph unicode=""
+ d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10
0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z"/>
+ <glyph unicode=""
+ d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z"/>
+ <glyph unicode=""
+ d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z"/>
+ <glyph unicode=""
+ d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z"/>
+ <glyph unicode=""
+ d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z"/>
+ <glyph unicode=""
+ d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z"/>
+ <glyph unicode=""
+ d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z"/>
+ <glyph unicode=""
+ d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z"/>
+ <glyph unicode=""
+ d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z"/>
+ <glyph unicode=""
+ d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z"/>
+ <glyph unicode=""
+ d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z"/>
+ <glyph unicode=""
+ d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z"/>
+ <glyph unicode=""
+ d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z"/>
+ <glyph unicode=""
+ d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z"/>
+ <glyph unicode=""
+ d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z"/>
+ <glyph unicode=""
+ d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z"/>
+ <glyph unicode=""
+ d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z"/>
+ <glyph unicode=""
+ d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z"/>
+ <glyph unicode=""
+ d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z"/>
+ <glyph unicode=""
+ d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z"/>
+ <glyph unicode=""
+ d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q2
1 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z"/>
+ <glyph unicode=""
+ d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z"/>
+ <glyph unicode=""
+ d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z"/>
+ <glyph unicode=""
+ d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z"/>
+ <glyph unicode=""
+ d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z"/>
+ <glyph unicode=""
+ d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z"/>
+ <glyph unicode=""
+ d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z"/>
+ <glyph unicode=""
+ d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z"/>
+ <glyph unicode=""
+ d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z"/>
+ <glyph unicode=""
+ d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z"/>
+ <glyph unicode=""
+ d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z"/>
+ <glyph unicode=""
+ d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z"/>
+ <glyph unicode=""
+ d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z"/>
+ <glyph unicode=""
+ d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z"/>
+ <glyph unicode=""
+ d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z"/>
+ <glyph unicode=""
+ d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z"/>
+ <glyph unicode=""
+ d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z"/>
+ <glyph unicode=""
+ d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z"/>
+ <glyph unicode=""
+ d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z"/>
+ <glyph unicode=""
+ d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z"/>
+ <glyph unicode=""
+ d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z"/>
+ <glyph unicode=""
+ d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z"/>
+ <glyph unicode=""
+ d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z"/>
+ <glyph unicode=""
+ d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z"/>
+ <glyph unicode=""
+ d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z"/>
+ <glyph unicode=""
+ d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z"/>
+ <glyph unicode=""
+ d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z"/>
+ <glyph unicode=""
+ d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z"/>
+ <glyph unicode=""
+ d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z"/>
+ <glyph unicode=""
+ d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z"/>
+ <glyph unicode=""
+ d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z"/>
+ <glyph unicode=""
+ d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z"/>
+ <glyph unicode=""
+ d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z"/>
+ <glyph unicode=""
+ d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z"/>
+ <glyph unicode=""
+ d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z"/>
+ <glyph unicode=""
+ d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z"/>
+ <glyph unicode=""
+ d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z"/>
+ <glyph unicode=""
+ d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z"/>
+ <glyph unicode=""
+ d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z"/>
+ <glyph unicode=""
+ d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z"/>
+ <glyph unicode=""
+ d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z"/>
+ <glyph unicode=""
+ d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z"/>
+ <glyph unicode=""
+ d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z"/>
+ <glyph unicode=""
+ d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z"/>
+ <glyph unicode=""
+ d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z"/>
+ <glyph unicode=""
+ d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z"/>
+ <glyph unicode=""
+ d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z"/>
+ <glyph unicode=""
+ d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z"/>
+ <glyph unicode=""
+ d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z"/>
+ <glyph unicode=""
+ d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z"/>
+ <glyph unicode=""
+ d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z"/>
+ <glyph unicode=""
+ d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.
5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z"/>
+ <glyph unicode=""
+ d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z"/>
+ <glyph unicode="" horiz-adv-x="1220"
+ d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z "/>
+ <glyph unicode=""
+ d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z"/>
+ <glyph unicode=""
+ d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z"/>
+ <glyph unicode=""
+ d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z"/>
+ <glyph unicode=""
+ d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z"/>
+ <glyph unicode=""
+ d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z"/>
+ <glyph unicode=""
+ d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z"/>
+ <glyph unicode=""
+ d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z"/>
+ <glyph unicode=""
+ d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z"/>
+ <glyph unicode=""
+ d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z"/>
+ <glyph unicode=""
+ d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z"/>
+ <glyph unicode=""
+ d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z"/>
+ <glyph unicode=""
+ d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z"/>
+ <glyph unicode=""
+ d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z "/>
+ <glyph unicode=""
+ d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z "/>
+ <glyph unicode=""
+ d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z"/>
+ <glyph unicode=""
+ d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z"/>
+ <glyph unicode=""
+ d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z"/>
+ <glyph unicode=""
+ d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z"/>
+ <glyph unicode=""
+ d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z"/>
+ <glyph unicode=""
+ d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z"/>
+ <glyph unicode=""
+ d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z"/>
+ <glyph unicode=""
+ d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z"/>
+ <glyph unicode=""
+ d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z"/>
+ <glyph unicode=""
+ d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z"/>
+ <glyph unicode=""
+ d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z"/>
+ <glyph unicode=""
+ d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z"/>
+ <glyph unicode=""
+ d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z"/>
+ <glyph unicode=""
+ d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z"/>
+ <glyph unicode=""
+ d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z"/>
+ <glyph unicode=""
+ d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z"/>
+ <glyph unicode=""
+ d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z"/>
+ <glyph unicode=""
+ d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z"/>
+ <glyph unicode=""
+ d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z"/>
+ <glyph unicode=""
+ d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z"/>
+ <glyph unicode=""
+ d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z"/>
+ <glyph unicode=""
+ d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z"/>
+ <glyph unicode=""
+ d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z"/>
+ <glyph unicode=""
+ d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z"/>
+ <glyph unicode=""
+ d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z"/>
+ <glyph unicode=""
+ d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z"/>
+ <glyph unicode=""
+ d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z"/>
+ <glyph unicode=""
+ d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z"/>
+ <glyph unicode=""
+ d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z"/>
+ <glyph unicode=""
+ d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z"/>
+ <glyph unicode=""
+ d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z"/>
+ <glyph unicode=""
+ d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z "/>
+ <glyph unicode=""
+ d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z"/>
+ <glyph unicode=""
+ d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z"/>
+ <glyph unicode=""
+
<TRUNCATED>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/fonts/glyphicons-halflings-regular.ttf
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/fonts/glyphicons-halflings-regular.ttf b/web/META-INF/resources/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..1413fc6
Binary files /dev/null and b/web/META-INF/resources/fonts/glyphicons-halflings-regular.ttf differ
[04/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/angular.min.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/angular.min.js b/web/META-INF/resources/js/libs/angular.min.js
new file mode 100755
index 0000000..a9745e6
--- /dev/null
+++ b/web/META-INF/resources/js/libs/angular.min.js
@@ -0,0 +1,250 @@
+/*
+ AngularJS v1.3.7
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(M,Y,t){'use strict';function T(b){return function(){var a=arguments[0],c;c="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.3.7/"+(b?b+"/":"")+a;for(a=1;a<arguments.length;a++){c=c+(1==a?"?":"&")+"p"+(a-1)+"=";var d=encodeURIComponent,e;e=arguments[a];e="function"==typeof e?e.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof e?"undefined":"string"!=typeof e?JSON.stringify(e):e;c+=d(e)}return Error(c)}}function Sa(b){if(null==b||Ta(b))return!1;var a=b.length;return b.nodeType===
+na&&a?!0:H(b)||x(b)||0===a||"number"===typeof a&&0<a&&a-1 in b}function s(b,a,c){var d,e;if(b)if(G(b))for(d in b)"prototype"==d||"length"==d||"name"==d||b.hasOwnProperty&&!b.hasOwnProperty(d)||a.call(c,b[d],d,b);else if(x(b)||Sa(b)){var f="object"!==typeof b;d=0;for(e=b.length;d<e;d++)(f||d in b)&&a.call(c,b[d],d,b)}else if(b.forEach&&b.forEach!==s)b.forEach(a,c,b);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d,b);return b}function Ed(b,a,c){for(var d=Object.keys(b).sort(),e=0;e<d.length;e++)a.call(c,
+b[d[e]],d[e]);return d}function kc(b){return function(a,c){b(c,a)}}function Fd(){return++nb}function lc(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function z(b){for(var a=b.$$hashKey,c=1,d=arguments.length;c<d;c++){var e=arguments[c];if(e)for(var f=Object.keys(e),g=0,h=f.length;g<h;g++){var l=f[g];b[l]=e[l]}}lc(b,a);return b}function ba(b){return parseInt(b,10)}function C(){}function oa(b){return b}function da(b){return function(){return b}}function D(b){return"undefined"===typeof b}function y(b){return"undefined"!==
+typeof b}function P(b){return null!==b&&"object"===typeof b}function H(b){return"string"===typeof b}function V(b){return"number"===typeof b}function pa(b){return"[object Date]"===Da.call(b)}function G(b){return"function"===typeof b}function ob(b){return"[object RegExp]"===Da.call(b)}function Ta(b){return b&&b.window===b}function Ua(b){return b&&b.$evalAsync&&b.$watch}function Va(b){return"boolean"===typeof b}function mc(b){return!(!b||!(b.nodeName||b.prop&&b.attr&&b.find))}function Gd(b){var a={};
+b=b.split(",");var c;for(c=0;c<b.length;c++)a[b[c]]=!0;return a}function ua(b){return Q(b.nodeName||b[0]&&b[0].nodeName)}function Wa(b,a){var c=b.indexOf(a);0<=c&&b.splice(c,1);return a}function Ea(b,a,c,d){if(Ta(b)||Ua(b))throw Ja("cpws");if(a){if(b===a)throw Ja("cpi");c=c||[];d=d||[];if(P(b)){var e=c.indexOf(b);if(-1!==e)return d[e];c.push(b);d.push(a)}if(x(b))for(var f=a.length=0;f<b.length;f++)e=Ea(b[f],null,c,d),P(b[f])&&(c.push(b[f]),d.push(e)),a.push(e);else{var g=a.$$hashKey;x(a)?a.length=
+0:s(a,function(b,c){delete a[c]});for(f in b)b.hasOwnProperty(f)&&(e=Ea(b[f],null,c,d),P(b[f])&&(c.push(b[f]),d.push(e)),a[f]=e);lc(a,g)}}else if(a=b)x(b)?a=Ea(b,[],c,d):pa(b)?a=new Date(b.getTime()):ob(b)?(a=new RegExp(b.source,b.toString().match(/[^\/]*$/)[0]),a.lastIndex=b.lastIndex):P(b)&&(e=Object.create(Object.getPrototypeOf(b)),a=Ea(b,e,c,d));return a}function qa(b,a){if(x(b)){a=a||[];for(var c=0,d=b.length;c<d;c++)a[c]=b[c]}else if(P(b))for(c in a=a||{},b)if("$"!==c.charAt(0)||"$"!==c.charAt(1))a[c]=
+b[c];return a||b}function fa(b,a){if(b===a)return!0;if(null===b||null===a)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&"object"==c)if(x(b)){if(!x(a))return!1;if((c=b.length)==a.length){for(d=0;d<c;d++)if(!fa(b[d],a[d]))return!1;return!0}}else{if(pa(b))return pa(a)?fa(b.getTime(),a.getTime()):!1;if(ob(b)&&ob(a))return b.toString()==a.toString();if(Ua(b)||Ua(a)||Ta(b)||Ta(a)||x(a))return!1;c={};for(d in b)if("$"!==d.charAt(0)&&!G(b[d])){if(!fa(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c.hasOwnProperty(d)&&
+"$"!==d.charAt(0)&&a[d]!==t&&!G(a[d]))return!1;return!0}return!1}function Xa(b,a,c){return b.concat(Ya.call(a,c))}function nc(b,a){var c=2<arguments.length?Ya.call(arguments,2):[];return!G(a)||a instanceof RegExp?a:c.length?function(){return arguments.length?a.apply(b,Xa(c,arguments,0)):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}}function Hd(b,a){var c=a;"string"===typeof b&&"$"===b.charAt(0)&&"$"===b.charAt(1)?c=t:Ta(a)?c="$WINDOW":a&&Y===a?c="$DOCUMENT":Ua(a)&&
+(c="$SCOPE");return c}function Za(b,a){if("undefined"===typeof b)return t;V(a)||(a=a?2:null);return JSON.stringify(b,Hd,a)}function oc(b){return H(b)?JSON.parse(b):b}function va(b){b=B(b).clone();try{b.empty()}catch(a){}var c=B("<div>").append(b).html();try{return b[0].nodeType===pb?Q(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+Q(b)})}catch(d){return Q(c)}}function pc(b){try{return decodeURIComponent(b)}catch(a){}}function qc(b){var a={},c,d;s((b||"").split("&"),function(b){b&&
+(c=b.replace(/\+/g,"%20").split("="),d=pc(c[0]),y(d)&&(b=y(c[1])?pc(c[1]):!0,rc.call(a,d)?x(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Nb(b){var a=[];s(b,function(b,d){x(b)?s(b,function(b){a.push(Fa(d,!0)+(!0===b?"":"="+Fa(b,!0)))}):a.push(Fa(d,!0)+(!0===b?"":"="+Fa(b,!0)))});return a.length?a.join("&"):""}function qb(b){return Fa(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Fa(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,
+":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,a?"%20":"+")}function Id(b,a){var c,d,e=rb.length;b=B(b);for(d=0;d<e;++d)if(c=rb[d]+a,H(c=b.attr(c)))return c;return null}function Jd(b,a){var c,d,e={};s(rb,function(a){a+="app";!c&&b.hasAttribute&&b.hasAttribute(a)&&(c=b,d=b.getAttribute(a))});s(rb,function(a){a+="app";var e;!c&&(e=b.querySelector("["+a.replace(":","\\:")+"]"))&&(c=e,d=e.getAttribute(a))});c&&(e.strictDi=null!==Id(c,"strict-di"),a(c,d?[d]:[],e))}function sc(b,
+a,c){P(c)||(c={});c=z({strictDi:!1},c);var d=function(){b=B(b);if(b.injector()){var d=b[0]===Y?"document":va(b);throw Ja("btstrpd",d.replace(/</,"<").replace(/>/,">"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);c.debugInfoEnabled&&a.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);a.unshift("ng");d=Ob(a,c.strictDi);d.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return d},
+e=/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;M&&e.test(M.name)&&(c.debugInfoEnabled=!0,M.name=M.name.replace(e,""));if(M&&!f.test(M.name))return d();M.name=M.name.replace(f,"");ga.resumeBootstrap=function(b){s(b,function(b){a.push(b)});d()}}function Kd(){M.name="NG_ENABLE_DEBUG_INFO!"+M.name;M.location.reload()}function Ld(b){b=ga.element(b).injector();if(!b)throw Ja("test");return b.get("$$testability")}function tc(b,a){a=a||"_";return b.replace(Md,function(b,d){return(d?a:"")+b.toLowerCase()})}
+function Nd(){var b;uc||((ra=M.jQuery)&&ra.fn.on?(B=ra,z(ra.fn,{scope:Ka.scope,isolateScope:Ka.isolateScope,controller:Ka.controller,injector:Ka.injector,inheritedData:Ka.inheritedData}),b=ra.cleanData,ra.cleanData=function(a){var c;if(Pb)Pb=!1;else for(var d=0,e;null!=(e=a[d]);d++)(c=ra._data(e,"events"))&&c.$destroy&&ra(e).triggerHandler("$destroy");b(a)}):B=R,ga.element=B,uc=!0)}function Qb(b,a,c){if(!b)throw Ja("areq",a||"?",c||"required");return b}function sb(b,a,c){c&&x(b)&&(b=b[b.length-1]);
+Qb(G(b),a,"not a function, got "+(b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function La(b,a){if("hasOwnProperty"===b)throw Ja("badname",a);}function vc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g<f;g++)d=a[g],b&&(b=(e=b)[d]);return!c&&G(b)?nc(e,b):b}function tb(b){var a=b[0];b=b[b.length-1];var c=[a];do{a=a.nextSibling;if(!a)break;c.push(a)}while(a!==b);return B(c)}function ha(){return Object.create(null)}function Od(b){function a(a,b,c){return a[b]||
+(a[b]=c())}var c=T("$injector"),d=T("ng");b=a(b,"angular",Object);b.$$minErr=b.$$minErr||T;return a(b,"module",function(){var b={};return function(f,g,h){if("hasOwnProperty"===f)throw d("badname","module");g&&b.hasOwnProperty(f)&&(b[f]=null);return a(b,f,function(){function a(c,d,e,f){f||(f=b);return function(){f[e||"push"]([c,d,arguments]);return u}}if(!g)throw c("nomod",f);var b=[],d=[],e=[],q=a("$injector","invoke","push",d),u={_invokeQueue:b,_configBlocks:d,_runBlocks:e,requires:g,name:f,provider:a("$provide",
+"provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),animation:a("$animateProvider","register"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:q,run:function(a){e.push(a);return this}};h&&q(h);return u})}})}function Pd(b){z(b,{bootstrap:sc,copy:Ea,extend:z,equals:fa,element:B,forEach:s,injector:Ob,noop:C,bind:nc,toJson:Za,
+fromJson:oc,identity:oa,isUndefined:D,isDefined:y,isString:H,isFunction:G,isObject:P,isNumber:V,isElement:mc,isArray:x,version:Qd,isDate:pa,lowercase:Q,uppercase:ub,callbacks:{counter:0},getTestability:Ld,$$minErr:T,$$csp:$a,reloadWithDebugInfo:Kd});ab=Od(M);try{ab("ngLocale")}catch(a){ab("ngLocale",[]).provider("$locale",Rd)}ab("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:Sd});a.provider("$compile",wc).directive({a:Td,input:xc,textarea:xc,form:Ud,script:Vd,select:Wd,style:Xd,
+option:Yd,ngBind:Zd,ngBindHtml:$d,ngBindTemplate:ae,ngClass:be,ngClassEven:ce,ngClassOdd:de,ngCloak:ee,ngController:fe,ngForm:ge,ngHide:he,ngIf:ie,ngInclude:je,ngInit:ke,ngNonBindable:le,ngPluralize:me,ngRepeat:ne,ngShow:oe,ngStyle:pe,ngSwitch:qe,ngSwitchWhen:re,ngSwitchDefault:se,ngOptions:te,ngTransclude:ue,ngModel:ve,ngList:we,ngChange:xe,pattern:yc,ngPattern:yc,required:zc,ngRequired:zc,minlength:Ac,ngMinlength:Ac,maxlength:Bc,ngMaxlength:Bc,ngValue:ye,ngModelOptions:ze}).directive({ngInclude:Ae}).directive(vb).directive(Cc);
+a.provider({$anchorScroll:Be,$animate:Ce,$browser:De,$cacheFactory:Ee,$controller:Fe,$document:Ge,$exceptionHandler:He,$filter:Dc,$interpolate:Ie,$interval:Je,$http:Ke,$httpBackend:Le,$location:Me,$log:Ne,$parse:Oe,$rootScope:Pe,$q:Qe,$$q:Re,$sce:Se,$sceDelegate:Te,$sniffer:Ue,$templateCache:Ve,$templateRequest:We,$$testability:Xe,$timeout:Ye,$window:Ze,$$rAF:$e,$$asyncCallback:af,$$jqLite:bf})}])}function bb(b){return b.replace(cf,function(a,b,d,e){return e?d.toUpperCase():d}).replace(df,"Moz$1")}
+function Ec(b){b=b.nodeType;return b===na||!b||9===b}function Fc(b,a){var c,d,e=a.createDocumentFragment(),f=[];if(Rb.test(b)){c=c||e.appendChild(a.createElement("div"));d=(ef.exec(b)||["",""])[1].toLowerCase();d=ia[d]||ia._default;c.innerHTML=d[1]+b.replace(ff,"<$1></$2>")+d[2];for(d=d[0];d--;)c=c.lastChild;f=Xa(f,c.childNodes);c=e.firstChild;c.textContent=""}else f.push(a.createTextNode(b));e.textContent="";e.innerHTML="";s(f,function(a){e.appendChild(a)});return e}function R(b){if(b instanceof
+R)return b;var a;H(b)&&(b=U(b),a=!0);if(!(this instanceof R)){if(a&&"<"!=b.charAt(0))throw Sb("nosel");return new R(b)}if(a){a=Y;var c;b=(c=gf.exec(b))?[a.createElement(c[1])]:(c=Fc(b,a))?c.childNodes:[]}Gc(this,b)}function Tb(b){return b.cloneNode(!0)}function wb(b,a){a||xb(b);if(b.querySelectorAll)for(var c=b.querySelectorAll("*"),d=0,e=c.length;d<e;d++)xb(c[d])}function Hc(b,a,c,d){if(y(d))throw Sb("offargs");var e=(d=yb(b))&&d.events,f=d&&d.handle;if(f)if(a)s(a.split(" "),function(a){if(y(c)){var d=
+e[a];Wa(d||[],c);if(d&&0<d.length)return}b.removeEventListener(a,f,!1);delete e[a]});else for(a in e)"$destroy"!==a&&b.removeEventListener(a,f,!1),delete e[a]}function xb(b,a){var c=b.ng339,d=c&&zb[c];d&&(a?delete d.data[a]:(d.handle&&(d.events.$destroy&&d.handle({},"$destroy"),Hc(b)),delete zb[c],b.ng339=t))}function yb(b,a){var c=b.ng339,c=c&&zb[c];a&&!c&&(b.ng339=c=++hf,c=zb[c]={events:{},data:{},handle:t});return c}function Ub(b,a,c){if(Ec(b)){var d=y(c),e=!d&&a&&!P(a),f=!a;b=(b=yb(b,!e))&&b.data;
+if(d)b[a]=c;else{if(f)return b;if(e)return b&&b[a];z(b,a)}}}function Ab(b,a){return b.getAttribute?-1<(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" "):!1}function Bb(b,a){a&&b.setAttribute&&s(a.split(" "),function(a){b.setAttribute("class",U((" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").replace(" "+U(a)+" "," ")))})}function Cb(b,a){if(a&&b.setAttribute){var c=(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");s(a.split(" "),function(a){a=
+U(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});b.setAttribute("class",U(c))}}function Gc(b,a){if(a)if(a.nodeType)b[b.length++]=a;else{var c=a.length;if("number"===typeof c&&a.window!==a){if(c)for(var d=0;d<c;d++)b[b.length++]=a[d]}else b[b.length++]=a}}function Ic(b,a){return Db(b,"$"+(a||"ngController")+"Controller")}function Db(b,a,c){9==b.nodeType&&(b=b.documentElement);for(a=x(a)?a:[a];b;){for(var d=0,e=a.length;d<e;d++)if((c=B.data(b,a[d]))!==t)return c;b=b.parentNode||11===b.nodeType&&b.host}}
+function Jc(b){for(wb(b,!0);b.firstChild;)b.removeChild(b.firstChild)}function Kc(b,a){a||wb(b);var c=b.parentNode;c&&c.removeChild(b)}function jf(b,a){a=a||M;if("complete"===a.document.readyState)a.setTimeout(b);else B(a).on("load",b)}function Lc(b,a){var c=Eb[a.toLowerCase()];return c&&Mc[ua(b)]&&c}function kf(b,a){var c=b.nodeName;return("INPUT"===c||"TEXTAREA"===c)&&Nc[a]}function lf(b,a){var c=function(c,e){c.isDefaultPrevented=function(){return c.defaultPrevented};var f=a[e||c.type],g=f?f.length:
+0;if(g){if(D(c.immediatePropagationStopped)){var h=c.stopImmediatePropagation;c.stopImmediatePropagation=function(){c.immediatePropagationStopped=!0;c.stopPropagation&&c.stopPropagation();h&&h.call(c)}}c.isImmediatePropagationStopped=function(){return!0===c.immediatePropagationStopped};1<g&&(f=qa(f));for(var l=0;l<g;l++)c.isImmediatePropagationStopped()||f[l].call(b,c)}};c.elem=b;return c}function bf(){this.$get=function(){return z(R,{hasClass:function(b,a){b.attr&&(b=b[0]);return Ab(b,a)},addClass:function(b,
+a){b.attr&&(b=b[0]);return Cb(b,a)},removeClass:function(b,a){b.attr&&(b=b[0]);return Bb(b,a)}})}}function Ma(b,a){var c=b&&b.$$hashKey;if(c)return"function"===typeof c&&(c=b.$$hashKey()),c;c=typeof b;return c="function"==c||"object"==c&&null!==b?b.$$hashKey=c+":"+(a||Fd)():c+":"+b}function cb(b,a){if(a){var c=0;this.nextUid=function(){return++c}}s(b,this.put,this)}function mf(b){return(b=b.toString().replace(Oc,"").match(Pc))?"function("+(b[1]||"").replace(/[\s\r\n]+/," ")+")":"fn"}function Vb(b,
+a,c){var d;if("function"===typeof b){if(!(d=b.$inject)){d=[];if(b.length){if(a)throw H(c)&&c||(c=b.name||mf(b)),Ga("strictdi",c);a=b.toString().replace(Oc,"");a=a.match(Pc);s(a[1].split(nf),function(a){a.replace(of,function(a,b,c){d.push(c)})})}b.$inject=d}}else x(b)?(a=b.length-1,sb(b[a],"fn"),d=b.slice(0,a)):sb(b,"fn",!0);return d}function Ob(b,a){function c(a){return function(b,c){if(P(b))s(b,kc(a));else return a(b,c)}}function d(a,b){La(a,"service");if(G(b)||x(b))b=q.instantiate(b);if(!b.$get)throw Ga("pget",
+a);return n[a+"Provider"]=b}function e(a,b){return function(){var c=r.invoke(b,this);if(D(c))throw Ga("undef",a);return c}}function f(a,b,c){return d(a,{$get:!1!==c?e(a,b):b})}function g(a){var b=[],c;s(a,function(a){function d(a){var b,c;b=0;for(c=a.length;b<c;b++){var e=a[b],f=q.get(e[0]);f[e[1]].apply(f,e[2])}}if(!m.get(a)){m.put(a,!0);try{H(a)?(c=ab(a),b=b.concat(g(c.requires)).concat(c._runBlocks),d(c._invokeQueue),d(c._configBlocks)):G(a)?b.push(q.invoke(a)):x(a)?b.push(q.invoke(a)):sb(a,"module")}catch(e){throw x(a)&&
+(a=a[a.length-1]),e.message&&e.stack&&-1==e.stack.indexOf(e.message)&&(e=e.message+"\n"+e.stack),Ga("modulerr",a,e.stack||e.message||e);}}});return b}function h(b,c){function d(a,e){if(b.hasOwnProperty(a)){if(b[a]===l)throw Ga("cdep",a+" <- "+k.join(" <- "));return b[a]}try{return k.unshift(a),b[a]=l,b[a]=c(a,e)}catch(f){throw b[a]===l&&delete b[a],f;}finally{k.shift()}}function e(b,c,f,g){"string"===typeof f&&(g=f,f=null);var k=[],h=Vb(b,a,g),l,q,n;q=0;for(l=h.length;q<l;q++){n=h[q];if("string"!==
+typeof n)throw Ga("itkn",n);k.push(f&&f.hasOwnProperty(n)?f[n]:d(n,g))}x(b)&&(b=b[l]);return b.apply(c,k)}return{invoke:e,instantiate:function(a,b,c){var d=Object.create((x(a)?a[a.length-1]:a).prototype);a=e(a,d,b,c);return P(a)||G(a)?a:d},get:d,annotate:Vb,has:function(a){return n.hasOwnProperty(a+"Provider")||b.hasOwnProperty(a)}}}a=!0===a;var l={},k=[],m=new cb([],!0),n={$provide:{provider:c(d),factory:c(f),service:c(function(a,b){return f(a,["$injector",function(a){return a.instantiate(b)}])}),
+value:c(function(a,b){return f(a,da(b),!1)}),constant:c(function(a,b){La(a,"constant");n[a]=b;u[a]=b}),decorator:function(a,b){var c=q.get(a+"Provider"),d=c.$get;c.$get=function(){var a=r.invoke(d,c);return r.invoke(b,null,{$delegate:a})}}}},q=n.$injector=h(n,function(a,b){ga.isString(b)&&k.push(b);throw Ga("unpr",k.join(" <- "));}),u={},r=u.$injector=h(u,function(a,b){var c=q.get(a+"Provider",b);return r.invoke(c.$get,c,t,a)});s(g(b),function(a){r.invoke(a||C)});return r}function Be(){var b=!0;this.disableAutoScrolling=
+function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;Array.prototype.some.call(a,function(a){if("a"===ua(a))return b=a,!0});return b}function f(b){if(b){b.scrollIntoView();var c;c=g.yOffset;G(c)?c=c():mc(c)?(c=c[0],c="fixed"!==a.getComputedStyle(c).position?0:c.getBoundingClientRect().bottom):V(c)||(c=0);c&&(b=b.getBoundingClientRect().top,a.scrollBy(0,b-c))}else a.scrollTo(0,0)}function g(){var a=c.hash(),b;a?(b=h.getElementById(a))?f(b):(b=e(h.getElementsByName(a)))?
+f(b):"top"===a&&f(null):f(null)}var h=a.document;b&&d.$watch(function(){return c.hash()},function(a,b){a===b&&""===a||jf(function(){d.$evalAsync(g)})});return g}]}function af(){this.$get=["$$rAF","$timeout",function(b,a){return b.supported?function(a){return b(a)}:function(b){return a(b,0,!1)}}]}function pf(b,a,c,d){function e(a){try{a.apply(null,Ya.call(arguments,1))}finally{if(v--,0===v)for(;w.length;)try{w.pop()()}catch(b){c.error(b)}}}function f(a,b){(function N(){s(L,function(a){a()});J=b(N,
+a)})()}function g(){h();l()}function h(){A=b.history.state;A=D(A)?null:A;fa(A,I)&&(A=I);I=A}function l(){if(E!==m.url()||F!==A)E=m.url(),F=A,s(W,function(a){a(m.url(),A)})}function k(a){try{return decodeURIComponent(a)}catch(b){return a}}var m=this,n=a[0],q=b.location,u=b.history,r=b.setTimeout,O=b.clearTimeout,p={};m.isMock=!1;var v=0,w=[];m.$$completeOutstandingRequest=e;m.$$incOutstandingRequestCount=function(){v++};m.notifyWhenNoOutstandingRequests=function(a){s(L,function(a){a()});0===v?a():
+w.push(a)};var L=[],J;m.addPollFn=function(a){D(J)&&f(100,r);L.push(a);return a};var A,F,E=q.href,S=a.find("base"),X=null;h();F=A;m.url=function(a,c,e){D(e)&&(e=null);q!==b.location&&(q=b.location);u!==b.history&&(u=b.history);if(a){var f=F===e;if(E===a&&(!d.history||f))return m;var g=E&&Ha(E)===Ha(a);E=a;F=e;!d.history||g&&f?(g||(X=a),c?q.replace(a):g?(c=q,e=a.indexOf("#"),a=-1===e?"":a.substr(e+1),c.hash=a):q.href=a):(u[c?"replaceState":"pushState"](e,"",a),h(),F=A);return m}return X||q.href.replace(/%27/g,
+"'")};m.state=function(){return A};var W=[],wa=!1,I=null;m.onUrlChange=function(a){if(!wa){if(d.history)B(b).on("popstate",g);B(b).on("hashchange",g);wa=!0}W.push(a);return a};m.$$checkUrlChange=l;m.baseHref=function(){var a=S.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};var ea={},y="",ca=m.baseHref();m.cookies=function(a,b){var d,e,f,g;if(a)b===t?n.cookie=encodeURIComponent(a)+"=;path="+ca+";expires=Thu, 01 Jan 1970 00:00:00 GMT":H(b)&&(d=(n.cookie=encodeURIComponent(a)+"="+encodeURIComponent(b)+
+";path="+ca).length+1,4096<d&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"));else{if(n.cookie!==y)for(y=n.cookie,d=y.split("; "),ea={},f=0;f<d.length;f++)e=d[f],g=e.indexOf("="),0<g&&(a=k(e.substring(0,g)),ea[a]===t&&(ea[a]=k(e.substring(g+1))));return ea}};m.defer=function(a,b){var c;v++;c=r(function(){delete p[c];e(a)},b||0);p[c]=!0;return c};m.defer.cancel=function(a){return p[a]?(delete p[a],O(a),e(C),!0):!1}}function De(){this.$get=["$window",
+"$log","$sniffer","$document",function(b,a,c,d){return new pf(b,d,a,c)}]}function Ee(){this.$get=function(){function b(b,d){function e(a){a!=n&&(q?q==a&&(q=a.n):q=a,f(a.n,a.p),f(a,n),n=a,n.n=null)}function f(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(b in a)throw T("$cacheFactory")("iid",b);var g=0,h=z({},d,{id:b}),l={},k=d&&d.capacity||Number.MAX_VALUE,m={},n=null,q=null;return a[b]={put:function(a,b){if(k<Number.MAX_VALUE){var c=m[a]||(m[a]={key:a});e(c)}if(!D(b))return a in l||g++,l[a]=b,g>k&&this.remove(q.key),
+b},get:function(a){if(k<Number.MAX_VALUE){var b=m[a];if(!b)return;e(b)}return l[a]},remove:function(a){if(k<Number.MAX_VALUE){var b=m[a];if(!b)return;b==n&&(n=b.p);b==q&&(q=b.n);f(b.n,b.p);delete m[a]}delete l[a];g--},removeAll:function(){l={};g=0;m={};n=q=null},destroy:function(){m=h=l=null;delete a[b]},info:function(){return z({},h,{size:g})}}}var a={};b.info=function(){var b={};s(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function Ve(){this.$get=["$cacheFactory",
+function(b){return b("templates")}]}function wc(b,a){function c(a,b){var c=/^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/,d={};s(a,function(a,e){var f=a.match(c);if(!f)throw ja("iscp",b,e,a);d[e]={mode:f[1][0],collection:"*"===f[2],optional:"?"===f[3],attrName:f[4]||e}});return d}var d={},e=/^\s*directive\:\s*([\w\-]+)\s+(.*)$/,f=/(([\w\-]+)(?:\:([^;]+))?;?)/,g=Gd("ngSrc,ngSrcset,src,srcset"),h=/^(?:(\^\^?)?(\?)?(\^\^?)?)?/,l=/^(on[a-z]+|formaction)$/;this.directive=function n(a,e){La(a,"directive");H(a)?(Qb(e,
+"directiveFactory"),d.hasOwnProperty(a)||(d[a]=[],b.factory(a+"Directive",["$injector","$exceptionHandler",function(b,e){var f=[];s(d[a],function(d,g){try{var h=b.invoke(d);G(h)?h={compile:da(h)}:!h.compile&&h.link&&(h.compile=da(h.link));h.priority=h.priority||0;h.index=g;h.name=h.name||a;h.require=h.require||h.controller&&h.name;h.restrict=h.restrict||"EA";P(h.scope)&&(h.$$isolateBindings=c(h.scope,h.name));f.push(h)}catch(l){e(l)}});return f}])),d[a].push(e)):s(a,kc(n));return this};this.aHrefSanitizationWhitelist=
+function(b){return y(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return y(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};var k=!0;this.debugInfoEnabled=function(a){return y(a)?(k=a,this):k};this.$get=["$injector","$interpolate","$exceptionHandler","$templateRequest","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(a,b,c,r,O,p,v,w,L,J,A){function F(a,b){try{a.addClass(b)}catch(c){}}
+function E(a,b,c,d,e){a instanceof B||(a=B(a));s(a,function(b,c){b.nodeType==pb&&b.nodeValue.match(/\S+/)&&(a[c]=B(b).wrap("<span></span>").parent()[0])});var f=S(a,b,a,c,d,e);E.$$addScopeClass(a);var g=null;return function(b,c,d){Qb(b,"scope");d=d||{};var e=d.parentBoundTranscludeFn,h=d.transcludeControllers;d=d.futureParentElement;e&&e.$$boundTransclude&&(e=e.$$boundTransclude);g||(g=(d=d&&d[0])?"foreignobject"!==ua(d)&&d.toString().match(/SVG/)?"svg":"html":"html");d="html"!==g?B(Wb(g,B("<div>").append(a).html())):
+c?Ka.clone.call(a):a;if(h)for(var l in h)d.data("$"+l+"Controller",h[l].instance);E.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,e);return d}}function S(a,b,c,d,e,f){function g(a,c,d,e){var f,l,k,q,n,p,w;if(r)for(w=Array(c.length),q=0;q<h.length;q+=3)f=h[q],w[f]=c[f];else w=c;q=0;for(n=h.length;q<n;)l=w[h[q++]],c=h[q++],f=h[q++],c?(c.scope?(k=a.$new(),E.$$addScopeInfo(B(l),k)):k=a,p=c.transcludeOnThisElement?X(a,c.transclude,e,c.elementTranscludeOnThisElement):!c.templateOnThisElement&&e?e:!e&&b?X(a,
+b):null,c(f,k,l,d,p)):f&&f(a,l.childNodes,t,e)}for(var h=[],l,k,q,n,r,p=0;p<a.length;p++){l=new Xb;k=W(a[p],[],l,0===p?d:t,e);(f=k.length?ea(k,a[p],l,b,c,null,[],[],f):null)&&f.scope&&E.$$addScopeClass(l.$$element);l=f&&f.terminal||!(q=a[p].childNodes)||!q.length?null:S(q,f?(f.transcludeOnThisElement||!f.templateOnThisElement)&&f.transclude:b);if(f||l)h.push(p,f,l),n=!0,r=r||f;f=null}return n?g:null}function X(a,b,c,d){return function(d,e,f,g,h){d||(d=a.$new(!1,h),d.$$transcluded=!0);return b(d,e,
+{parentBoundTranscludeFn:c,transcludeControllers:f,futureParentElement:g})}}function W(a,b,c,d,g){var h=c.$attr,l;switch(a.nodeType){case na:ca(b,ya(ua(a)),"E",d,g);for(var k,q,n,r=a.attributes,p=0,w=r&&r.length;p<w;p++){var O=!1,L=!1;k=r[p];l=k.name;q=U(k.value);k=ya(l);if(n=eb.test(k))l=l.replace(Rc,"").substr(8).replace(/_(.)/g,function(a,b){return b.toUpperCase()});var u=k.replace(/(Start|End)$/,"");D(u)&&k===u+"Start"&&(O=l,L=l.substr(0,l.length-5)+"end",l=l.substr(0,l.length-6));k=ya(l.toLowerCase());
+h[k]=l;if(n||!c.hasOwnProperty(k))c[k]=q,Lc(a,k)&&(c[k]=!0);Oa(a,b,q,k,n);ca(b,k,"A",d,g,O,L)}a=a.className;if(H(a)&&""!==a)for(;l=f.exec(a);)k=ya(l[2]),ca(b,k,"C",d,g)&&(c[k]=U(l[3])),a=a.substr(l.index+l[0].length);break;case pb:M(b,a.nodeValue);break;case 8:try{if(l=e.exec(a.nodeValue))k=ya(l[1]),ca(b,k,"M",d,g)&&(c[k]=U(l[2]))}catch(v){}}b.sort(N);return b}function wa(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw ja("uterdir",b,c);a.nodeType==na&&(a.hasAttribute(b)&&
+e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return B(d)}function I(a,b,c){return function(d,e,f,g,h){e=wa(e[0],b,c);return a(d,e,f,g,h)}}function ea(a,d,e,f,g,l,k,n,r){function w(a,b,c,d){if(a){c&&(a=I(a,c,d));a.require=K.require;a.directiveName=z;if(S===K||K.$$isolateScope)a=Z(a,{isolateScope:!0});k.push(a)}if(b){c&&(b=I(b,c,d));b.require=K.require;b.directiveName=z;if(S===K||K.$$isolateScope)b=Z(b,{isolateScope:!0});n.push(b)}}function L(a,b,c,d){var e,f="data",
+g=!1,l=c,k;if(H(b)){k=b.match(h);b=b.substring(k[0].length);k[3]&&(k[1]?k[3]=null:k[1]=k[3]);"^"===k[1]?f="inheritedData":"^^"===k[1]&&(f="inheritedData",l=c.parent());"?"===k[2]&&(g=!0);e=null;d&&"data"===f&&(e=d[b])&&(e=e.instance);e=e||l[f]("$"+b+"Controller");if(!e&&!g)throw ja("ctreq",b,a);return e||null}x(b)&&(e=[],s(b,function(b){e.push(L(a,b,c,d))}));return e}function v(a,c,f,g,h){function l(a,b,c){var d;Ua(a)||(c=b,b=a,a=t);C&&(d=F);c||(c=C?W.parent():W);return h(a,b,d,c,wa)}var r,w,u,A,
+F,db,W,I;d===f?(I=e,W=e.$$element):(W=B(f),I=new Xb(W,e));S&&(A=c.$new(!0));h&&(db=l,db.$$boundTransclude=h);J&&(X={},F={},s(J,function(a){var b={$scope:a===S||a.$$isolateScope?A:c,$element:W,$attrs:I,$transclude:db};u=a.controller;"@"==u&&(u=I[a.name]);b=p(u,b,!0,a.controllerAs);F[a.name]=b;C||W.data("$"+a.name+"Controller",b.instance);X[a.name]=b}));if(S){E.$$addScopeInfo(W,A,!0,!(ka&&(ka===S||ka===S.$$originalDirective)));E.$$addScopeClass(W,!0);g=X&&X[S.name];var xa=A;g&&g.identifier&&!0===S.bindToController&&
+(xa=g.instance);s(A.$$isolateBindings=S.$$isolateBindings,function(a,d){var e=a.attrName,f=a.optional,g,h,l,k;switch(a.mode){case "@":I.$observe(e,function(a){xa[d]=a});I.$$observers[e].$$scope=c;I[e]&&(xa[d]=b(I[e])(c));break;case "=":if(f&&!I[e])break;h=O(I[e]);k=h.literal?fa:function(a,b){return a===b||a!==a&&b!==b};l=h.assign||function(){g=xa[d]=h(c);throw ja("nonassign",I[e],S.name);};g=xa[d]=h(c);f=function(a){k(a,xa[d])||(k(a,g)?l(c,a=xa[d]):xa[d]=a);return g=a};f.$stateful=!0;f=a.collection?
+c.$watchCollection(I[e],f):c.$watch(O(I[e],f),null,h.literal);A.$on("$destroy",f);break;case "&":h=O(I[e]),xa[d]=function(a){return h(c,a)}}})}X&&(s(X,function(a){a()}),X=null);g=0;for(r=k.length;g<r;g++)w=k[g],$(w,w.isolateScope?A:c,W,I,w.require&&L(w.directiveName,w.require,W,F),db);var wa=c;S&&(S.template||null===S.templateUrl)&&(wa=A);a&&a(wa,f.childNodes,t,h);for(g=n.length-1;0<=g;g--)w=n[g],$(w,w.isolateScope?A:c,W,I,w.require&&L(w.directiveName,w.require,W,F),db)}r=r||{};for(var A=-Number.MAX_VALUE,
+F,J=r.controllerDirectives,X,S=r.newIsolateScopeDirective,ka=r.templateDirective,ea=r.nonTlbTranscludeDirective,ca=!1,D=!1,C=r.hasElementTranscludeDirective,aa=e.$$element=B(d),K,z,N,Aa=f,Q,M=0,R=a.length;M<R;M++){K=a[M];var Oa=K.$$start,eb=K.$$end;Oa&&(aa=wa(d,Oa,eb));N=t;if(A>K.priority)break;if(N=K.scope)K.templateUrl||(P(N)?(Na("new/isolated scope",S||F,K,aa),S=K):Na("new/isolated scope",S,K,aa)),F=F||K;z=K.name;!K.templateUrl&&K.controller&&(N=K.controller,J=J||{},Na("'"+z+"' controller",J[z],
+K,aa),J[z]=K);if(N=K.transclude)ca=!0,K.$$tlb||(Na("transclusion",ea,K,aa),ea=K),"element"==N?(C=!0,A=K.priority,N=aa,aa=e.$$element=B(Y.createComment(" "+z+": "+e[z]+" ")),d=aa[0],V(g,Ya.call(N,0),d),Aa=E(N,f,A,l&&l.name,{nonTlbTranscludeDirective:ea})):(N=B(Tb(d)).contents(),aa.empty(),Aa=E(N,f));if(K.template)if(D=!0,Na("template",ka,K,aa),ka=K,N=G(K.template)?K.template(aa,e):K.template,N=Sc(N),K.replace){l=K;N=Rb.test(N)?Tc(Wb(K.templateNamespace,U(N))):[];d=N[0];if(1!=N.length||d.nodeType!==
+na)throw ja("tplrt",z,"");V(g,aa,d);R={$attr:{}};N=W(d,[],R);var ba=a.splice(M+1,a.length-(M+1));S&&y(N);a=a.concat(N).concat(ba);Qc(e,R);R=a.length}else aa.html(N);if(K.templateUrl)D=!0,Na("template",ka,K,aa),ka=K,K.replace&&(l=K),v=T(a.splice(M,a.length-M),aa,e,g,ca&&Aa,k,n,{controllerDirectives:J,newIsolateScopeDirective:S,templateDirective:ka,nonTlbTranscludeDirective:ea}),R=a.length;else if(K.compile)try{Q=K.compile(aa,e,Aa),G(Q)?w(null,Q,Oa,eb):Q&&w(Q.pre,Q.post,Oa,eb)}catch(qf){c(qf,va(aa))}K.terminal&&
+(v.terminal=!0,A=Math.max(A,K.priority))}v.scope=F&&!0===F.scope;v.transcludeOnThisElement=ca;v.elementTranscludeOnThisElement=C;v.templateOnThisElement=D;v.transclude=Aa;r.hasElementTranscludeDirective=C;return v}function y(a){for(var b=0,c=a.length;b<c;b++){var d=b,e;e=z(Object.create(a[b]),{$$isolateScope:!0});a[d]=e}}function ca(b,e,f,g,h,l,k){if(e===h)return null;h=null;if(d.hasOwnProperty(e)){var q;e=a.get(e+"Directive");for(var r=0,p=e.length;r<p;r++)try{if(q=e[r],(g===t||g>q.priority)&&-1!=
+q.restrict.indexOf(f)){if(l){var w={$$start:l,$$end:k};q=z(Object.create(q),w)}b.push(q);h=q}}catch(O){c(O)}}return h}function D(b){if(d.hasOwnProperty(b))for(var c=a.get(b+"Directive"),e=0,f=c.length;e<f;e++)if(b=c[e],b.multiElement)return!0;return!1}function Qc(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;s(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&b[e]!==d&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});s(b,function(b,f){"class"==f?(F(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==
+f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function T(a,b,c,d,e,f,g,h){var l=[],k,q,n=b[0],p=a.shift(),w=z({},p,{templateUrl:null,transclude:null,replace:null,$$originalDirective:p}),O=G(p.templateUrl)?p.templateUrl(b,c):p.templateUrl,u=p.templateNamespace;b.empty();r(L.getTrustedResourceUrl(O)).then(function(r){var L,v;r=Sc(r);if(p.replace){r=Rb.test(r)?Tc(Wb(u,U(r))):[];L=r[0];if(1!=r.length||L.nodeType!==
+na)throw ja("tplrt",p.name,O);r={$attr:{}};V(d,b,L);var A=W(L,[],r);P(p.scope)&&y(A);a=A.concat(a);Qc(c,r)}else L=n,b.html(r);a.unshift(w);k=ea(a,L,c,e,b,p,f,g,h);s(d,function(a,c){a==L&&(d[c]=b[0])});for(q=S(b[0].childNodes,e);l.length;){r=l.shift();v=l.shift();var J=l.shift(),E=l.shift(),A=b[0];if(!r.$$destroyed){if(v!==n){var I=v.className;h.hasElementTranscludeDirective&&p.replace||(A=Tb(L));V(J,B(v),A);F(B(A),I)}v=k.transcludeOnThisElement?X(r,k.transclude,E):E;k(q,r,A,d,v)}}l=null});return function(a,
+b,c,d,e){a=e;b.$$destroyed||(l?l.push(b,c,d,a):(k.transcludeOnThisElement&&(a=X(b,k.transclude,e)),k(q,b,c,d,a)))}}function N(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function Na(a,b,c,d){if(b)throw ja("multidir",b.name,c.name,a,va(d));}function M(a,c){var d=b(c,!0);d&&a.push({priority:0,compile:function(a){a=a.parent();var b=!!a.length;b&&E.$$addBindingClass(a);return function(a,c){var e=c.parent();b||E.$$addBindingClass(e);E.$$addBindingInfo(e,
+d.expressions);a.$watch(d,function(a){c[0].nodeValue=a})}}})}function Wb(a,b){a=Q(a||"html");switch(a){case "svg":case "math":var c=Y.createElement("div");c.innerHTML="<"+a+">"+b+"</"+a+">";return c.childNodes[0].childNodes;default:return b}}function R(a,b){if("srcdoc"==b)return L.HTML;var c=ua(a);if("xlinkHref"==b||"form"==c&&"action"==b||"img"!=c&&("src"==b||"ngSrc"==b))return L.RESOURCE_URL}function Oa(a,c,d,e,f){var h=R(a,e);f=g[e]||f;var k=b(d,!0,h,f);if(k){if("multiple"===e&&"select"===ua(a))throw ja("selmulti",
+va(a));c.push({priority:100,compile:function(){return{pre:function(a,c,g){c=g.$$observers||(g.$$observers={});if(l.test(e))throw ja("nodomevents");var n=g[e];n!==d&&(k=n&&b(n,!0,h,f),d=n);k&&(g[e]=k(a),(c[e]||(c[e]=[])).$$inter=!0,(g.$$observers&&g.$$observers[e].$$scope||a).$watch(k,function(a,b){"class"===e&&a!=b?g.$updateClass(a,b):g.$set(e,a)}))}}}})}}function V(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g<h;g++)if(a[g]==d){a[g++]=c;h=g+e-1;for(var k=a.length;g<k;g++,
+h++)h<k?a[g]=a[h]:delete a[g];a.length-=e-1;a.context===d&&(a.context=c);break}f&&f.replaceChild(c,d);a=Y.createDocumentFragment();a.appendChild(d);B(c).data(B(d).data());ra?(Pb=!0,ra.cleanData([d])):delete B.cache[d[B.expando]];d=1;for(e=b.length;d<e;d++)f=b[d],B(f).remove(),a.appendChild(f),delete b[d];b[0]=c;b.length=1}function Z(a,b){return z(function(){return a.apply(null,arguments)},a,b)}function $(a,b,d,e,f,g){try{a(b,d,e,f,g)}catch(h){c(h,va(d))}}var Xb=function(a,b){if(b){var c=Object.keys(b),
+d,e,f;d=0;for(e=c.length;d<e;d++)f=c[d],this[f]=b[f]}else this.$attr={};this.$$element=a};Xb.prototype={$normalize:ya,$addClass:function(a){a&&0<a.length&&J.addClass(this.$$element,a)},$removeClass:function(a){a&&0<a.length&&J.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=Uc(a,b);c&&c.length&&J.addClass(this.$$element,c);(c=Uc(b,a))&&c.length&&J.removeClass(this.$$element,c)},$set:function(a,b,d,e){var f=this.$$element[0],g=Lc(f,a),h=kf(f,a),f=a;g?(this.$$element.prop(a,b),e=g):
+h&&(this[h]=b,f=h);this[a]=b;e?this.$attr[a]=e:(e=this.$attr[a])||(this.$attr[a]=e=tc(a,"-"));g=ua(this.$$element);if("a"===g&&"href"===a||"img"===g&&"src"===a)this[a]=b=A(b,"src"===a);else if("img"===g&&"srcset"===a){for(var g="",h=U(b),k=/(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/,k=/\s/.test(h)?k:/(,)/,h=h.split(k),k=Math.floor(h.length/2),l=0;l<k;l++)var q=2*l,g=g+A(U(h[q]),!0),g=g+(" "+U(h[q+1]));h=U(h[2*l]).split(/\s/);g+=A(U(h[0]),!0);2===h.length&&(g+=" "+U(h[1]));this[a]=b=g}!1!==d&&(null===b||
+b===t?this.$$element.removeAttr(e):this.$$element.attr(e,b));(a=this.$$observers)&&s(a[f],function(a){try{a(b)}catch(d){c(d)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers=ha()),e=d[a]||(d[a]=[]);e.push(b);v.$evalAsync(function(){!e.$$inter&&c.hasOwnProperty(a)&&b(c[a])});return function(){Wa(e,b)}}};var Aa=b.startSymbol(),ka=b.endSymbol(),Sc="{{"==Aa||"}}"==ka?oa:function(a){return a.replace(/\{\{/g,Aa).replace(/}}/g,ka)},eb=/^ngAttr[A-Z]/;E.$$addBindingInfo=k?function(a,b){var c=
+a.data("$binding")||[];x(b)?c=c.concat(b):c.push(b);a.data("$binding",c)}:C;E.$$addBindingClass=k?function(a){F(a,"ng-binding")}:C;E.$$addScopeInfo=k?function(a,b,c,d){a.data(c?d?"$isolateScopeNoTemplate":"$isolateScope":"$scope",b)}:C;E.$$addScopeClass=k?function(a,b){F(a,b?"ng-isolate-scope":"ng-scope")}:C;return E}]}function ya(b){return bb(b.replace(Rc,""))}function Uc(b,a){var c="",d=b.split(/\s+/),e=a.split(/\s+/),f=0;a:for(;f<d.length;f++){for(var g=d[f],h=0;h<e.length;h++)if(g==e[h])continue a;
+c+=(0<c.length?" ":"")+g}return c}function Tc(b){b=B(b);var a=b.length;if(1>=a)return b;for(;a--;)8===b[a].nodeType&&rf.call(b,a,1);return b}function Fe(){var b={},a=!1,c=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,c){La(a,"controller");P(a)?z(b,a):b[a]=c};this.allowGlobals=function(){a=!0};this.$get=["$injector","$window",function(d,e){function f(a,b,c,d){if(!a||!P(a.$scope))throw T("$controller")("noscp",d,b);a.$scope[b]=c}return function(g,h,l,k){var m,n,q;l=!0===l;k&&H(k)&&(q=k);H(g)&&
+(k=g.match(c),n=k[1],q=q||k[3],g=b.hasOwnProperty(n)?b[n]:vc(h.$scope,n,!0)||(a?vc(e,n,!0):t),sb(g,n,!0));if(l)return l=(x(g)?g[g.length-1]:g).prototype,m=Object.create(l),q&&f(h,q,m,n||g.name),z(function(){d.invoke(g,m,h,n);return m},{instance:m,identifier:q});m=d.instantiate(g,h,n);q&&f(h,q,m,n||g.name);return m}}]}function Ge(){this.$get=["$window",function(b){return B(b.document)}]}function He(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Yb(b,a){if(H(b)){var c=
+b.replace(sf,"").trim();if(c){var d=a("Content-Type");(d=d&&0===d.indexOf(Vc))||(d=(d=c.match(tf))&&uf[d[0]].test(c));d&&(b=oc(c))}}return b}function Wc(b){var a=ha(),c,d,e;if(!b)return a;s(b.split("\n"),function(b){e=b.indexOf(":");c=Q(U(b.substr(0,e)));d=U(b.substr(e+1));c&&(a[c]=a[c]?a[c]+", "+d:d)});return a}function Xc(b){var a=P(b)?b:t;return function(c){a||(a=Wc(b));return c?(c=a[Q(c)],void 0===c&&(c=null),c):a}}function Yc(b,a,c,d){if(G(d))return d(b,a,c);s(d,function(d){b=d(b,a,c)});return b}
+function Ke(){var b=this.defaults={transformResponse:[Yb],transformRequest:[function(a){return P(a)&&"[object File]"!==Da.call(a)&&"[object Blob]"!==Da.call(a)&&"[object FormData]"!==Da.call(a)?Za(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:qa(Zb),put:qa(Zb),patch:qa(Zb)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},a=!1;this.useApplyAsync=function(b){return y(b)?(a=!!b,this):a};var c=this.interceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory",
+"$rootScope","$q","$injector",function(d,e,f,g,h,l){function k(a){function c(a){var b=z({},a);b.data=a.data?Yc(a.data,a.headers,a.status,e.transformResponse):a.data;a=a.status;return 200<=a&&300>a?b:h.reject(b)}function d(a){var b,c={};s(a,function(a,d){G(a)?(b=a(),null!=b&&(c[d]=b)):c[d]=a});return c}if(!ga.isObject(a))throw T("$http")("badreq",a);var e=z({method:"get",transformRequest:b.transformRequest,transformResponse:b.transformResponse},a);e.headers=function(a){var c=b.headers,e=z({},a.headers),
+f,g,c=z({},c.common,c[Q(a.method)]);a:for(f in c){a=Q(f);for(g in e)if(Q(g)===a)continue a;e[f]=c[f]}return d(e)}(a);e.method=ub(e.method);var f=[function(a){var d=a.headers,e=Yc(a.data,Xc(d),t,a.transformRequest);D(e)&&s(d,function(a,b){"content-type"===Q(b)&&delete d[b]});D(a.withCredentials)&&!D(b.withCredentials)&&(a.withCredentials=b.withCredentials);return m(a,e).then(c,c)},t],g=h.when(e);for(s(u,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&
+f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),g=g.then(a,k)}g.success=function(a){g.then(function(b){a(b.data,b.status,b.headers,e)});return g};g.error=function(a){g.then(null,function(b){a(b.data,b.status,b.headers,e)});return g};return g}function m(c,f){function l(b,c,d,e){function f(){m(c,b,d,e)}F&&(200<=b&&300>b?F.put(X,[b,c,Wc(d),e]):F.remove(X));a?g.$applyAsync(f):(f(),g.$$phase||g.$apply())}function m(a,b,d,e){b=Math.max(b,0);(200<=b&&300>b?J.resolve:J.reject)({data:a,
+status:b,headers:Xc(d),config:c,statusText:e})}function w(a){m(a.data,a.status,qa(a.headers()),a.statusText)}function u(){var a=k.pendingRequests.indexOf(c);-1!==a&&k.pendingRequests.splice(a,1)}var J=h.defer(),A=J.promise,F,E,s=c.headers,X=n(c.url,c.params);k.pendingRequests.push(c);A.then(u,u);!c.cache&&!b.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(F=P(c.cache)?c.cache:P(b.cache)?b.cache:q);F&&(E=F.get(X),y(E)?E&&G(E.then)?E.then(w,w):x(E)?m(E[1],E[0],qa(E[2]),E[3]):m(E,200,{},
+"OK"):F.put(X,A));D(E)&&((E=Zc(c.url)?e.cookies()[c.xsrfCookieName||b.xsrfCookieName]:t)&&(s[c.xsrfHeaderName||b.xsrfHeaderName]=E),d(c.method,X,f,l,s,c.timeout,c.withCredentials,c.responseType));return A}function n(a,b){if(!b)return a;var c=[];Ed(b,function(a,b){null===a||D(a)||(x(a)||(a=[a]),s(a,function(a){P(a)&&(a=pa(a)?a.toISOString():Za(a));c.push(Fa(b)+"="+Fa(a))}))});0<c.length&&(a+=(-1==a.indexOf("?")?"?":"&")+c.join("&"));return a}var q=f("$http"),u=[];s(c,function(a){u.unshift(H(a)?l.get(a):
+l.invoke(a))});k.pendingRequests=[];(function(a){s(arguments,function(a){k[a]=function(b,c){return k(z(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){s(arguments,function(a){k[a]=function(b,c,d){return k(z(d||{},{method:a,url:b,data:c}))}})})("post","put","patch");k.defaults=b;return k}]}function vf(){return new M.XMLHttpRequest}function Le(){this.$get=["$browser","$window","$document",function(b,a,c){return wf(b,vf,b.defer,a.angular.callbacks,c[0])}]}function wf(b,a,c,
+d,e){function f(a,b,c){var f=e.createElement("script"),m=null;f.type="text/javascript";f.src=a;f.async=!0;m=function(a){f.removeEventListener("load",m,!1);f.removeEventListener("error",m,!1);e.body.removeChild(f);f=null;var g=-1,u="unknown";a&&("load"!==a.type||d[b].called||(a={type:"error"}),u=a.type,g="error"===a.type?404:200);c&&c(g,u)};f.addEventListener("load",m,!1);f.addEventListener("error",m,!1);e.body.appendChild(f);return m}return function(e,h,l,k,m,n,q,u){function r(){v&&v();w&&w.abort()}
+function O(a,d,e,f,g){J!==t&&c.cancel(J);v=w=null;a(d,e,f,g);b.$$completeOutstandingRequest(C)}b.$$incOutstandingRequestCount();h=h||b.url();if("jsonp"==Q(e)){var p="_"+(d.counter++).toString(36);d[p]=function(a){d[p].data=a;d[p].called=!0};var v=f(h.replace("JSON_CALLBACK","angular.callbacks."+p),p,function(a,b){O(k,a,d[p].data,"",b);d[p]=C})}else{var w=a();w.open(e,h,!0);s(m,function(a,b){y(a)&&w.setRequestHeader(b,a)});w.onload=function(){var a=w.statusText||"",b="response"in w?w.response:w.responseText,
+c=1223===w.status?204:w.status;0===c&&(c=b?200:"file"==Ba(h).protocol?404:0);O(k,c,b,w.getAllResponseHeaders(),a)};e=function(){O(k,-1,null,null,"")};w.onerror=e;w.onabort=e;q&&(w.withCredentials=!0);if(u)try{w.responseType=u}catch(L){if("json"!==u)throw L;}w.send(l||null)}if(0<n)var J=c(r,n);else n&&G(n.then)&&n.then(r)}}function Ie(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler","$sce",
+function(c,d,e){function f(a){return"\\\\\\"+a}function g(f,g,u,r){function O(c){return c.replace(k,b).replace(m,a)}function p(a){try{var b=a;a=u?e.getTrusted(u,b):e.valueOf(b);var c;if(r&&!y(a))c=a;else if(null==a)c="";else{switch(typeof a){case "string":break;case "number":a=""+a;break;default:a=Za(a)}c=a}return c}catch(g){c=$b("interr",f,g.toString()),d(c)}}r=!!r;for(var v,w,L=0,J=[],A=[],F=f.length,E=[],s=[];L<F;)if(-1!=(v=f.indexOf(b,L))&&-1!=(w=f.indexOf(a,v+h)))L!==v&&E.push(O(f.substring(L,
+v))),L=f.substring(v+h,w),J.push(L),A.push(c(L,p)),L=w+l,s.push(E.length),E.push("");else{L!==F&&E.push(O(f.substring(L)));break}if(u&&1<E.length)throw $b("noconcat",f);if(!g||J.length){var X=function(a){for(var b=0,c=J.length;b<c;b++){if(r&&D(a[b]))return;E[s[b]]=a[b]}return E.join("")};return z(function(a){var b=0,c=J.length,e=Array(c);try{for(;b<c;b++)e[b]=A[b](a);return X(e)}catch(g){a=$b("interr",f,g.toString()),d(a)}},{exp:f,expressions:J,$$watchDelegate:function(a,b,c){var d;return a.$watchGroup(A,
+function(c,e){var f=X(c);G(b)&&b.call(this,f,c!==e?d:f,a);d=f},c)}})}}var h=b.length,l=a.length,k=new RegExp(b.replace(/./g,f),"g"),m=new RegExp(a.replace(/./g,f),"g");g.startSymbol=function(){return b};g.endSymbol=function(){return a};return g}]}function Je(){this.$get=["$rootScope","$window","$q","$$q",function(b,a,c,d){function e(e,h,l,k){var m=a.setInterval,n=a.clearInterval,q=0,u=y(k)&&!k,r=(u?d:c).defer(),O=r.promise;l=y(l)?l:0;O.then(null,null,e);O.$$intervalId=m(function(){r.notify(q++);0<
+l&&q>=l&&(r.resolve(q),n(O.$$intervalId),delete f[O.$$intervalId]);u||b.$apply()},h);f[O.$$intervalId]=r;return O}var f={};e.cancel=function(b){return b&&b.$$intervalId in f?(f[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete f[b.$$intervalId],!0):!1};return e}]}function Rd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,
+maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",
+longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function ac(b){b=b.split("/");for(var a=b.length;a--;)b[a]=qb(b[a]);return b.join("/")}function $c(b,a){var c=Ba(b);a.$$protocol=c.protocol;a.$$host=c.hostname;a.$$port=ba(c.port)||xf[c.protocol]||null}function ad(b,a){var c="/"!==b.charAt(0);c&&(b="/"+b);var d=Ba(b);a.$$path=decodeURIComponent(c&&"/"===d.pathname.charAt(0)?d.pathname.substring(1):
+d.pathname);a.$$search=qc(d.search);a.$$hash=decodeURIComponent(d.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function za(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Ha(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function bd(b){return b.replace(/(#.+)|#$/,"$1")}function bc(b){return b.substr(0,Ha(b).lastIndexOf("/")+1)}function cc(b,a){this.$$html5=!0;a=a||"";var c=bc(b);$c(b,this);this.$$parse=function(a){var b=za(c,a);if(!H(b))throw Fb("ipthprfx",a,c);
+ad(b,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Nb(this.$$search),b=this.$$hash?"#"+qb(this.$$hash):"";this.$$url=ac(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;(f=za(b,d))!==t?(g=f,g=(f=za(a,f))!==t?c+(za("/",f)||f):b+g):(f=za(c,d))!==t?g=c+f:c==d+"/"&&(g=c);g&&this.$$parse(g);return!!g}}function dc(b,a){var c=bc(b);$c(b,this);this.$$parse=function(d){d=
+za(b,d)||za(c,d);var e;"#"===d.charAt(0)?(e=za(a,d),D(e)&&(e=d)):e=this.$$html5?d:"";ad(e,this);d=this.$$path;var f=/^\/[A-Z]:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));f.exec(e)||(d=(e=f.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Nb(this.$$search),e=this.$$hash?"#"+qb(this.$$hash):"";this.$$url=ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$parseLinkUrl=function(a,c){return Ha(b)==Ha(a)?(this.$$parse(a),!0):!1}}function cd(b,
+a){this.$$html5=!0;dc.apply(this,arguments);var c=bc(b);this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;b==Ha(d)?f=d:(g=za(c,d))?f=b+a+g:c===d+"/"&&(f=c);f&&this.$$parse(f);return!!f};this.$$compose=function(){var c=Nb(this.$$search),e=this.$$hash?"#"+qb(this.$$hash):"";this.$$url=ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+a+this.$$url}}function Gb(b){return function(){return this[b]}}function dd(b,a){return function(c){if(D(c))return this[b];this[b]=
+a(c);this.$$compose();return this}}function Me(){var b="",a={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(a){return y(a)?(b=a,this):b};this.html5Mode=function(b){return Va(b)?(a.enabled=b,this):P(b)?(Va(b.enabled)&&(a.enabled=b.enabled),Va(b.requireBase)&&(a.requireBase=b.requireBase),Va(b.rewriteLinks)&&(a.rewriteLinks=b.rewriteLinks),this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(c,d,e,f,g){function h(a,b,c){var e=k.url(),f=k.$$state;
+try{d.url(a,b,c),k.$$state=d.state()}catch(g){throw k.url(e),k.$$state=f,g;}}function l(a,b){c.$broadcast("$locationChangeSuccess",k.absUrl(),a,k.$$state,b)}var k,m;m=d.baseHref();var n=d.url(),q;if(a.enabled){if(!m&&a.requireBase)throw Fb("nobase");q=n.substring(0,n.indexOf("/",n.indexOf("//")+2))+(m||"/");m=e.history?cc:cd}else q=Ha(n),m=dc;k=new m(q,"#"+b);k.$$parseLinkUrl(n,n);k.$$state=d.state();var u=/^\s*(javascript|mailto):/i;f.on("click",function(b){if(a.rewriteLinks&&!b.ctrlKey&&!b.metaKey&&
+2!=b.which){for(var e=B(b.target);"a"!==ua(e[0]);)if(e[0]===f[0]||!(e=e.parent())[0])return;var h=e.prop("href"),l=e.attr("href")||e.attr("xlink:href");P(h)&&"[object SVGAnimatedString]"===h.toString()&&(h=Ba(h.animVal).href);u.test(h)||!h||e.attr("target")||b.isDefaultPrevented()||!k.$$parseLinkUrl(h,l)||(b.preventDefault(),k.absUrl()!=d.url()&&(c.$apply(),g.angular["ff-684208-preventDefault"]=!0))}});k.absUrl()!=n&&d.url(k.absUrl(),!0);var r=!0;d.onUrlChange(function(a,b){c.$evalAsync(function(){var d=
+k.absUrl(),e=k.$$state,f;k.$$parse(a);k.$$state=b;f=c.$broadcast("$locationChangeStart",a,d,b,e).defaultPrevented;k.absUrl()===a&&(f?(k.$$parse(d),k.$$state=e,h(d,!1,e)):(r=!1,l(d,e)))});c.$$phase||c.$digest()});c.$watch(function(){var a=bd(d.url()),b=bd(k.absUrl()),f=d.state(),g=k.$$replace,q=a!==b||k.$$html5&&e.history&&f!==k.$$state;if(r||q)r=!1,c.$evalAsync(function(){var b=k.absUrl(),d=c.$broadcast("$locationChangeStart",b,a,k.$$state,f).defaultPrevented;k.absUrl()===b&&(d?(k.$$parse(a),k.$$state=
+f):(q&&h(b,g,f===k.$$state?null:k.$$state),l(a,f)))});k.$$replace=!1});return k}]}function Ne(){var b=!0,a=this;this.debugEnabled=function(a){return y(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||C;a=!1;try{a=!!e.apply}catch(l){}return a?function(){var a=
+[];s(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function sa(b,a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw la("isecfld",a);return b}function ta(b,a){if(b){if(b.constructor===b)throw la("isecfn",a);if(b.window===b)throw la("isecwindow",
+a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw la("isecdom",a);if(b===Object)throw la("isecobj",a);}return b}function ec(b){return b.constant}function fb(b,a,c,d){ta(b,d);a=a.split(".");for(var e,f=0;1<a.length;f++){e=sa(a.shift(),d);var g=ta(b[e],d);g||(g={},b[e]=g);b=g}e=sa(a.shift(),d);ta(b[e],d);return b[e]=c}function Pa(b){return"constructor"==b}function ed(b,a,c,d,e,f,g){sa(b,f);sa(a,f);sa(c,f);sa(d,f);sa(e,f);var h=function(a){return ta(a,f)},l=g||Pa(b)?h:oa,k=g||Pa(a)?h:oa,m=
+g||Pa(c)?h:oa,n=g||Pa(d)?h:oa,q=g||Pa(e)?h:oa;return function(f,g){var h=g&&g.hasOwnProperty(b)?g:f;if(null==h)return h;h=l(h[b]);if(!a)return h;if(null==h)return t;h=k(h[a]);if(!c)return h;if(null==h)return t;h=m(h[c]);if(!d)return h;if(null==h)return t;h=n(h[d]);return e?null==h?t:h=q(h[e]):h}}function yf(b,a){return function(c,d){return b(c,d,ta,a)}}function zf(b,a,c){var d=a.expensiveChecks,e=d?Af:Bf,f=e[b];if(f)return f;var g=b.split("."),h=g.length;if(a.csp)f=6>h?ed(g[0],g[1],g[2],g[3],g[4],
+c,d):function(a,b){var e=0,f;do f=ed(g[e++],g[e++],g[e++],g[e++],g[e++],c,d)(a,b),b=t,a=f;while(e<h);return f};else{var l="";d&&(l+="s = eso(s, fe);\nl = eso(l, fe);\n");var k=d;s(g,function(a,b){sa(a,c);var e=(b?"s":'((l&&l.hasOwnProperty("'+a+'"))?l:s)')+"."+a;if(d||Pa(a))e="eso("+e+", fe)",k=!0;l+="if(s == null) return undefined;\ns="+e+";\n"});l+="return s;";a=new Function("s","l","eso","fe",l);a.toString=da(l);k&&(a=yf(a,c));f=a}f.sharedGetter=!0;f.assign=function(a,c){return fb(a,b,c,b)};return e[b]=
+f}function fc(b){return G(b.valueOf)?b.valueOf():Cf.call(b)}function Oe(){var b=ha(),a=ha();this.$get=["$filter","$sniffer",function(c,d){function e(a){var b=a;a.sharedGetter&&(b=function(b,c){return a(b,c)},b.literal=a.literal,b.constant=a.constant,b.assign=a.assign);return b}function f(a,b){for(var c=0,d=a.length;c<d;c++){var e=a[c];e.constant||(e.inputs?f(e.inputs,b):-1===b.indexOf(e)&&b.push(e))}return b}function g(a,b){return null==a||null==b?a===b:"object"===typeof a&&(a=fc(a),"object"===typeof a)?
+!1:a===b||a!==a&&b!==b}function h(a,b,c,d){var e=d.$$inputs||(d.$$inputs=f(d.inputs,[])),h;if(1===e.length){var l=g,e=e[0];return a.$watch(function(a){var b=e(a);g(b,l)||(h=d(a),l=b&&fc(b));return h},b,c)}for(var k=[],q=0,n=e.length;q<n;q++)k[q]=g;return a.$watch(function(a){for(var b=!1,c=0,f=e.length;c<f;c++){var l=e[c](a);if(b||(b=!g(l,k[c])))k[c]=l&&fc(l)}b&&(h=d(a));return h},b,c)}function l(a,b,c,d){var e,f;return e=a.$watch(function(a){return d(a)},function(a,c,d){f=a;G(b)&&b.apply(this,arguments);
+y(a)&&d.$$postDigest(function(){y(f)&&e()})},c)}function k(a,b,c,d){function e(a){var b=!0;s(a,function(a){y(a)||(b=!1)});return b}var f,g;return f=a.$watch(function(a){return d(a)},function(a,c,d){g=a;G(b)&&b.call(this,a,c,d);e(a)&&d.$$postDigest(function(){e(g)&&f()})},c)}function m(a,b,c,d){var e;return e=a.$watch(function(a){return d(a)},function(a,c,d){G(b)&&b.apply(this,arguments);e()},c)}function n(a,b){if(!b)return a;var c=a.$$watchDelegate,c=c!==k&&c!==l?function(c,d){var e=a(c,d);return b(e,
+c,d)}:function(c,d){var e=a(c,d),f=b(e,c,d);return y(e)?f:e};a.$$watchDelegate&&a.$$watchDelegate!==h?c.$$watchDelegate=a.$$watchDelegate:b.$stateful||(c.$$watchDelegate=h,c.inputs=[a]);return c}var q={csp:d.csp,expensiveChecks:!1},u={csp:d.csp,expensiveChecks:!0};return function(d,f,g){var v,w,L;switch(typeof d){case "string":L=d=d.trim();var J=g?a:b;v=J[L];v||(":"===d.charAt(0)&&":"===d.charAt(1)&&(w=!0,d=d.substring(2)),g=g?u:q,v=new gc(g),v=(new gb(v,c,g)).parse(d),v.constant?v.$$watchDelegate=
+m:w?(v=e(v),v.$$watchDelegate=v.literal?k:l):v.inputs&&(v.$$watchDelegate=h),J[L]=v);return n(v,f);case "function":return n(d,f);default:return n(C,f)}}}]}function Qe(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return fd(function(a){b.$evalAsync(a)},a)}]}function Re(){this.$get=["$browser","$exceptionHandler",function(b,a){return fd(function(a){b.defer(a)},a)}]}function fd(b,a){function c(a,b,c){function d(b){return function(c){e||(e=!0,b.call(a,c))}}var e=!1;return[d(b),d(c)]}function d(){this.$$state=
+{status:0}}function e(a,b){return function(c){b.call(a,c)}}function f(c){!c.processScheduled&&c.pending&&(c.processScheduled=!0,b(function(){var b,d,e;e=c.pending;c.processScheduled=!1;c.pending=t;for(var f=0,g=e.length;f<g;++f){d=e[f][0];b=e[f][c.status];try{G(b)?d.resolve(b(c.value)):1===c.status?d.resolve(c.value):d.reject(c.value)}catch(h){d.reject(h),a(h)}}}))}function g(){this.promise=new d;this.resolve=e(this,this.resolve);this.reject=e(this,this.reject);this.notify=e(this,this.notify)}var h=
+T("$q",TypeError);d.prototype={then:function(a,b,c){var d=new g;this.$$state.pending=this.$$state.pending||[];this.$$state.pending.push([d,a,b,c]);0<this.$$state.status&&f(this.$$state);return d.promise},"catch":function(a){return this.then(null,a)},"finally":function(a,b){return this.then(function(b){return k(b,!0,a)},function(b){return k(b,!1,a)},b)}};g.prototype={resolve:function(a){this.promise.$$state.status||(a===this.promise?this.$$reject(h("qcycle",a)):this.$$resolve(a))},$$resolve:function(b){var d,
+e;e=c(this,this.$$resolve,this.$$reject);try{if(P(b)||G(b))d=b&&b.then;G(d)?(this.promise.$$state.status=-1,d.call(b,e[0],e[1],this.notify)):(this.promise.$$state.value=b,this.promise.$$state.status=1,f(this.promise.$$state))}catch(g){e[1](g),a(g)}},reject:function(a){this.promise.$$state.status||this.$$reject(a)},$$reject:function(a){this.promise.$$state.value=a;this.promise.$$state.status=2;f(this.promise.$$state)},notify:function(c){var d=this.promise.$$state.pending;0>=this.promise.$$state.status&&
+d&&d.length&&b(function(){for(var b,e,f=0,g=d.length;f<g;f++){e=d[f][0];b=d[f][3];try{e.notify(G(b)?b(c):c)}catch(h){a(h)}}})}};var l=function(a,b){var c=new g;b?c.resolve(a):c.reject(a);return c.promise},k=function(a,b,c){var d=null;try{G(c)&&(d=c())}catch(e){return l(e,!1)}return d&&G(d.then)?d.then(function(){return l(a,b)},function(a){return l(a,!1)}):l(a,b)},m=function(a,b,c,d){var e=new g;e.resolve(a);return e.promise.then(b,c,d)},n=function u(a){if(!G(a))throw h("norslvr",a);if(!(this instanceof
+u))return new u(a);var b=new g;a(function(a){b.resolve(a)},function(a){b.reject(a)});return b.promise};n.defer=function(){return new g};n.reject=function(a){var b=new g;b.reject(a);return b.promise};n.when=m;n.all=function(a){var b=new g,c=0,d=x(a)?[]:{};s(a,function(a,e){c++;m(a).then(function(a){d.hasOwnProperty(e)||(d[e]=a,--c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});0===c&&b.resolve(d);return b.promise};return n}function $e(){this.$get=["$window","$timeout",function(b,
+a){var c=b.requestAnimationFrame||b.webkitRequestAnimationFrame,d=b.cancelAnimationFrame||b.webkitCancelAnimationFrame||b.webkitCancelRequestAnimationFrame,e=!!c,f=e?function(a){var b=c(a);return function(){d(b)}}:function(b){var c=a(b,16.66,!1);return function(){a.cancel(c)}};f.supported=e;return f}]}function Pe(){var b=10,a=T("$rootScope"),c=null,d=null;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse","$browser",function(e,f,g,h){function l(){this.$id=
+++nb;this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this.$root=this;this.$$destroyed=!1;this.$$listeners={};this.$$listenerCount={};this.$$isolateBindings=null}function k(b){if(r.$$phase)throw a("inprog",r.$$phase);r.$$phase=b}function m(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function n(){}function q(){for(;v.length;)try{v.shift()()}catch(a){f(a)}d=null}function u(){null===
+d&&(d=h.defer(function(){r.$apply(q)}))}l.prototype={constructor:l,$new:function(a,b){function c(){d.$$destroyed=!0}var d;b=b||this;a?(d=new l,d.$root=this.$root):(this.$$ChildScope||(this.$$ChildScope=function(){this.$$watchers=this.$$nextSibling=this.$$childHead=this.$$childTail=null;this.$$listeners={};this.$$listenerCount={};this.$id=++nb;this.$$ChildScope=null},this.$$ChildScope.prototype=this),d=new this.$$ChildScope);d.$parent=b;d.$$prevSibling=b.$$childTail;b.$$childHead?(b.$$childTail.$$nextSibling=
+d,b.$$childTail=d):b.$$childHead=b.$$childTail=d;(a||b!=this)&&d.$on("$destroy",c);return d},$watch:function(a,b,d){var e=g(a);if(e.$$watchDelegate)return e.$$watchDelegate(this,b,d,e);var f=this.$$watchers,h={fn:b,last:n,get:e,exp:a,eq:!!d};c=null;G(b)||(h.fn=C);f||(f=this.$$watchers=[]);f.unshift(h);return function(){Wa(f,h);c=null}},$watchGroup:function(a,b){function c(){h=!1;l?(l=!1,b(e,e,g)):b(e,d,g)}var d=Array(a.length),e=Array(a.length),f=[],g=this,h=!1,l=!0;if(!a.length){var k=!0;g.$evalAsync(function(){k&&
+b(e,e,g)});return function(){k=!1}}if(1===a.length)return this.$watch(a[0],function(a,c,f){e[0]=a;d[0]=c;b(e,a===c?e:d,f)});s(a,function(a,b){var l=g.$watch(a,function(a,f){e[b]=a;d[b]=f;h||(h=!0,g.$evalAsync(c))});f.push(l)});return function(){for(;f.length;)f.shift()()}},$watchCollection:function(a,b){function c(a){e=a;var b,d,g,h;if(!D(e)){if(P(e))if(Sa(e))for(f!==q&&(f=q,p=f.length=0,k++),a=e.length,p!==a&&(k++,f.length=p=a),b=0;b<a;b++)h=f[b],g=e[b],d=h!==h&&g!==g,d||h===g||(k++,f[b]=g);else{f!==
+m&&(f=m={},p=0,k++);a=0;for(b in e)e.hasOwnProperty(b)&&(a++,g=e[b],h=f[b],b in f?(d=h!==h&&g!==g,d||h===g||(k++,f[b]=g)):(p++,f[b]=g,k++));if(p>a)for(b in k++,f)e.hasOwnProperty(b)||(p--,delete f[b])}else f!==e&&(f=e,k++);return k}}c.$stateful=!0;var d=this,e,f,h,l=1<b.length,k=0,n=g(a,c),q=[],m={},u=!0,p=0;return this.$watch(n,function(){u?(u=!1,b(e,e,d)):b(e,h,d);if(l)if(P(e))if(Sa(e)){h=Array(e.length);for(var a=0;a<e.length;a++)h[a]=e[a]}else for(a in h={},e)rc.call(e,a)&&(h[a]=e[a]);else h=
+e})},$digest:function(){var e,g,l,m,u,v,s=b,t,W=[],y,I;k("$digest");h.$$checkUrlChange();this===r&&null!==d&&(h.defer.cancel(d),q());c=null;do{v=!1;for(t=this;O.length;){try{I=O.shift(),I.scope.$eval(I.expression,I.locals)}catch(B){f(B)}c=null}a:do{if(m=t.$$watchers)for(u=m.length;u--;)try{if(e=m[u])if((g=e.get(t))!==(l=e.last)&&!(e.eq?fa(g,l):"number"===typeof g&&"number"===typeof l&&isNaN(g)&&isNaN(l)))v=!0,c=e,e.last=e.eq?Ea(g,null):g,e.fn(g,l===n?g:l,t),5>s&&(y=4-s,W[y]||(W[y]=[]),W[y].push({msg:G(e.exp)?
+"fn: "+(e.exp.name||e.exp.toString()):e.exp,newVal:g,oldVal:l}));else if(e===c){v=!1;break a}}catch(D){f(D)}if(!(m=t.$$childHead||t!==this&&t.$$nextSibling))for(;t!==this&&!(m=t.$$nextSibling);)t=t.$parent}while(t=m);if((v||O.length)&&!s--)throw r.$$phase=null,a("infdig",b,W);}while(v||O.length);for(r.$$phase=null;p.length;)try{p.shift()()}catch(ca){f(ca)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;if(this!==r){for(var b in this.$$listenerCount)m(this,
+this.$$listenerCount[b],b);a.$$childHead==this&&(a.$$childHead=this.$$nextSibling);a.$$childTail==this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=C;this.$on=this.$watch=this.$watchGroup=function(){return C};this.$$listeners={};this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=
+this.$$childTail=this.$root=this.$$watchers=null}}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a,b){r.$$phase||O.length||h.defer(function(){O.length&&r.$digest()});O.push({scope:this,expression:a,locals:b})},$$postDigest:function(a){p.push(a)},$apply:function(a){try{return k("$apply"),this.$eval(a)}catch(b){f(b)}finally{r.$$phase=null;try{r.$digest()}catch(c){throw f(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&v.push(b);u()},$on:function(a,b){var c=this.$$listeners[a];
+c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,m(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,g=!1,h={name:a,targetScope:e,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},l=Xa([h],arguments,1),k,n;do{d=e.$$listeners[a]||c;h.currentScope=e;k=0;for(n=d.length;k<n;k++)if(d[k])try{d[k].apply(null,
+l)}catch(m){f(m)}else d.splice(k,1),k--,n--;if(g)return h.currentScope=null,h;e=e.$parent}while(e);h.currentScope=null;return h},$broadcast:function(a,b){var c=this,d=this,e={name:a,targetScope:this,preventDefault:function(){e.defaultPrevented=!0},defaultPrevented:!1};if(!this.$$listenerCount[a])return e;for(var g=Xa([e],arguments,1),h,l;c=d;){e.currentScope=c;d=c.$$listeners[a]||[];h=0;for(l=d.length;h<l;h++)if(d[h])try{d[h].apply(null,g)}catch(k){f(k)}else d.splice(h,1),h--,l--;if(!(d=c.$$listenerCount[a]&&
+c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent}e.currentScope=null;return e}};var r=new l,O=r.$$asyncQueue=[],p=r.$$postDigestQueue=[],v=r.$$applyAsyncQueue=[];return r}]}function Sd(){var b=/^\s*(https?|ftp|mailto|tel|file):/,a=/^\s*((https?|ftp|file|blob):|data:image\/)/;this.aHrefSanitizationWhitelist=function(a){return y(a)?(b=a,this):b};this.imgSrcSanitizationWhitelist=function(b){return y(b)?(a=b,this):a};this.$get=function(){return function(c,d){var e=
+d?a:b,f;f=Ba(c).href;return""===f||f.match(e)?c:"unsafe:"+f}}}function Df(b){if("self"===b)return b;if(H(b)){if(-1<b.indexOf("***"))throw Ca("iwcard",b);b=gd(b).replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*");return new RegExp("^"+b+"$")}if(ob(b))return new RegExp("^"+b.source+"$");throw Ca("imatcher");}function hd(b){var a=[];y(b)&&s(b,function(b){a.push(Df(b))});return a}function Te(){this.SCE_CONTEXTS=ma;var b=["self"],a=[];this.resourceUrlWhitelist=function(a){arguments.length&&(b=hd(a));return b};
+this.resourceUrlBlacklist=function(b){arguments.length&&(a=hd(b));return a};this.$get=["$injector",function(c){function d(a,b){return"self"===a?Zc(b):!!a.exec(b.href)}function e(a){var b=function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var f=function(a){throw Ca("unsafe");};c.has("$sanitize")&&(f=c.get("$sanitize"));
+var g=e(),h={};h[ma.HTML]=e(g);h[ma.CSS]=e(g);h[ma.URL]=e(g);h[ma.JS]=e(g);h[ma.RESOURCE_URL]=e(h[ma.URL]);return{trustAs:function(a,b){var c=h.hasOwnProperty(a)?h[a]:null;if(!c)throw Ca("icontext",a,b);if(null===b||b===t||""===b)return b;if("string"!==typeof b)throw Ca("itype",a);return new c(b)},getTrusted:function(c,e){if(null===e||e===t||""===e)return e;var g=h.hasOwnProperty(c)?h[c]:null;if(g&&e instanceof g)return e.$$unwrapTrustedValue();if(c===ma.RESOURCE_URL){var g=Ba(e.toString()),n,q,u=
+!1;n=0;for(q=b.length;n<q;n++)if(d(b[n],g)){u=!0;break}if(u)for(n=0,q=a.length;n<q;n++)if(d(a[n],g)){u=!1;break}if(u)return e;throw Ca("insecurl",e.toString());}if(c===ma.HTML)return f(e);throw Ca("unsafe");},valueOf:function(a){return a instanceof g?a.$$unwrapTrustedValue():a}}}]}function Se(){var b=!0;this.enabled=function(a){arguments.length&&(b=!!a);return b};this.$get=["$parse","$sceDelegate",function(a,c){if(b&&8>Qa)throw Ca("iequirks");var d=qa(ma);d.isEnabled=function(){return b};d.trustAs=
+c.trustAs;d.getTrusted=c.getTrusted;d.valueOf=c.valueOf;b||(d.trustAs=d.getTrusted=function(a,b){return b},d.valueOf=oa);d.parseAs=function(b,c){var e=a(c);return e.literal&&e.constant?e:a(c,function(a){return d.getTrusted(b,a)})};var e=d.parseAs,f=d.getTrusted,g=d.trustAs;s(ma,function(a,b){var c=Q(b);d[bb("parse_as_"+c)]=function(b){return e(a,b)};d[bb("get_trusted_"+c)]=function(b){return f(a,b)};d[bb("trust_as_"+c)]=function(b){return g(a,b)}});return d}]}function Ue(){this.$get=["$window","$document",
+function(b,a){var c={},d=ba((/android (\d+)/.exec(Q((b.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),f=a[0]||{},g,h=/^(Moz|webkit|ms)(?=[A-Z])/,l=f.body&&f.body.style,k=!1,m=!1;if(l){for(var n in l)if(k=h.exec(n)){g=k[0];g=g.substr(0,1).toUpperCase()+g.substr(1);break}g||(g="WebkitOpacity"in l&&"webkit");k=!!("transition"in l||g+"Transition"in l);m=!!("animation"in l||g+"Animation"in l);!d||k&&m||(k=H(f.body.style.webkitTransition),m=H(f.body.style.webkitAnimation))}return{history:!(!b.history||
+!b.history.pushState||4>d||e),hasEvent:function(a){if("input"===a&&11>=Qa)return!1;if(D(c[a])){var b=f.createElement("div");c[a]="on"+a in b}return c[a]},csp:$a(),vendorPrefix:g,transitions:k,animations:m,android:d}}]}function We(){this.$get=["$templateCache","$http","$q",function(b,a,c){function d(e,f){d.totalPendingRequests++;var g=a.defaults&&a.defaults.transformResponse;x(g)?g=g.filter(function(a){return a!==Yb}):g===Yb&&(g=null);return a.get(e,{cache:b,transformResponse:g}).then(function(a){d.totalPendingRequests--;
+return a.data},function(a){d.totalPendingRequests--;if(!f)throw ja("tpload",e);return c.reject(a)})}d.totalPendingRequests=0;return d}]}function Xe(){this.$get=["$rootScope","$browser","$location",function(b,a,c){return{findBindings:function(a,b,c){a=a.getElementsByClassName("ng-binding");var g=[];s(a,function(a){var d=ga.element(a).data("$binding");d&&s(d,function(d){c?(new RegExp("(^|\\s)"+gd(b)+"(\\s|\\||$)")).test(d)&&g.push(a):-1!=d.indexOf(b)&&g.push(a)})});return g},findModels:function(a,b,
+c){for(var g=["ng-","data-ng-","ng\\:"],h=0;h<g.length;++h){var l=a.querySelectorAll("["+g[h]+"model"+(c?"=":"*=")+'"'+b+'"]');if(l.length)return l}},getLocation:function(){return c.url()},setLocation:function(a){a!==c.url()&&(c.url(a),b.$digest())},whenStable:function(b){a.notifyWhenNoOutstandingRequests(b)}}}]}function Ye(){this.$get=["$rootScope","$browser","$q","$$q","$exceptionHandler",function(b,a,c,d,e){function f(f,l,k){var m=y(k)&&!k,n=(m?d:c).defer(),q=n.promise;l=a.defer(function(){try{n.resolve(f())}catch(a){n.reject(a),
+e(a)}finally{delete g[q.$$timeoutId]}m||b.$apply()},l);q.$$timeoutId=l;g[l]=n;return q}var g={};f.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),delete g[b.$$timeoutId],a.defer.cancel(b.$$timeoutId)):!1};return f}]}function Ba(b){Qa&&(Z.setAttribute("href",b),b=Z.href);Z.setAttribute("href",b);return{href:Z.href,protocol:Z.protocol?Z.protocol.replace(/:$/,""):"",host:Z.host,search:Z.search?Z.search.replace(/^\?/,""):"",hash:Z.hash?Z.hash.replace(/^#/,""):"",hostname:Z.hostname,
+port:Z.port,pathname:"/"===Z.pathname.charAt(0)?Z.pathname:"/"+Z.pathname}}function Zc(b){b=H(b)?Ba(b):b;return b.protocol===id.protocol&&b.host===id.host}function Ze(){this.$get=da(M)}function Dc(b){function a(c,d){if(P(c)){var e={};s(c,function(b,c){e[c]=a(c,b)});return e}return b.factory(c+"Filter",d)}this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+"Filter")}}];a("currency",jd);a("date",kd);a("filter",Ef);a("json",Ff);a("limitTo",Gf);a("lowercase",Hf);a("number",
+ld);a("orderBy",md);a("uppercase",If)}function Ef(){return function(b,a,c){if(!x(b))return b;var d;switch(typeof a){case "function":break;case "boolean":case "number":case "string":d=!0;case "object":a=Jf(a,c,d);break;default:return b}return b.filter(a)}}function Jf(b,a,c){!0===a?a=fa:G(a)||(a=function(a,b){if(P(a)||P(b))return!1;a=Q(""+a);b=Q(""+b);return-1!==a.indexOf(b)});return function(d){return hb(d,b,a,c)}}function hb(b,a,c,d){var e=typeof b,f=typeof a;if("string"===f&&"!"===a.charAt(0))return!hb(b,
+a.substring(1),c,d);if("array"===e)return b.some(function(b){return hb(b,a,c,d)});switch(e){case "object":var g;if(d){for(g in b)if("$"!==g.charAt(0)&&hb(b[g],a,c))return!0;return!1}if("object"===f){for(g in a)if(e=a[g],!G(e)&&(f="$"===g,!hb(f?b:b[g],e,c,f)))return!1;return!0}return c(b,a);case "function":return!1;default:return c(b,a)}}function jd(b){var a=b.NUMBER_FORMATS;return function(b,d,e){D(d)&&(d=a.CURRENCY_SYM);D(e)&&(e=a.PATTERNS[1].maxFrac);return null==b?b:nd(b,a.PATTERNS[1],a.GROUP_SEP,
+a.DECIMAL_SEP,e).replace(/\u00A4/g,d)}}function ld(b){var a=b.NUMBER_FORMATS;return function(b,d){return null==b?b:nd(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function nd(b,a,c,d,e){if(!isFinite(b)||P(b))return"";var f=0>b;b=Math.abs(b);var g=b+"",h="",l=[],k=!1;if(-1!==g.indexOf("e")){var m=g.match(/([\d\.]+)e(-?)(\d+)/);m&&"-"==m[2]&&m[3]>e+1?b=0:(h=g,k=!0)}if(k)0<e&&1>b&&(h=b.toFixed(e),b=parseFloat(h));else{g=(g.split(od)[1]||"").length;D(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));
+b=+(Math.round(+(b.toString()+"e"+e)).toString()+"e"+-e);var g=(""+b).split(od),k=g[0],g=g[1]||"",n=0,q=a.lgSize,u=a.gSize;if(k.length>=q+u)for(n=k.length-q,m=0;m<n;m++)0===(n-m)%u&&0!==m&&(h+=c),h+=k.charAt(m);for(m=n;m<k.length;m++)0===(k.length-m)%q&&0!==m&&(h+=c),h+=k.charAt(m);for(;g.length<e;)g+="0";e&&"0"!==e&&(h+=d+g.substr(0,e))}0===b&&(f=!1);l.push(f?a.negPre:a.posPre,h,f?a.negSuf:a.posSuf);return l.join("")}function Hb(b,a,c){var d="";0>b&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&
+(b=b.substr(b.length-a));return d+b}function $(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(0<c||e>-c)e+=c;0===e&&-12==c&&(e=12);return Hb(e,a,d)}}function Ib(b,a){return function(c,d){var e=c["get"+b](),f=ub(a?"SHORT"+b:b);return d[f][e]}}function pd(b){var a=(new Date(b,0,1)).getDay();return new Date(b,0,(4>=a?5:12)-a)}function qd(b){return function(a){var c=pd(a.getFullYear());a=+new Date(a.getFullYear(),a.getMonth(),a.getDate()+(4-a.getDay()))-+c;a=1+Math.round(a/6048E5);return Hb(a,b)}}
+function kd(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,l=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=ba(b[9]+b[10]),g=ba(b[9]+b[11]));h.call(a,ba(b[1]),ba(b[2])-1,ba(b[3]));f=ba(b[4]||0)-f;g=ba(b[5]||0)-g;h=ba(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));l.call(a,f,g,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e,f){var g="",h=[],l,k;e=e||
+"mediumDate";e=b.DATETIME_FORMATS[e]||e;H(c)&&(c=Kf.test(c)?ba(c):a(c));V(c)&&(c=new Date(c));if(!pa(c))return c;for(;e;)(k=Lf.exec(e))?(h=Xa(h,k,1),e=h.pop()):(h.push(e),e=null);f&&"UTC"===f&&(c=new Date(c.getTime()),c.setMinutes(c.getMinutes()+c.getTimezoneOffset()));s(h,function(a){l=Mf[a];g+=l?l(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Ff(){return function(b,a){D(a)&&(a=2);return Za(b,a)}}function Gf(){return function(b,a){V(b)&&(b=b.toString());if(!x(b)&&
+!H(b))return b;a=Infinity===Math.abs(Number(a))?Number(a):ba(a);if(H(b))return a?0<=a?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0<a?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function md(b){return function(a,c,d){function e(a,b){return b?function(b,c){return a(c,b)}:a}function f(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}function g(a){return null===a?"null":"function"===
+typeof a.toString&&(a=a.toString(),f(a))||"function"===typeof a.valueOf&&(a=a.valueOf(),f(a))?a:""}function h(a,b){var c=typeof a,d=typeof b;c===d&&"object"===c&&(a=g(a),b=g(b));return c===d?("string"===c&&(a=a.toLowerCase(),b=b.toLowerCase()),a===b?0:a<b?-1:1):c<d?-1:1}if(!Sa(a))return a;c=x(c)?c:[c];0===c.length&&(c=["+"]);c=c.map(function(a){var c=!1,d=a||oa;if(H(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))c="-"==a.charAt(0),a=a.substring(1);if(""===a)return e(function(a,b){return h(a,b)},c);d=b(a);
+if(d.constant){var f=d();return e(function(a,b){return h(a[f],b[f])},c)}}return e(function(a,b){return h(d(a),d(b))},c)});return Ya.call(a).sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(0!==e)return e}return 0},d))}}function Ia(b){G(b)&&(b={link:b});b.restrict=b.restrict||"AC";return da(b)}function rd(b,a,c,d,e){var f=this,g=[],h=f.$$parentForm=b.parent().controller("form")||Jb;f.$error={};f.$$success={};f.$pending=t;f.$name=e(a.name||a.ngForm||"")(c);f.$dirty=!1;f.$pristine=
+!0;f.$valid=!0;f.$invalid=!1;f.$submitted=!1;h.$addControl(f);f.$rollbackViewValue=function(){s(g,function(a){a.$rollbackViewValue()})};f.$commitViewValue=function(){s(g,function(a){a.$commitViewValue()})};f.$addControl=function(a){La(a.$name,"input");g.push(a);a.$name&&(f[a.$name]=a)};f.$$renameControl=function(a,b){var c=a.$name;f[c]===a&&delete f[c];f[b]=a;a.$name=b};f.$removeControl=function(a){a.$name&&f[a.$name]===a&&delete f[a.$name];s(f.$pending,function(b,c){f.$setValidity(c,null,a)});s(f.$error,
+function(b,c){f.$setValidity(c,null,a)});Wa(g,a)};sd({ctrl:this,$element:b,set:function(a,b,c){var d=a[b];d?-1===d.indexOf(c)&&d.push(c):a[b]=[c]},unset:function(a,b,c){var d=a[b];d&&(Wa(d,c),0===d.length&&delete a[b])},parentForm:h,$animate:d});f.$setDirty=function(){d.removeClass(b,Ra);d.addClass(b,Kb);f.$dirty=!0;f.$pristine=!1;h.$setDirty()};f.$setPristine=function(){d.setClass(b,Ra,Kb+" ng-submitted");f.$dirty=!1;f.$pristine=!0;f.$submitted=!1;s(g,function(a){a.$setPristine()})};f.$setUntouched=
+function(){s(g,function(a){a.$setUntouched()})};f.$setSubmitted=function(){d.addClass(b,"ng-submitted");f.$submitted=!0;h.$setSubmitted()}}function hc(b){b.$formatters.push(function(a){return b.$isEmpty(a)?a:a.toString()})}function ib(b,a,c,d,e,f){var g=Q(a[0].type);if(!e.android){var h=!1;a.on("compositionstart",function(a){h=!0});a.on("compositionend",function(){h=!1;l()})}var l=function(b){k&&(f.defer.cancel(k),k=null);if(!h){var e=a.val();b=b&&b.type;"password"===g||c.ngTrim&&"false"===c.ngTrim||
+(e=U(e));(d.$viewValue!==e||""===e&&d.$$hasNativeValidators)&&d.$setViewValue(e,b)}};if(e.hasEvent("input"))a.on("input",l);else{var k,m=function(a,b,c){k||(k=f.defer(function(){k=null;b&&b.value===c||l(a)}))};a.on("keydown",function(a){var b=a.keyCode;91===b||15<b&&19>b||37<=b&&40>=b||m(a,this,this.value)});if(e.hasEvent("paste"))a.on("paste cut",m)}a.on("change",l);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)}}function Lb(b,a){return function(c,d){var e,f;if(pa(c))return c;
+if(H(c)){'"'==c.charAt(0)&&'"'==c.charAt(c.length-1)&&(c=c.substring(1,c.length-1));if(Nf.test(c))return new Date(c);b.lastIndex=0;if(e=b.exec(c))return e.shift(),f=d?{yyyy:d.getFullYear(),MM:d.getMonth()+1,dd:d.getDate(),HH:d.getHours(),mm:d.getMinutes(),ss:d.getSeconds(),sss:d.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},s(e,function(b,c){c<a.length&&(f[a[c]]=+b)}),new Date(f.yyyy,f.MM-1,f.dd,f.HH,f.mm,f.ss||0,1E3*f.sss||0)}return NaN}}function jb(b,a,c,d){return function(e,
+f,g,h,l,k,m){function n(a){return a&&!(a.getTime&&a.getTime()!==a.getTime())}function q(a){return y(a)?pa(a)?a:c(a):t}td(e,f,g,h);ib(e,f,g,h,l,k);var u=h&&h.$options&&h.$options.timezone,r;h.$$parserName=b;h.$parsers.push(function(b){return h.$isEmpty(b)?null:a.test(b)?(b=c(b,r),"UTC"===u&&b.setMinutes(b.getMinutes()-b.getTimezoneOffset()),b):t});h.$formatters.push(function(a){if(a&&!pa(a))throw Mb("datefmt",a);if(n(a)){if((r=a)&&"UTC"===u){var b=6E4*r.getTimezoneOffset();r=new Date(r.getTime()+b)}return m("date")(a,
+d,u)}r=null;return""});if(y(g.min)||g.ngMin){var s;h.$validators.min=function(a){return!n(a)||D(s)||c(a)>=s};g.$observe("min",function(a){s=q(a);h.$validate()})}if(y(g.max)||g.ngMax){var p;h.$validators.max=function(a){return!n(a)||D(p)||c(a)<=p};g.$observe("max",function(a){p=q(a);h.$validate()})}}}function td(b,a,c,d){(d.$$hasNativeValidators=P(a[0].validity))&&d.$parsers.push(function(b){var c=a.prop("validity")||{};return c.badInput&&!c.typeMismatch?t:b})}function ud(b,a,c,d,e){if(y(d)){b=b(d);
+if(!b.constant)throw T("ngModel")("constexpr",c,d);return b(a)}return e}function sd(b){function a(a,b){b&&!f[a]?(k.addClass(e,a),f[a]=!0):!b&&f[a]&&(k.removeClass(e,a),f[a]=!1)}function c(b,c){b=b?"-"+tc(b,"-"):"";a(kb+b,!0===c);a(vd+b,!1===c)}var d=b.ctrl,e=b.$element,f={},g=b.set,h=b.unset,l=b.parentForm,k=b.$animate;f[vd]=!(f[kb]=e.hasClass(kb));d.$setValidity=function(b,e,f){e===t?(d.$pending||(d.$pending={}),g(d.$pending,b,f)):(d.$pending&&h(d.$pending,b,f),wd(d.$pending)&&(d.$pending=t));Va(e)?
+e?(h(d.$error,b,f),g(d.$$success,b,f)):(g(d.$error,b,f),h(d.$$success,b,f)):(h(d.$error,b,f),h(d.$$success,b,f));d.$pending?(a(xd,!0),d.$valid=d.$invalid=t,c("",null)):(a(xd,!1),d.$valid=wd(d.$error),d.$invalid=!d.$valid,c("",d.$valid));e=d.$pending&&d.$pending[b]?t:d.$error[b]?!1:d.$$success[b]?!0:null;c(b,e);l.$setValidity(b,e,d)}}function wd(b){if(b)for(var a in b)return!1;return!0}function ic(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d<a.length;d++){for(var e=
+a[d],m=0;m<b.length;m++)if(e==b[m])continue a;c.push(e)}return c}function e(a){if(!x(a)){if(H(a))return a.split(" ");if(P(a)){var b=[];s(a,function(a,c){a&&(b=b.concat(c.split(" ")))});return b}}return a}return{restrict:"AC",link:function(f,g,h){function l(a,b){var c=g.data("$classCounts")||{},d=[];s(a,function(a){if(0<b||c[a])c[a]=(c[a]||0)+b,c[a]===+(0<b)&&d.push(a)});g.data("$classCounts",c);return d.join(" ")}function k(b){if(!0===a||f.$index%2===a){var k=e(b||[]);if(!m){var u=l(k,1);h.$addClass(u)}else if(!fa(b,
+m)){var r=e(m),u=d(k,r),k=d(r,k),u=l(u,1),k=l(k,-1);u&&u.length&&c.addClass(g,u);k&&k.length&&c.removeClass(g,k)}}m=qa(b)}var m;f.$watch(h[b],k,!0);h.$observe("class",function(a){k(f.$eval(h[b]))});"ngClass"!==b&&f.$watch("$index",function(c,d){var g=c&1;if(g!==(d&1)){var k=e(f.$eval(h[b]));g===a?(g=l(k,1),h.$addClass(g)):(g=l(k,-1),h.$removeClass(g))}})}}}]}var Of=/^\/(.+)\/([a-z]*)$/,Q=function(b){return H(b)?b.toLowerCase():b},rc=Object.prototype.hasOwnProperty,ub=function(b){return H(b)?b.toUpperCase():
+b},Qa,B,ra,Ya=[].slice,rf=[].splice,Pf=[].push,Da=Object.prototype.toString,Ja=T("ng"),ga=M.angular||(M.angular={}),ab,nb=0;Qa=Y.documentMode;C.$inject=[];oa.$inject=[];var x=Array.isArray,U=function(b){return H(b)?b.trim():b},gd=function(b){return b.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08")},$a=function(){if(y($a.isActive_))return $a.isActive_;var b=!(!Y.querySelector("[ng-csp]")&&!Y.querySelector("[data-ng-csp]"));if(!b)try{new Function("")}catch(a){b=!0}return $a.isActive_=
+b},rb=["ng-","data-ng-","ng:","x-ng-"],Md=/[A-Z]/g,uc=!1,Pb,na=1,pb=3,Qd={full:"1.3.7",major:1,minor:3,dot:7,codeName:"leaky-obstruction"};R.expando="ng339";var zb=R.cache={},hf=1;R._data=function(b){return this.cache[b[this.expando]]||{}};var cf=/([\:\-\_]+(.))/g,df=/^moz([A-Z])/,Qf={mouseleave:"mouseout",mouseenter:"mouseover"},Sb=T("jqLite"),gf=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Rb=/<|&#?\w+;/,ef=/<([\w:]+)/,ff=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ia={option:[1,'<select multiple="multiple">',
+"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ia.optgroup=ia.option;ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead;ia.th=ia.td;var Ka=R.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===Y.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),R(M).on("load",a))},toString:function(){var b=[];s(this,function(a){b.push(""+
+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?B(this[b]):B(this[this.length+b])},length:0,push:Pf,sort:[].sort,splice:[].splice},Eb={};s("multiple selected checked disabled readOnly required open".split(" "),function(b){Eb[Q(b)]=b});var Mc={};s("input select option textarea button form details".split(" "),function(b){Mc[b]=!0});var Nc={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};s({data:Ub,removeData:xb},function(b,a){R[a]=b});s({data:Ub,
+inheritedData:Db,scope:function(b){return B.data(b,"$scope")||Db(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return B.data(b,"$isolateScope")||B.data(b,"$isolateScopeNoTemplate")},controller:Ic,injector:function(b){return Db(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Ab,css:function(b,a,c){a=bb(a);if(y(c))b.style[a]=c;else return b.style[a]},attr:function(b,a,c){var d=Q(a);if(Eb[d])if(y(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));
+else return b[a]||(b.attributes.getNamedItem(a)||C).specified?d:t;else if(y(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?t:b},prop:function(b,a,c){if(y(c))b[a]=c;else return b[a]},text:function(){function b(a,b){if(D(b)){var d=a.nodeType;return d===na||d===pb?a.textContent:""}a.textContent=b}b.$dv="";return b}(),val:function(b,a){if(D(a)){if(b.multiple&&"select"===ua(b)){var c=[];s(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?
+null:c}return b.value}b.value=a},html:function(b,a){if(D(a))return b.innerHTML;wb(b,!0);b.innerHTML=a},empty:Jc},function(b,a){R.prototype[a]=function(a,d){var e,f,g=this.length;if(b!==Jc&&(2==b.length&&b!==Ab&&b!==Ic?a:d)===t){if(P(a)){for(e=0;e<g;e++)if(b===Ub)b(this[e],a);else for(f in a)b(this[e],f,a[f]);return this}e=b.$dv;g=e===t?Math.min(g,1):g;for(f=0;f<g;f++){var h=b(this[f],a,d);e=e?e+h:h}return e}for(e=0;e<g;e++)b(this[e],a,d);return this}});s({removeData:xb,on:function a(c,d,e,f){if(y(f))throw Sb("onargs");
+if(Ec(c)){var g=yb(c,!0);f=g.events;var h=g.handle;h||(h=g.handle=lf(c,f));for(var g=0<=d.indexOf(" ")?d.split(" "):[d],l=g.length;l--;){d=g[l];var k=f[d];k||(f[d]=[],"mouseenter"===d||"mouseleave"===d?a(c,Qf[d],function(a){var c=a.relatedTarget;c&&(c===this||this.contains(c))||h(a,d)}):"$destroy"!==d&&c.addEventListener(d,h,!1),k=f[d]);k.push(e)}}},off:Hc,one:function(a,c,d){a=B(a);a.on(c,function f(){a.off(c,d);a.off(c,f)});a.on(c,d)},replaceWith:function(a,c){var d,e=a.parentNode;wb(a);s(new R(c),
+function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];s(a.childNodes,function(a){a.nodeType===na&&c.push(a)});return c},contents:function(a){return a.contentDocument||a.childNodes||[]},append:function(a,c){var d=a.nodeType;if(d===na||11===d){c=new R(c);for(var d=0,e=c.length;d<e;d++)a.appendChild(c[d])}},prepend:function(a,c){if(a.nodeType===na){var d=a.firstChild;s(new R(c),function(c){a.insertBefore(c,d)})}},wrap:function(a,c){c=B(c).eq(0).clone()[0];
+var d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:Kc,detach:function(a){Kc(a,!0)},after:function(a,c){var d=a,e=a.parentNode;c=new R(c);for(var f=0,g=c.length;f<g;f++){var h=c[f];e.insertBefore(h,d.nextSibling);d=h}},addClass:Cb,removeClass:Bb,toggleClass:function(a,c,d){c&&s(c.split(" "),function(c){var f=d;D(f)&&(f=!Ab(a,c));(f?Cb:Bb)(a,c)})},parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null},next:function(a){return a.nextElementSibling},find:function(a,c){return a.getElementsByTagName?
+a.getElementsByTagName(c):[]},clone:Tb,triggerHandler:function(a,c,d){var e,f,g=c.type||c,h=yb(a);if(h=(h=h&&h.events)&&h[g])e={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return!0===this.defaultPrevented},stopImmediatePropagation:function(){this.immediatePropagationStopped=!0},isImmediatePropagationStopped:function(){return!0===this.immediatePropagationStopped},stopPropagation:C,type:g,target:a},c.type&&(e=z(e,c)),c=qa(h),f=d?[e].concat(d):[e],s(c,function(c){e.isImmediatePropagationStopped()||
+c.apply(a,f)})}},function(a,c){R.prototype[c]=function(c,e,f){for(var g,h=0,l=this.length;h<l;h++)D(g)?(g=a(this[h],c,e,f),y(g)&&(g=B(g))):Gc(g,a(this[h],c,e,f));return y(g)?g:this};R.prototype.bind=R.prototype.on;R.prototype.unbind=R.prototype.off});cb.prototype={put:function(a,c){this[Ma(a,this.nextUid)]=c},get:function(a){return this[Ma(a,this.nextUid)]},remove:function(a){var c=this[a=Ma(a,this.nextUid)];delete this[a];return c}};var Pc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,nf=/,/,of=/^\s*(_?)(\S+?)\1\s*$/,
+Oc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Ga=T("$injector");Ob.$$annotate=Vb;var Rf=T("$animate"),Ce=["$provide",function(a){this.$$selectors={};this.register=function(c,d){var e=c+"-animation";if(c&&"."!=c.charAt(0))throw Rf("notcsel",c);this.$$selectors[c.substr(1)]=e;a.factory(e,d)};this.classNameFilter=function(a){1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?a:null);return this.$$classNameFilter};this.$get=["$$q","$$asyncCallback","$rootScope",function(a,d,e){function f(d){var f,
+g=a.defer();g.promise.$$cancelFn=function(){f&&f()};e.$$postDigest(function(){f=d(function(){g.resolve()})});return g.promise}function g(a,c){var d=[],e=[],f=ha();s((a.attr("class")||"").split(/\s+/),function(a){f[a]=!0});s(c,function(a,c){var g=f[c];!1===a&&g?e.push(c):!0!==a||g||d.push(c)});return 0<d.length+e.length&&[d.length?d:null,e.length?e:null]}function h(a,c,d){for(var e=0,f=c.length;e<f;++e)a[c[e]]=d}function l(){m||(m=a.defer(),d(function(){m.resolve();m=null}));return m.promise}function k(a,
+c){if(ga.isObject(c)){var d=z(c.from||{},c.to||{});a.css(d)}}var m;return{animate:function(a,c,d){k(a,{from:c,to:d});return l()},enter:function(a,c,d,e){k(a,e);d?d.after(a):c.prepend(a);return l()},leave:function(a,c){a.remove();return l()},move:function(a,c,d,e){return this.enter(a,c,d,e)},addClass:function(a,c,d){return this.setClass(a,c,[],d)},$$addClassImmediately:function(a,c,d){a=B(a);c=H(c)?c:x(c)?c.join(" "):"";s(a,function(a){Cb(a,c)});k(a,d);return l()},removeClass:function(a,c,d){return this.setClass(a,
+[],c,d)},$$removeClassImmediately:function(a,c,d){a=B(a);c=H(c)?c:x(c)?c.join(" "):"";s(a,function(a){Bb(a,c)});k(a,d);return l()},setClass:function(a,c,d,e){var k=this,l=!1;a=B(a);var m=a.data("$$animateClasses");m?e&&m.options&&(m.options=ga.extend(m.options||{},e)):(m={classes:{},options:e},l=!0);e=m.classes;c=x(c)?c:c.split(" ");d=x(d)?d:d.split(" ");h(e,c,!0);h(e,d,!1);l&&(m.promise=f(function(c){var d=a.data("$$animateClasses");a.removeData("$$animateClasses");if(d){var e=g(a,d.classes);e&&
+k.$$setClassImmediately(a,e[0],e[1],d.options)}c()}),a.data("$$animateClasses",m));return m.promise},$$setClassImmediately:function(a,c,d,e){c&&this.$$addClassImmediately(a,c);d&&this.$$removeClassImmediately(a,d);k(a,e);return l()},enabled:C,cancel:C}}]}],ja=T("$compile");wc.$inject=["$provide","$$sanitizeUriProvider"];var Rc=/^((?:x|data)[\:\-_])/i,Vc="application/json",Zb={"Content-Type":Vc+";charset=utf-8"},tf=/^\[|^\{(?!\{)/,uf={"[":/]$/,"{":/}$/},sf=/^\)\]\}',?\n/,$b=T("$interpolate"),Sf=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
+xf={http:80,https:443,ftp:21},Fb=T("$location"),Tf={$$html5:!1,$$replace:!1,absUrl:Gb("$$absUrl"),url:function(a){if(D(a))return this.$$url;var c=Sf.exec(a);(c[1]||""===a)&&this.path(decodeURIComponent(c[1]));(c[2]||c[1]||""===a)&&this.search(c[3]||"");this.hash(c[5]||"");return this},protocol:Gb("$$protocol"),host:Gb("$$host"),port:Gb("$$port"),path:dd("$$path",function(a){a=null!==
<TRUNCATED>
[11/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/mudrod_service.log.2016-10-13
----------------------------------------------------------------------
diff --git a/service/mudrod_service.log.2016-10-13 b/service/mudrod_service.log.2016-10-13
new file mode 100644
index 0000000..55bb7b1
--- /dev/null
+++ b/service/mudrod_service.log.2016-10-13
@@ -0,0 +1,1064 @@
+2016-10-13 10:22:53,736 INFO elasticsearch.plugins - [Plantman] modules [], plugins [], sites []
+2016-10-13 10:22:54,863 WARN util.NativeCodeLoader - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
+2016-10-13 10:22:55,468 INFO util.log - Logging initialized @27861ms
+2016-10-13 10:22:55,540 INFO server.Server - jetty-9.2.z-SNAPSHOT
+2016-10-13 10:22:55,555 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@33995523{/jobs,null,AVAILABLE}
+2016-10-13 10:22:55,555 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@54ca3956{/jobs/json,null,AVAILABLE}
+2016-10-13 10:22:55,556 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@4bd84a98{/jobs/job,null,AVAILABLE}
+2016-10-13 10:22:55,556 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@4365de48{/jobs/job/json,null,AVAILABLE}
+2016-10-13 10:22:55,556 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@3a2cab4a{/stages,null,AVAILABLE}
+2016-10-13 10:22:55,557 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@3f2925d0{/stages/json,null,AVAILABLE}
+2016-10-13 10:22:55,557 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@36ac2427{/stages/stage,null,AVAILABLE}
+2016-10-13 10:22:55,557 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@5b562b24{/stages/stage/json,null,AVAILABLE}
+2016-10-13 10:22:55,558 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@47fadff{/stages/pool,null,AVAILABLE}
+2016-10-13 10:22:55,558 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@720e0f05{/stages/pool/json,null,AVAILABLE}
+2016-10-13 10:22:55,559 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@25d4907f{/storage,null,AVAILABLE}
+2016-10-13 10:22:55,559 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@4f3190ea{/storage/json,null,AVAILABLE}
+2016-10-13 10:22:55,560 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@36d8cca6{/storage/rdd,null,AVAILABLE}
+2016-10-13 10:22:55,561 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@34ac9b5f{/storage/rdd/json,null,AVAILABLE}
+2016-10-13 10:22:55,561 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@357aa2dd{/environment,null,AVAILABLE}
+2016-10-13 10:22:55,562 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@768fc258{/environment/json,null,AVAILABLE}
+2016-10-13 10:22:55,562 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@6c29dd3{/executors,null,AVAILABLE}
+2016-10-13 10:22:55,562 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@56e48837{/executors/json,null,AVAILABLE}
+2016-10-13 10:22:55,563 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@36e8a47c{/executors/threadDump,null,AVAILABLE}
+2016-10-13 10:22:55,563 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@3efd3dfb{/executors/threadDump/json,null,AVAILABLE}
+2016-10-13 10:22:55,568 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@2cc303f2{/static,null,AVAILABLE}
+2016-10-13 10:22:55,568 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@5e14836d{/,null,AVAILABLE}
+2016-10-13 10:22:55,569 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@2dac1797{/api,null,AVAILABLE}
+2016-10-13 10:22:55,570 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@7ae9f53c{/stages/stage/kill,null,AVAILABLE}
+2016-10-13 10:22:55,576 INFO server.ServerConnector - Started ServerConnector@7c44d8af{HTTP/1.1}{0.0.0.0:4040}
+2016-10-13 10:22:55,576 INFO server.Server - Started @27970ms
+2016-10-13 10:22:55,899 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@21ef5820{/metrics/json,null,AVAILABLE}
+2016-10-13 10:22:56,915 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@18f65a5{/SQL,null,AVAILABLE}
+2016-10-13 10:22:56,916 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@427c96f1{/SQL/json,null,AVAILABLE}
+2016-10-13 10:22:56,917 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@14917a7b{/SQL/execution,null,AVAILABLE}
+2016-10-13 10:22:56,917 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@425a9bf9{/SQL/execution/json,null,AVAILABLE}
+2016-10-13 10:22:56,918 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@62fc895{/static/sql,null,AVAILABLE}
+2016-10-13 10:22:59,462 WARN hadoop.ParquetRecordReader - Can not initialize counter due to context is not a instance of TaskInputOutputContext, but is org.apache.hadoop.mapreduce.task.TaskAttemptContextImpl
+2016-10-13 10:22:59,733 INFO ontology.OntologyFactory - Using ontology extension: Local
+2016-10-13 10:22:59,737 INFO process.LocalOntology - Creating new ontology
+2016-10-13 10:23:00,142 WARN impl.RDFDefaultErrorHandler - unknown-source: {W136} Relative URIs are not permitted in RDF: specifically <ont-policy.rdf>
+2016-10-13 10:25:31,381 INFO search.SearchMetadataResource - Response received: {}
+2016-10-13 10:25:31,387 ERROR utils.JAXRSUtils - No message body writer has been found for class com.google.gson.JsonObject, ContentType: application/json
+2016-10-13 10:25:31,395 INFO ontology.OntologyResource - Response received: []
+2016-10-13 10:25:31,395 INFO ontology.OntologyResource - Response received: []
+2016-10-13 10:25:31,560 INFO integration.LinkageIntegration -
+************************ UserHistoryLinkage results***************************
+2016-10-13 10:25:31,577 INFO integration.LinkageIntegration - ( atmospheric water vapor 0.42 )
+2016-10-13 10:25:31,578 INFO integration.LinkageIntegration - ( oscat 0.42 )
+2016-10-13 10:25:31,578 INFO integration.LinkageIntegration - ( radar 0.41 )
+2016-10-13 10:25:31,578 INFO integration.LinkageIntegration - ( tellu 0.36 )
+2016-10-13 10:25:31,578 INFO integration.LinkageIntegration - ( tellu land 0.35 )
+2016-10-13 10:25:31,578 INFO integration.LinkageIntegration - ( tellu ocean 0.35 )
+2016-10-13 10:25:31,579 INFO integration.LinkageIntegration - ( geo 3 altimeter 0.35 )
+2016-10-13 10:25:31,579 INFO integration.LinkageIntegration - ( dmsp f08 0.35 )
+2016-10-13 10:25:31,580 INFO integration.LinkageIntegration - ( aquarius radiometer 0.33 )
+2016-10-13 10:25:31,580 INFO integration.LinkageIntegration - ( atmospheric electricity 0.32 )
+2016-10-13 10:25:31,580 INFO integration.LinkageIntegration - ( ocean temperature 0.31 )
+2016-10-13 10:25:31,594 INFO integration.LinkageIntegration -
+************************ ClickStreamLinkage results***************************
+2016-10-13 10:25:31,594 INFO integration.LinkageIntegration - ( ice extent 0.86 )
+2016-10-13 10:25:31,594 INFO integration.LinkageIntegration - ( seawind adeo ii level 3 sigma 0 local time day browse dataset 0.76 )
+2016-10-13 10:25:31,595 INFO integration.LinkageIntegration - ( seawind quikscat level 3 sigma 0 local time day browse dataset 0.74 )
+2016-10-13 10:25:31,595 INFO integration.LinkageIntegration - ( sea ice age 0.73 )
+2016-10-13 10:25:31,595 INFO integration.LinkageIntegration - ( arctic 0.73 )
+2016-10-13 10:25:31,595 INFO integration.LinkageIntegration - ( ice 0.69 )
+2016-10-13 10:25:31,596 INFO integration.LinkageIntegration - ( sigma naught 0.68 )
+2016-10-13 10:25:31,596 INFO integration.LinkageIntegration - ( radar 0.64 )
+2016-10-13 10:25:31,596 INFO integration.LinkageIntegration - ( quikscat south china sea 0.63 )
+2016-10-13 10:25:31,597 INFO integration.LinkageIntegration - ( gulf mexico 0.63 )
+2016-10-13 10:25:31,597 INFO integration.LinkageIntegration - ( scat byu l3 ow sigma0 enhance 0.63 )
+2016-10-13 10:25:31,607 INFO integration.LinkageIntegration -
+************************ MetadataLinkage results***************************
+2016-10-13 10:25:31,607 INFO integration.LinkageIntegration - ( cryosphere 0.96 )
+2016-10-13 10:25:31,629 INFO integration.LinkageIntegration - ( ice extent 0.96 )
+2016-10-13 10:25:31,630 INFO integration.LinkageIntegration - ( spectral engineering 0.85 )
+2016-10-13 10:25:31,630 INFO integration.LinkageIntegration - ( sigma naught 0.74 )
+2016-10-13 10:25:31,630 INFO integration.LinkageIntegration - ( radar 0.74 )
+2016-10-13 10:25:31,631 INFO integration.LinkageIntegration - ( scp 0.7 )
+2016-10-13 10:25:31,631 INFO integration.LinkageIntegration - ( david long 0.66 )
+2016-10-13 10:25:31,631 INFO integration.LinkageIntegration - ( byu 0.66 )
+2016-10-13 10:25:31,631 INFO integration.LinkageIntegration - ( sir 0.66 )
+2016-10-13 10:25:31,631 INFO integration.LinkageIntegration - ( backscatter 0.59 )
+2016-10-13 10:25:31,632 INFO integration.LinkageIntegration - ( sigma 0 0.59 )
+2016-10-13 10:25:31,636 INFO integration.LinkageIntegration -
+************************ SWEETLinkage results***************************
+2016-10-13 10:25:33,831 INFO jni.JniLoader - successfully loaded /var/folders/mw/f_p4r21n5ld16hnyd7j8r8w4fv8362/T/jniloader1470683595192669599netlib-native_system-osx-x86_64.jnilib
+2016-10-13 10:25:34,271 INFO search.SearchMetadataResource - Response received: "{\"PDResults\":[{\"Short Name\":\"QSCAT_ARCTIC_SEAICE_AGE_CLASS_BYUSCP_V1\",\"Long Name\":\"SeaWinds on QuikSCAT Arctic Sea Ice Age Classification (BYU/SCP)\",\"Topic\":\"Sea Ice Age\",\"Abstract\":\"This SeaWinds on QuikSCAT scatterometer-derived Arctic sea ice classification dataset is provided as a service to the ocean and sea ice research communities on behalf of Dr. David Long at Brigham Young University (BYU) and the Scatterometer Climate Record Pathfinder (SCP). This dataset provides nominal 4.45 km (pixel resolution at reference latitude 70 N) gridded fields that classify First-Year (FY) and Multi-Year (MY) sea ice using SeaWinds on QuikSCAT scatterometer observations on a daily basis from 20 June 2002 through 23 November 2009. It is unique from other sea ice classification datasets primarily due to its utilization of passive microwave AMSR-E data to provide the initial ocean/i...\",\"Release
Date\":\"12/31/2012\"},{\"Short Name\":\"NSCAT_LEVEL_1.7_V2\",\"Long Name\":\"NSCAT Level 1.7 SDR, Sigma-0 Cells\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"The NASA Scatterometer (NSCAT) Level 1.7 ocean sigma-0 referenced to 50 km wind vector cells (WVC) contains daily backscatter (sigma-0) data from ascending and descending passes. Rain flagging information is not included. Data is flagged where measurements are either missing, ambiguous, or contaminated by land/sea ice. This is the most up-to-date version, which designates the final phase of calibration, validation and science data processing, which was completed in November of 1998, on behalf of the JPL NSCAT Project; re-processing had only minor impacts on the Level 1.7 data...\",\"Release Date\":\"07/22/1998\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_IMAGES_LTOD\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Images of Arctic Reg
ion\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded Sigma-0 retrievals over the Antarctic Polar region from SeaWinds on QuikSCAT retrievals subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately morning (00:00 to 08:00 local) and evening (16:00 to 24:00 local). The eight hour interval at each LTOD reference of morning vs. evening corresponds to the natural boundaries of time separation within the data at polar latitudes. Hence, morning and evening are used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. It should be noted that these GIF images are meant for browse purposes ...\",\"Release Date\":\"03/20/2012\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_IMAGES\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Browse Images of Arctic Region\",\"Topi
c\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Arctic Polar from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The GIF image files are separated according to polarization, and the averaged Sigma-0 measurements are displayed in grayscale with no color bar. Very bright areas i...\",\"Release Date\":\"11/01/2003\"},{\"Short Name\":\"ERS-2_BYU_L3_OW_SIGMA0_ENHANCED\",\"Long Name\":\"ERS-2 Gridded Level 3 Enhanced Resolution Sigma-0 from BYU\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This European Remote Sensing
(ERS) Sigma-0 dataset is generated by the Scatterometer Climate Record Pathfinder (SCP) project at Brigham Young University (BYU) and is generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at BYU. The dataset provides SIR processed Sigma-0 data from the ERS-2 C-band scatterometer, which is also known as the Active Microwave Instrument (AMI). AMI is a multimode radar operating at a frequency of 5.3 GHz (C-band), using vertically polarized antennas for both transmission and reception. The SIR technique results in an enhanced resolution image reconstruction and gridded on an equal-area grid (for non-polar regions) at 8.9...\",\"Release Date\":\"11/28/2011\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_GLOBAL_RECTANGULAR_BROWSE_MAPS_LITE\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Global Rectangular Browse Maps (Reduced)\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains global, rectangular-gridded, daily a
veraged Sigma-0 retrievals from SeaWinds on QuikSCAT retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are separated according to polarization. For example, one SIR file for a particular day will contain the globally gridded avera...\",\"Release Date\":\"03/19/2001\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_GLOBAL_RECTANGULAR_BROWSE_IMAGES\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Global Rectangular Browse Images\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of global, rectangular-gridded, daily averaged Sigma-0 retrieva
ls from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU). The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The GIF image files are separated according to polarization, and the averaged Sigma-0 measurements are displayed in grayscale with no color bar. Very bright areas indicate high Sigma-0 ...\",\"Release Date\":\"11/01/2003\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LITE\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Browse Maps (Reduced) of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Arctic Polar
region from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are separated according to polarization. For example, one SIR file for a particular day will contain the gridde...\",\"Release Date\":\"11/01/2003\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_GLOBAL_RECTANGULAR_BROWSE_IMAGES\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Global Rectangular Browse Images\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of global, rectangular-gridded, daily averaged Sigma-0 retrievals from SeaWinds on QuikSCAT retrievals, w
hich are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU). The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The GIF image files are separated according to polarization, and the averaged Sigma-0 measurements are displayed in grayscale with no color bar. Very bright areas indicate high Sigm...\",\"Release Date\":\"03/19/2001\"},{\"Short Name\":\"QUIKSCAT_BYU_L3_OW_SIGMA0_ENHANCED\",\"Long Name\":\"SeaWinds on QuikSCAT Enhanced Resolution Regionally Gridded Sigma-0 (BYU, D. Long)\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains enhanced resolution gridded fields of the normalized radar cross-section (sigma-0) made from the SeaWinds on QuikSCAT L1B dataset using two different forms of the si
ngle-variate Scatterometer Image Reconstruction (SIR) algorithm: 1) for \u0027egg\u0027 sigma-0 measurements and 2) for \u0027slice\u0027 sigma-0 measurements, where the SIR with filtering (SIRF) algorithm is used. For \u0027egg\u0027 measurements, the full antenna/processing spatial response is used while a simplified spatial response function in which the spatial response is assumed to be 1 over the footprint and 0 elsewhere is used for \u0027slice\u0027 measurements. The SIR algorithm with \u0027eggs\u0027 makes images of sigma-0 at the measurement inci...\",\"Release Date\":\"11/02/2011\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_MAPS_FULL\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Browse Maps (Complete) of Antarctica\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrieval statistics over the Antarctic Polar region from the QuikSCAT L1B retrie
vals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The QuikSCAT scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are all contained within a single tar file for a given day. When the tar file is unpacked, the individual...\",\"Release Date\":\"03/19/2001\"},{\"Short Name\":\"WENTZ_SASS_SIGMA0_L2\",\"Long Name\":\"SEASAT SCATTEROMETER BINNED 50KM SIGMA-0 DATA (Wentz)\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"Contains Seasat-A Scatterometer (SASS) Sigma-0 measurements for the entire Seasat mission, from July 1978 until October 1978, produced by Frank Wentz at Remote Sensing Systems. The data are presented chronologically by swath and co
nsist of the forward and aft values, binned in 50 km cells. For each cell there are 17 parameters including time, location, incidence angle, sigma-0, instrument corrections, and data quality...\",\"Release Date\":\"12/03/1996\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LTOD\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Maps of Antarctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrievals over the Anarctic Polar region from SeaWinds on QuikSCAT retrievals subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately morning (04:00 to 12:00 local) and afternoon (12:00 to 20:00 local). The eight hour interval at each LTOD reference of morning vs. afternoon corresponds to the natural boundaries of time separation within the data at polar latitudes. Hence, morning and afternoon
are used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. This dataset is generated using a Scatterometer Image Reconstruction (SIR) techn...\",\"Release Date\":\"03/20/2012\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LTOD\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Maps of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrievals over the Arctic Polar region from SeaWinds on QuikSCAT retrievals subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately morning (00:00 to 08:00 local) and evening (16:00 to 24:00 local). The eight hour interval at each LTOD reference of morning vs. evening corresponds to the natural boundaries of time separation within the data at polar latitudes. Hence, morning and evening are
used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. This dataset is generated using a Scatterometer Image Reconstruction (SIR) technique dev...\",\"Release Date\":\"03/20/2012\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_IMAGES_LTOD\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Images of Antarctica\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded Sigma-0 retrievals over the Antarctic Polar region from SeaWinds on QuikSCAT retrievals subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately morning (04:00 to 12:00 local) and afternoon (12:00 to 20:00 local). The eight hour interval at each LTOD reference of morning vs. afternoon corresponds to the natural boundaries of time separation within the data at polar latitudes. H
ence, morning and afternoon are used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. It should be noted that these GIF images are meant for browse pur...\",\"Release Date\":\"03/20/2012\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_IMAGES\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Browse Images of Antarctica\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Antarctic Polar from the QuikSCAT L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU). The QuikSCAT scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while
the outer beam is vertically polarized. The GIF image files are separated according to polarization, and the averaged Sigma-0 measurements are displayed in grayscale with no color bar. Very bright are...\",\"Release Date\":\"03/19/2001\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_IMAGES_LTOD\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Images of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded Sigma-0 retrievals over the Arctic Polar region from SeaWinds on ADEOS-II retrievals subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately mid-day (08:00 to 16:00 local) and evening (16:00 to 24:00 local). The eight hour interval at each LTOD reference of mid-day vs. evening corresponds to the natural boundaries of time separation within the data at polar latitudes. Hence, mid-
day and evening are used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. It should be noted that these GIF images are meant for browse purposes onl...\",\"Release Date\":\"03/20/2012\"},{\"Short Name\":\"OSTIA-UKMO-L4-GLOB-v2.0\",\"Long Name\":\"GHRSST Level 4 OSTIA Global Foundation Sea Surface Temperature Analysis (GDS version 2)\",\"Topic\":\"Sea Ice Concentration, Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at the UK Met Office using optimal interpolation (OI) on a global 0.054 degree grid. The Operational Sea Surface Temperature and Sea Ice Analysis (OSTIA) analysis uses satellite data from sensors that include the Advanced Very High Resolution Radiometer (AVHRR), the Spinning Enhanced Visible and Infrared Imager (SEVIRI), the Geostationary Operational Environmental Satellite (GO
ES) imager, the Infrared Atmospheric Sounding Interferometer (IASI), the Tropical Rainfall Measuring Mission Microwave Imager (TMI) and in situ data from ships, drifting and moor...\",\"Release Date\":\"12/18/2012\"},{\"Short Name\":\"NSCAT_BYU_L3_OW_SIGMA0_ENHANCED\",\"Long Name\":\"NSCAT Gridded Level 3 Enhanced Resolution Sigma-0 from BYU\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This NASA Scatterometer (NSCAT) satellite Sigma-0 dataset is generated by the Scatterometer Climate Record Pathfinder (SCP) project at Brigham Young University (BYU) and is generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long. The SIR technique results in an enhanced resolution image reconstruction and gridded on an equal-area grid (for non-polar regions) at 4.45 km pixel resolution stored in SIR files; polar regions are gridded using a polar-stereographic technique. A non-enhanced version is provided at 22.25 km pixel resolution in a format known
as GRD files. All files are produced in IEEE formatted binary. All data files are separated and organ...\",\"Release Date\":\"11/27/2011\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_GLOBAL_RECTANGULAR_BROWSE_MAPS_FULL\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Global Rectangular Browse Maps (Complete)\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains global, rectangular-gridded Sigma-0 retrieval statistics from SeaWinds on QuikSCAT retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are all contained within a single tar file for a given day.
When the tar file is unpacked, the individual SIR files are separated acc...\",\"Release Date\":\"03/19/2001\"},{\"Short Name\":\"ERS-1_BYU_L3_OW_SIGMA0_ENHANCED\",\"Long Name\":\"ERS-1 Gridded Level 3 Enhanced Resolution Sigma-0 from BYU\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This European Remote Sensing (ERS) Sigma-0 dataset is generated by the Scatterometer Climate Record Pathfinder (SCP) project at Brigham Young University (BYU) and is generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at BYU. The dataset provides SIR processed Sigma-0 data from the ERS-1 C-band scatterometer, which is also known as the Active Microwave Instrument (AMI). AMI is a multimode radar operating at a frequency of 5.3 GHz (C-band), using vertically polarized antennas for both transmission and reception. The SIR technique results in an enhanced resolution image reconstruction and gridded on an equal-area grid (for non-polar regions) at 8.9...
\",\"Release Date\":\"11/28/2011\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_GLOBAL_RECTANGULAR_BROWSE_MAPS_FULL\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Global Rectangular Browse Maps (Complete)\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of global, rectangular-gridded, daily averaged Sigma-0 retrievals from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU). The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The GIF image files are separated according to polarization, and the averaged Sigma-0 measurements are displayed in grayscale with no color bar. Very bright areas indicate high Sigma-0 ...\",\"Release Date\":\"11/0
1/2003\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ANTARCTIC_POLAR-STEREOGRAPHIC_BROWSE_IMAGES_LTOD\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Images of Antarctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded Sigma-0 retrievals over the Antarctic Polar region from SeaWinds on ADEOS-II subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately morning (00:00 to 08:00 local) and evening (16:00 to 24:00 local). The eight hour interval at each LTOD reference of morning vs. evening corresponds to the natural boundaries of time separation within the data at polar latitudes. Hence, morning and evening are used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. It should be noted that these GIF images are meant for browse purposes only and sh...\",\"Rele
ase Date\":\"03/20/2012\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LTOD\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Maps of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrievals over the Arctic Polar region from SeaWinds on ADEOS-II retrievals subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately mid-day (08:00 to 16:00 local) and evening (16:00 to 24:00 local). The eight hour interval at each LTOD reference of mid-day vs. evening corresponds to the natural boundaries of time separation within the data at polar latitudes. Hence, mid-day and evening are used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. This dataset is generated using a Scatterometer Image Reconstruction (SIR) technique dev...\"
,\"Release Date\":\"03/20/2012\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LITE\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Browse Maps (Reduced) of Antarctica\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Antarctic Polar region from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are separated according to polarization. For example, one SIR file for a particular day will contain the gri...\"
,\"Release Date\":\"11/01/2003\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ENHANCED\",\"Long Name\":\"SeaWinds on ADEOS-II Enhanced Resolution Regionally Gridded Sigma-0 (BYU, D. Long)\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains enhanced resolution gridded fields of the normalized radar cross-section (sigma-0) made from the SeaWinds on ADEOS-II L1B dataset using two different forms of the single-variate Scatterometer Image Reconstruction (SIR) algorithm: 1) for \u0027egg\u0027 sigma-0 measurements and 2) for \u0027slice\u0027 sigma-0 measurements, where the SIR with filtering (SIRF) algorithm is used. For \u0027egg\u0027 measurements, the full antenna/processing spatial response is used while a simplified spatial response function in which the spatial response is assumed to be 1 over the footprint and 0 elsewhere is used for \u0027slice\u0027 measurements. The SIR algorithm with \u0027eggs\u0027 makes images of sigma-0 at the measurement inci...\
",\"Release Date\":\"11/02/2011\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_MAPS_FULL\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Browse Maps (Complete) of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrieval statistics over the Arctic Polar region from the QuikSCAT L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The QuikSCAT scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are all contained within a single tar file for a given day. When the tar file is unpacked, the individual SI...\",\
"Release Date\":\"03/19/2001\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LITE\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Browse Maps (Reduced) of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Arctic Polar region from the QuikSCAT L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The QuikSCAT scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are separated according to polarization. For example, one SIR file for a particular day will contain t...\",\"Rel
ease Date\":\"03/19/2001\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_IMAGES\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Browse Images of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Arctic Polar from the QuikSCAT L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU). The QuikSCAT scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The GIF image files are separated according to polarization, and the averaged Sigma-0 measurements are displayed in grayscale with no color bar. Very bright areas ...\",\"Release Date\":\"0
3/19/2001\"},{\"Short Name\":\"QSCAT_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LITE\",\"Long Name\":\"SeaWinds on QuikSCAT Level 3 Sigma-0 Polar-Stereographic Browse Maps (Reduced) of Antarctica\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Antarctic Polar region from the QuikSCAT L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The QuikSCAT scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are separated according to polarization. For example, one SIR file for a particular day will contai...\",\"Release Date\":\"03/1
9/2001\"},{\"Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_GLOBAL_RECTANGULAR_BROWSE_MAPS_LITE\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Global Rectangular Browse Maps (Reduced)\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains global, rectangular-gridded, daily averaged Sigma-0 retrievals from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are separated according to polarization. For example, one SIR file for a particular day will contain the globally gridded average S...\",\"Release Date\":\"11/01/2003\"},{\"Short Name\":\
"SEAWINDS_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_MAPS_FULL\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Browse Maps (Complete) of Antarctica\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrieval statistics over the Antarctic Polar region from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are all contained within a single tar file for a given day. When the tar file is unpacked, the individual...\",\"Release Date\":\"11/01/2003\"},{\"Short Name\":
\"SEAWINDS_BYU_L3_OW_SIGMA0_ARCTIC_POLAR-STEREOGRAPHIC_BROWSE_MAPS_FULL\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Browse Maps (Complete) of Arctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrieval statistics over the Arctic Polar region from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU); the processed files are therefore known as SIR files. The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The SIR files are all contained within a single tar file for a given day. When the tar file is unpacked, the individual SI...\",\"Release Date\":\"11/01/2003\"},{\"Short Name\":
\"SEAWINDS_BYU_L3_OW_SIGMA0_ANTARCTIC_POLAR-STEREOGRAPHIC_BROWSE_MAPS_LTOD\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Local-Time-of-Day Browse Maps of Antarctic Region\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains polar-stereographic-gridded Sigma-0 retrievals over the Antarctic Polar region from SeaWinds on ADEOS-II retrievals subsetted and averaged twice daily at the local time-of-day (LTOD); local times are approximately morning (00:00 to 08:00 local) and evening (16:00 to 24:00 local). The eight hour interval at each LTOD reference of morning vs. evening corresponds to the natural boundaries of time separation within the data at polar latitudes. Hence, morning and evening are used as approximations for the LTOD reference, where the actual LTOD may vary within the respective 8 hour interval. This dataset is generated using a Scatterometer Image Reconstruction (SIR) technique ...\",\"Release Date\":\"03/20/2012\"},{\"
Short Name\":\"SEAWINDS_BYU_L3_OW_SIGMA0_ANTARCTICA_POLAR-STEREOGRAPHIC_BROWSE_IMAGES\",\"Long Name\":\"SeaWinds on ADEOS-II Level 3 Sigma-0 Polar-Stereographic Browse Images of Antarctica\",\"Topic\":\"Sigma Naught, Ice Extent\",\"Abstract\":\"This dataset contains GIF images of polar-stereographic-gridded, daily averaged Sigma-0 retrievals over the Antarctic Polar from the SeaWinds L1B retrievals, which are generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long at Brigham Young University (BYU). The SeaWinds scatterometer scans at two nominal incidence angles, 46 degrees and 54.1 degrees, corresponding to the inner and outer beams respectively. The inner beam is horizontally polarized while the outer beam is vertically polarized. The GIF image files are separated according to polarization, and the averaged Sigma-0 measurements are displayed in grayscale with no color bar. Very bright are...\",\"Release Date\":\"11/02/2003\"},{\"Short Name\
":\"SEASAT_BYU_L3_OW_SIGMA0_ENHANCED\",\"Long Name\":\"SEASAT-A Scatterometer Level 3 Sigma-0 at Enhanced Resolution (BYU)\",\"Topic\":\"Ice Extent, Sigma Naught\",\"Abstract\":\"This SEASAT-A Scatterometer (SASS) Sigma-0 dataset is generated by the Scatterometer Climate Record Pathfinder (SCP) project at Brigham Young University (BYU) and is generated using a Scatterometer Image Reconstruction (SIR) technique developed by Dr. David Long. This dataset is derived from the SASS Geophysical Data Record (GDR). The SIR technique results in an enhanced resolution image reconstruction and gridded on an equal-area grid (for non-polar regions) at 4.45 km pixel resolution stored in SIR files; polar regions are gridded using a polar-stereographic technique. A non-enhanced version is provided at 22.25 km pixel resolution in a format known as GRD files. All files are produced in...\",\"Release Date\":\"04/22/2002\"},{\"Short Name\":\"NSCAT_25KM_MGDR_V2\",\"Long Name\":\"NSCAT High-Resolution MGD
R, Sigma-0 and Ocean Wind Vectors (Dunbar)\",\"Topic\":\"Sigma Naught, Surface Winds, Ice Extent\",\"Abstract\":\"The NASA Scatterometer (NSCAT) Level 2.5 high-resolution merged ocean wind vectors and sigma-0 in 25 km wind vector cell (WVC) swaths contain daily data from ascending and descending passes. Wind vectors are accurate to within 2 m/s (vector speed) and 20 degrees (vector direction). Wind vectors are not considered valid in rain contaminated regions; rain flags and precipitation information are not provided. Data is flagged where measurements are either missing or ambiguous. In the presence of land or sea ice winds values are set to 0, and sigma-0 values are preserved where measurements are available. This is the most up-to-date version, which designates the final phase of calibration, valida...\",\"Release Date\":\"02/19/2006\"},{\"Short Name\":\"RECON_SEA_LEVEL_OST_L4_V1\",\"Long Name\":\"Reconstructed Sea Level Version 1\",\"Topic\":\"Sea Surface Height\",\"Abstract\":\
"The Reconstructed Sea Level dataset contains sea level anomalies derived from satellite altimetry and tide gauges. The satellite altimetric record provides accurate measurements of sea level with near-global coverage, but it has a relatively short time span, since 1993. Tide gauges have measured sea level over the last 200 years, with some records extending back to 1807, but they only provide regional coverage, not global. Combining satellite altimetry with tide gauges, using a technique known as sea level reconstruction, results in a dataset with the record length of the tide gauges and the near-global coverage of satellite altimetry. Cyclostationary empirical orthogonal functions (CSEO...\",\"Release Date\":\"06/10/2013\"},{\"Short Name\":\"TELLUS_GRACE_MASCON_CRI_GRID_RL05_V2\",\"Long Name\":\"JPL GRACE Mascon Ocean, Ice, and Hydrology Equivalent Water Height RL05M.1 CRI Filtered Version 2\",\"Topic\":\"Gravity\",\"Abstract\":\"This dataset represents Version 2 of the JPL GRA
CE Mascon Equivalent Water Height RL05M.1, providing global water storage anomalies relative to a time-mean of monthly mass grids as derived from GRACE. These data are provided in a single data file in netCDF format and is applicable for ocean, ice, and hydrology. This version of the data employs a Coastal Resolution Improvement (CRI) filter that reduces leakage errors across coastlines. The storage anomalies are given in equivalent water thickness units (cm). The solution provided here is derived from solving for monthly gravity field variations in terms of spherical cap mass concentration functions, rather than spherical harmonic coefficien...\",\"Release Date\":\"04/28/2016\"},{\"Short Name\":\"TELLUS_GRACE_MASCON_GRID_RL05_V2\",\"Long Name\":\"JPL GRACE Mascon Ocean, Ice, and Hydrology Equivalent Water Height JPL RL05M.1 Version 2\",\"Topic\":\"Gravity\",\"Abstract\":\"This dataset represents Version 2 of the JPL GRACE Mascon Equivalent Water Height RL05M.1, providing global wa
ter storage anomalies relative to a time-mean of monthly mass grids as derived from GRACE. These data are provided in a single data file in netCDF format and is applicable for ocean, ice, and hydrology. It should be noted that this dataset does not correct for leakage errors across coastlines; it is therefore recommended only for users who want to apply their own algorithm to separate between land and ocean mass very near coastlines. The storage anomalies are given in equivalent water thickness units (cm). The solution provided here is derived from solving for monthly gravity field ...\",\"Release Date\":\"04/28/2016\"},{\"Short Name\":\"MERGED_TP_J1_OSTM_OST_GMSL_ASCII_V3\",\"Long Name\":\"Global Mean Sea Level Trend from Integrated Multi-Mission Ocean Altimeters TOPEX/Poseidon Jason-1 and OSTM/Jason-2 Version 3\",\"Topic\":\"Sea Surface Height\",\"Abstract\":\"This dataset contains the Global Mean Sea Level (GMSL) trend generated from the Integrated Multi-Mission Ocean Altimeter D
ata for Climate Research ( http://podaac.jpl.nasa.gov/dataset/MERGED_TP_J1_OSTM_OST_ALL_V3 ). The GMSL is a 1-dimensional time series of globally averaged Sea Surface Height Anomalies (SSHA) from TOPEX/Poseidon, Jason-1 and OSTM/Jason-2. It starts in September 1992 to present, with a lag of up to 4 months. All biases and cross-calibrations have been applied to the data so SSHA are consistent between satellites. Glacial Isostatic Adjustment (GIA) has not been applied, but it has been smoothed with a 60 day filter. These data are available in ASCII format...\",\"Release Date\":\"10/27/2015\"},{\"Short Name\":\"AVISO_L4_DYN_TOPO_1DEG_1MO\",\"Long Name\":\"AVISO Level 4 Absolute Dynamic Topography for Climate Model Comparison\",\"Topic\":\"Sea Surface Height\",\"Abstract\":\"This dataset contains absolute dynamic topography (similar to sea level but with respect to the geoid) binned and averaged monthly on 1 degree grids. The coverage is from October 1992 to December 2010. These
data were provided by AVISO (French space agency data provider) to support the CMIP5 (Coupled Model Intercomparison Project Phase 5) under the World Climate Research Program (WCRP) and was first made available via the JPL Earth System Grid. The dynamic topography are derived from sea surface height measured by several satellites including Envisat, TOPEX/Poseidon, Jason-1 and OSTM/Jason-2, and referenced to the geoid. Along with this dataset, two additional ancillary data files are i...\",\"Release Date\":\"02/28/2011\"},{\"Short Name\":\"PODAAC_MGDR\",\"Long Name\":\"TOPEX/POSEIDON ALTIMETER MERGED GEOPHYSICAL DATA RECORD GENERATION B\",\"Topic\":\"Sea Surface Height, Significant Wave Height\",\"Abstract\":\"The TOPEX/POSEIDON MGDR (Merged Geophysical Data Record) contains global coverage altimeter data. This data set (MGDR-B) contains generation B data which replaces the generation A data set. The objective of the TOPEX/POSEIDON mission, launched in August 1992 and currently oper
ating, is to determine ocean topography with a sea surface height measurement precision of 3 cm and a sea level measurement accuracy of 13 cm. The data product combines measurements from two altimeters, a NASA dual frequency (Ku and C band) instrument similar to the Geosat altimeter, and a French (CNES) instrument which is a proof-of-concept solid-state altimeter (Ku band). This data set contains mean sea surface, iono...\",\"Release Date\":\"04/20/1998\"},{\"Short Name\":\"OSTM_L2_OGDR_SSHA\",\"Long Name\":\"OSTM/JASON-2 OPERATIONAL GEOPHYSICAL DATA RECORD SEA SURFACE HEIGHT ANOMALIES\",\"Topic\":\"Significant Wave Height, Sea Surface Height\",\"Abstract\":\"The Operational Geophysical Data Records (OGDR) files from the Ocean Surface Topography Mission (OSTM)/Jason-2 contain altimeter data, with a precision orbit of 10 cm accuracy, provided approximately 3-5 hours after data collection. The instruments on OSTM make direct observations of the following quantities: altimeter range, s
ignificant wave height, ocean radar backscatter cross-section (a measure of wind speed), ionospheric electron content (derived by a simple formula), tropospheric water content, mean sea surface, Sea Surface Height Anomalies (SSHA), and position relative to the GPS satellite constellation. This dataset does contains less parameters than those found in the regular OGDR...\",\"Release Date\":\"11/24/2009\"},{\"Short Name\":\"OSTM_L2_GDR_D\",\"Long Name\":\"OSTM/JASON-2 GEOPHYSICAL DATA RECORD VERSION D\",\"Topic\":\"Significant Wave Height, Sea Surface Height\",\"Abstract\":\"The Geophysical Data Records (GDR) files from the Ocean Surface Topography Mission (OSTM)/Jason-2 contain full accuracy altimeter data, with a high precision orbit (accuracy 1.5 cm), provided approximately 35 days after data collection. The instruments on OSTM make direct observations of the following quantities: altimeter range, significant wave height, ocean radar backscatter cross-section (a measure of wind sp
eed), ionospheric electron content (derived by a simple formula), tropospheric water content, mean sea surface, Sea Surface Height Anomalies (SSHA), and position relative to the GPS satellite constellation. These data are distributed by NOAA NODC (National Ocean Data Center)...\",\"Release Date\":\"07/17/2012\"},{\"Short Name\":\"OSTM_L2_SGDR_D\",\"Long Name\":\"OSTM/JASON-2 SENSOR GEOPHYSICAL DATA RECORD VERSION D\",\"Topic\":\"Significant Wave Height, Sea Surface Height\",\"Abstract\":\"FOR EXPERT USE ONLY. The Sensor Geophysical Data Records (SGDR) files from the Ocean Surface Topography Mission (OSTM)/Jason-2 contain full accuracy altimeter data, with a high precision orbit (accuracy 1.5 cm), provided approximately 35 days after data collection. The instruments on OSTM make direct observations of the following quantities: altimeter range, significant wave height, ocean radar backscatter cross-section (a measure of wind speed), ionospheric electron content (derived by a simple
formula), tropospheric water content, mean sea surface, Sea Surface Height Anomalies (SSHA), and position relative to the GPS satellite constellation. Most importantly the SGDR contains waveforms,...\",\"Release Date\":\"07/17/2012\"},{\"Short Name\":\"OSTM_L2_GDR_SSHA_D\",\"Long Name\":\"OSTM/JASON-2 GEOPHYSICAL DATA RECORD SEA SURFACE HEIGHT ANOMALIES VERSION D\",\"Topic\":\"Significant Wave Height, Sea Surface Height\",\"Abstract\":\"The Geophysical Data Records (GDR) Sea Sufrace Height Anomaly (SSHA) files from the Ocean Surface Topography Mission (OSTM)/Jason-2 contain full accuracy altimeter data and SSHA, with a high precision orbit (accuracy 1.5 cm), provided approximately 35 days after data collection. The instruments on OSTM make direct observations of the following quantities: altimeter range, significant wave height, ocean radar backscatter cross-section (a measure of wind speed), ionospheric electron content (derived by a simple formula), tropospheric water content, me
an sea surface, Sea Surface Height Anomalies (SSHA), and position relative to the GPS satellite constellation. These data contain less paramete...\",\"Release Date\":\"07/17/2012\"},{\"Short Name\":\"OSTM_L2_IGDR_SSHA\",\"Long Name\":\"OSTM/JASON-2 INTERIM GEOPHYSICAL DATA RECORD SEA SURFACE HEIGHT ANOMALIES\",\"Topic\":\"Significant Wave Height, Sea Surface Height\",\"Abstract\":\"The Interim Geophysical Data Records (IGDR) files from the Ocean Surface Topography Mission (OSTM)/Jason-2 contain altimeter data, with a precision orbit of 2.5 cm accuracy, provided approximately 1-2 days after data collection. The instruments on OSTM make direct observations of the following quantities: altimeter range, significant wave height, ocean radar backscatter cross-section (a measure of wind speed), ionospheric electron content (derived by a simple formula), tropospheric water content, mean sea surface, Sea Surface Height Anomalies (SSHA), and position relative to the GPS satellite constellati
on. This dataset does contains less parameters than those found in the regular IGDR. T...\",\"Release Date\":\"11/24/2009\"},{\"Short Name\":\"OISST_HR_NRT-GOS-L4-BLK-v2.0\",\"Long Name\":\"Black Sea High Resolution SST L4 Analysis 0.0625 deg Resolution\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"CNR MED Sea Surface Temperature provides daily gap-free maps (L4) at 0.0625 deg. x 0.0625 deg. horizontal resolution over the Black Sea. The data are obtained from infra-red measurements collected by satellite radiometers and statistical interpolation. It is the CMEMS sea surface temperature nominal operational product for the Black sea...\",\"Release Date\":\"05/30/2016\"},{\"Short Name\":\"OISST_HR_NRT-GOS-L4-MED-v2.0\",\"Long Name\":\"Mediterranean Sea High Resolution SST L4 Analysis 1/16deg Resolution\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"CNR MED Sea Surface Temperature provides daily gap-free maps (L4) at 0.0625deg. x 0.0625deg. horizontal resolution over
the Mediterranean Sea. The data are obtained from infra-red measurements collected by satellite radiometers and statistical interpolation. It is the CMEMS sea surface temperature nominal operational product for the Mediterranean sea...\",\"Release Date\":\"05/30/2016\"},{\"Short Name\":\"MERGED_TP_J1_OSTM_OST_ALL_V3\",\"Long Name\":\"Integrated Multi-Mission Ocean Altimeter Data for Climate Research complete time series Version 3\",\"Topic\":\"Sea Surface Height\",\"Abstract\":\"This dataset contains along track geo-referenced Sea Surface Height Anomalies (SSHA) from TOPEX/Poseidon, Jason-1 and OSTM/Jason-2 (depending on time period) merged onto a single mean reference orbit. All biases and cross-calibrations have been applied to the data so SSHA are consistent between satellites to form a single climate data record. Altimeter data from the multi-mission Geophysical Data Records (GDRs) are interpolated to a common reference orbit facilitating direct time series analysis of the ge
o-referenced SSH. The data are in netCDF format . The data start at September 1992. The newest data are appended to the file quarterly...\",\"Release Date\":\"10/27/2015\"},{\"Short Name\":\"DMI-L4UHfnd-NSEABALTIC-DMI_OI\",\"Long Name\":\"GHRSST Level 4 DMI_OI North Sea and Baltic Sea Regional Foundation Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis by the Danish Meteorological Institute (DMI) using an optimal interpolation (OI) approach on a regional 0.03 degree grid. The analysis is based upon nighttime GHRSST L2P skin and subskin SST observations from several satellites over the North and Baltic Seas. The sensors include the Advanced Very High Resolution Radiometer (AVHRR), the Advanced Along Track Scanning Radiometer (AATSR), the Spinning Enhanced Visible and Infrared Imager (SEVIRI), the Advan
ced Microwave Scanning Radiometer-EOS (AMSRE) and the Moderate Resolution Imaging Spectroradiometer...\",\"Release Date\":\"09/07/2007\"},{\"Short Name\":\"MERGED_TP_J1_OSTM_OST_CYCLES_V3\",\"Long Name\":\"Integrated Multi-Mission Ocean Altimeter Data for Climate Research Version 3\",\"Topic\":\"Sea Surface Height\",\"Abstract\":\"This dataset contains along track geo-referenced Sea Surface Height Anomalies (SSHA) from TOPEX/Poseidon, Jason-1 and OSTM/Jason-2 (depending on time period) merged into a single mean reference orbit. All biases and cross-calibrations have been applied to the data so SSHA are consistent between satellites to form a single climate data record. Altimeter data from the multi-mission Geophysical Data Records (GDRs) are interpolated to a common reference orbit facilitating direct time series analysis of the geo-referenced SSH. The data are in netCDF format. Each file consists of one cycle of data, which is approximately 10 days long. Cycle 001 coincides wit
h cycle 001 of TOPEX/Poseidon (Sept...\",\"Release Date\":\"10/27/2015\"},{\"Short Name\":\"OISST_UHR_NRT-GOS-L4-BLK-v2.0\",\"Long Name\":\"Black Sea Ultra High Resolution SST L4 Analysis 0.01 deg Resolution\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"CNR MED Sea Surface Temperature provides daily gap-free maps (L4) at 0.01 deg. x 0.01 deg. horizontal resolution over the Black Sea. The data are obtained from infra-red measurements collected by satellite radiometers and statistical interpolation. It is the CMEMS sea surface temperature nominal operational product for the Black sea...\",\"Release Date\":\"06/02/2016\"},{\"Short Name\":\"EUR-L4HRfnd-GLOB-ODYSSEA\",\"Long Name\":\"GHRSST Level 4 ODYSSEA Global Foundation Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at Ifremer/CERSAT (France) u
sing optimal interpolation (OI) on a global 0.1 degree grid. It provides a daily cloud-free field of foundation sea surface temperature at approximately 10km resolution (0.1 degree) over the full globe. It is generated by merging microwave and infrared satellite sea surface temperature observations including those from the Advanced Very High Resolution Radiometer (AVHRR), the Advanced Along Track Scanning Radiometer (AATSR), the Spinning Enhanced Visible and Infrared Imager (SEVIRI), the Advanced Microwave Scanning Radiome...\",\"Release Date\":\"09/18/2007\"},{\"Short Name\":\"EUR-L2P-NAR18_SST\",\"Long Name\":\"GHRSST Level 2P North Atlantic Regional Bulk Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-18 satellite\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for HIgh Resolution Sea Surface Temperature (GHRSST) dataset for the North Atlantic Region (NAR) from the Advanced Very High Resolution Radiometer (AVHRR) on th
e NOAA-18 platform (launched on 20 May 2005). This particular dataset is produced by the European Organization for the Exploitation of Meteorological Satellites (EUMETSAT), Ocean and Sea Ice Satellite Application Facility (OSI SAF) in France.\\r\\n\\r\\nThe AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 197...\",\"Release Date\":\"12/01/2004\"},{\"Short Name\":\"EUR-L2P-NAR17_SST\",\"Long Name\":\"GHRSST Level 2P North Atlantic Regional Bulk Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-17 satellite\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) dataset for the North Atlantic Region (NAR) from the Advanced Very High Resolution Radiometer (A
VHRR) on the NOAA-17 platform (launched on \\r\\n24 Jun 2002). This particular dataset is produced by the European Organization for the Exploitation of Meteorological Satellites (EUMETSAT) Ocean and Sea Ice Satellite Application Facility (OSI SAF) in France.\\r\\n\\r\\nThe AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 19...\",\"Release Date\":\"12/01/2004\"},{\"Short Name\":\"EUR-L3P-NAR_AVHRR_NOAA_19\",\"Long Name\":\"GHRSST Level 3P North Atlantic Regional Subskin Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on NOAA-19\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for HIgh Resolution Sea Surface Temperature (GHRSST) dataset for the North Atlantic Region (NAR) from the Advanced Very High Resolution Rad
iometer (AVHRR) on the NOAA-19 platform (launched 6 Feb 2009). This particular dataset is produced by the European Organization for the Exploitation of Meteorological Satellites (EUMETSAT), Ocean and Sea Ice Satellite Application Facility (OSI SAF) in France. The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 1978. AVHRR ...\",\"Release Date\":\"08/07/2008\"},{\"Short Name\":\"ABOM-L4LRfnd-GLOB-GAMSSA_28km\",\"Long Name\":\"GHRSST Level 4 GAMSSA Global Foundation Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at the Australian Bureau of Meteorology using optimal interpolation (OI
) on a global 0.25 degree grid. This BLUELink Global Australian Multi-Sensor SST Analysis (GAMSSA) v1.0 system blends satellite SST observations from the Advanced Very High Resolution Radiometer (AVHRR), the Advanced Along Track Scanning Radiometer (AATSR), and, the Advanced Microwave Scanning Radiometer-EOS (AMSRE), and in situ data from ships, and drifting and moored buoy from the Global Telecommunications System (GTS). In order to produce a foundation SST estimate, the AATSR skin...\",\"Release Date\":\"07/27/2008\"},{\"Short Name\":\"JPL-L4UHfnd-GLOB-MUR\",\"Long Name\":\"GHRSST Level 4 MUR Global Foundation Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced as a retrospective dataset (four day latency) at the JPL Physical Oceanography DAAC using wavelets as basis functions in an optimal interpolation approach on a global 0.011 degre
e grid. The version 4 Multiscale Ultrahigh Resolution (MUR) L4 analysis is based upon nighttime GHRSST L2P skin and subskin SST observations from several instruments including the NASA Advanced Microwave Scanning Radiometer-EOS (AMSRE), the Moderate Resolution Imaging Spectroradiometer (MODIS) on the NASA Aqua and Terra platforms, the US Navy microwave WindSat radiometer and in situ SST observations from th...\",\"Release Date\":\"05/26/2010\"},{\"Short Name\":\"NCDC-L4LRblend-GLOB-AVHRR_OI\",\"Long Name\":\"GHRSST Level 4 AVHRR_OI Global Blended Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) global Level 4 sea surface temperature analysis produced daily on a 0.25 degree grid at the NOAA National Climatic Data Center. This product uses optimal interpolation (OI) using data from the 4 km Advanced Very High Resolution Radiometer (AVHRR) Pathfinder Version 5 time series (when available
, otherwise operational NOAA AVHRR data are used) and in situ ship and buoy observations. A second similar product is available that also includes Advanced Microwave Scanning Radiometer-EOS (AMSR-E) data from June 2002 onward. The OI analysis is a daily average SST that is bias adjusted using a spatially smoothed 7-day in situ SST average an...\",\"Release Date\":\"04/07/2007\"},{\"Short Name\":\"JPL-L4UHfnd-NCAMERICA-MUR\",\"Long Name\":\"GHRSST Level 4 MUR North America Regional Foundation Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced as a retrospective dataset at the JPL Physical Oceanography DAAC using wavelets as basis functions in an optimal interpolation approach on a regional 0.011 degree grid over the oceans off North and Central America (62N- 20S, 165W - 30W). The Multiscale Ultrahigh Resolution (MUR) L4 analysis is based
upon nighttime GHRSST L2P skin and subskin SST observations from several instruments such as: the NASA Advanced Microwave Scanning Radiometer-EOS (AMSRE), and the Moderate Resolution Imaging Spectroradiometer (MODIS) on the NASA Aqua and Terra platforms. The ice concentration data are f...\",\"Release Date\":\"05/27/2010\"},{\"Short Name\":\"JPL-L4UHblend-NCAMERICA-RTO_SST_Tn\",\"Long Name\":\"GHRSST Level 4 RTO Terra MODIS-AMSRE Night North America Regional Blended Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at the JPL Physical Oceanography DAAC using weighted averages on a regional 0.011 degree grid over the oceans off North and Central America (62N- 20S, 165W - 30W). This Research to Operations (RTO) analysis is based upon a composite of either nighttime or daytime GHRSST L2P skin SST from the Mod
erate Resolution Imaging Spectroradiometer (MODIS) on the NASA Aqua and Terra platforms, and subskin SST observations from the Advanced Microwave Scanning Radiometer-EOS (AMSRE). Four unique products (composites) are created: MODIS Terra/AMSRE day and night, an...\",\"Release Date\":\"09/23/2010\"},{\"Short Name\":\"Geo_Polar_Blended-OSPO-L4-GLOB-v1.0\",\"Long Name\":\"GHRSST Level 4 OSPO Global Foundation Sea Surface Temperature Analysis (GDS version 2)\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at the Office of Satellite and Product Operations (OSPO) using optimal interpolation (OI) on a global 0.054 degree grid. \\r\\nThe Geo-Polar Blended Sea Surface Temperature (SST) Analysis combines multi-satellite retrievals of sea surface temperature into a single analysis of SST. This analysis uses both daytime and nighttime data from sens
ors that include the Advanced Very High Resolution Radiometer (AVHRR), the Visible Infrared Imager Radiometer Suite (VIIRS), the Geostationary Operational Environmental Satellite (GOES) imager, the Japanese Advanced Mete...\",\"Release Date\":\"03/10/2015\"},{\"Short Name\":\"CMC0.1deg-CMC-L4-GLOB-v3.0\",\"Long Name\":\"GHRSST Level 4 CMC0.1deg Global Foundation Sea Surface Temperature Analysis (GDS version 2)\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature (SST) analysis produced daily on an operational basis at the Canadian Meteorological Center. This dataset merges infrared satellite SST at varying points in the time series from the Advanced Very High Resolution Radiometer (AVHRR) from NOAA-18,19, the European Meteorological Operational-A (METOP-A) and Operational-B (METOP-B), and microwave data from the Advanced Microwave Scanning Radiometer 2 (AMSR2) onboard the GCOM-W satellite
in conjunction with in situ observations of SST from drifting buoys and ships from the ICOADS program. It uses the previous days analysis as the background field for the s...\",\"Release Date\":\"07/28/2016\"},{\"Short Name\":\"OISST_UHR_NRT-GOS-L4-MED-v2.0\",\"Long Name\":\"Mediterranean Sea Ultra High Resolution SST L4 Analysis 0.01 deg Resolution\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"CNR MED Sea Surface Temperature provides daily gap-free maps (L4) at 0.01 deg. x 0.01deg. horizontal resolution over the Mediterranean \\r\\nSea. The data are obtained from infra-red measurements collected by satellite radiometers and statistical interpolation. It is the CMEMS sea surface temperature nominal operational product for the Mediterranean sea...\",\"Release Date\":\"05/30/2016\"},{\"Short Name\":\"NCDC-L4LRblend-GLOB-AVHRR_AMSR_OI\",\"Long Name\":\"GHRSST Level 4 AVHRR_AMSR_OI Global Blended Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstra
ct\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) global Level 4 sea surface temperature analysis produced daily on a 0.25 degree grid at the NOAA National Climatic Data Center. This product uses optimal interpolation (OI) using data from the Advanced Very High Resolution Radiometer (AVHRR) Pathfinder Version 5 time series (when available, otherwise operational NOAA AVHRR data are used), the Advanced Microwave Scanning Radiometer-EOS (AMSR-E), and in situ ship and buoy observations. A second similar product is available back to 1981 that includes only in situ and AVHRR Pathfinder data in its analysis. The OI analysis is a daily average SST that is bias adjusted using a spatiall...\",\"Release Date\":\"04/06/2007\"},{\"Short Name\":\"EUR-L3P-NAR_AVHRR_METOP_A\",\"Long Name\":\"GHRSST Level 3P North Atlantic Regional Subskin Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the MetOp-A satellite\",\"Topic\":\"Sea Surface Temperatu
re\",\"Abstract\":\"A Group for HIgh Resolution Sea Surface Temperature (GHRSST) dataset for the North Atlantic Region (NAR) from the Advanced Very High Resolution Radiometer (AVHRR) on the MetOp-A platform (launched on 19 Oct 2006). This particular dataset is produced by the European Organization for the Exploitation of Meteorological Satellites (EUMETSAT), Ocean and Sea Ice Satellite Application Facility (OSI SAF) in France. The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 1978. AV...\",\"Release Date\":\"08/07/2008\"},{\"Short Name\":\"AVHRR_SST_METOP_A_NAR-OSISAF-L3C-v1.0\",\"Long Name\":\"GHRSST Level 3C North Atlantic Regional Subskin Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on MetOp-A (GDS2 version)\",\"Top
ic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) dataset for the North Atlantic Region (NAR) derived from the Advanced Very High Resolution Radiometer (AVHRR) on the European Meteorological Operational-A (MetOp-A) platform (launched 19 Oct 2006). This particular dataset is produced by the European Organization for the Exploitation of Meteorological Satellites (EUMETSAT), Ocean and Sea Ice Satellite Application Facility (OSI SAF) in France. The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observati...\",\"Release Date\":\"02/01/2015\"},{\"Short Name\":\"EUR-L2P-AVHRR16_G\",\"Long Name\":\"GHRSST Level 2P Global Bulk Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-16 satellite\",\"Topic\":\"Sea Surf
ace Temperature\",\"Abstract\":\"A global Level 2P Group for High Resolution Sea Surface Temperature (GHRSST) dataset based on multi-channel sea surface temperature (SST) retrievals from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-16 platform (launched on 21 Sep 2000). The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 1978. AVHRR instruments measure the radiance of the Earth in 5 (or 6) relatively wide spectral bands. The first two are centered around the red (0.6 micrometer) ...\",\"Release Date\":\"12/09/2004\"},{\"Short Name\":\"EUR-L2P-AVHRR17_L\",\"Long Name\":\"GHRSST Level 2P Atlantic Regional Bulk Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-17 satellite\",\"Topic\":\"Sea Surface
Temperature\",\"Abstract\":\"A regional Level 2P Group for High Resolution Sea Surface Temperature (GHRSST) dataset for the Atlantic Ocean and nearby regions based on multi-channel sea surface temperature (SST) retrievals from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-17 platform (launched on 24 June 2002). The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 1978. AVHRR instruments measure the radiance of the Earth in 5 (or 6) relatively wide spectral bands. The first two ...\",\"Release Date\":\"12/07/2004\"},{\"Short Name\":\"EUR-L2P-AVHRR16_L\",\"Long Name\":\"GHRSST Level 2P Atlantic Regional Bulk Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-16 satellite\",\"Topic\":\"Sea Surface Temp
erature\",\"Abstract\":\"A regional Level 2P Group for High Resolution Sea Surface Temperature (GHRSST) dataset for the Atlantic Ocean and nearby regions based on multi-channel sea surface temperature (SST) retrievals from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-16 platform (launched on 21 Sep 2000). The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 1978. AVHRR instruments measure the radiance of the Earth in 5 (or 6) relatively wide spectral bands. The first two...\",\"Release Date\":\"12/09/2004\"},{\"Short Name\":\"NAVO-L2P-AVHRRMTA_G\",\"Long Name\":\"GHRSST Level 2P Global Bulk Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the MetOp-A satellite produced by NAVO\",\"Topic\":\"Sea Surface
Temperature\",\"Abstract\":\"A global Group for High Resolution Sea Surface Temperature (GHRSST) Level 2P dataset based on multi-channel sea surface temperature (SST) retrievals generated in real-time from the Advanced Very High Resolution Radiometer (AVHRR) on the European Meteorological Operational-A (MetOp-A; launched 19 Oct 2006) ) satellite produced and used operationally in oceanographic analyses and forecasts by the US Naval Oceanographic Office (NAVO). The MetOp satellite program is a European undertaking providing weather data services for monitoring climate and improving weather forecasts. It was jointly established by the European Space Agency (ESA) and the European Organisation for the Exploitation of Met...\",\"Release Date\":\"09/25/2007\"},{\"Short Name\":\"AVHRRMTB_G-NAVO-L2P-v1.0\",\"Long Name\":\"GHRSST Level 2P Global 1m Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the MetOp-B satellite produced by NAVO\",\"Topic\":\"Sea S
urface Temperature\",\"Abstract\":\"A global Group for High Resolution Sea Surface Temperature (GHRSST) Level 2P dataset based on multi-channel sea surface temperature (SST) retrievals generated in real-time from the Advanced Very High Resolution Radiometer (AVHRR) on the European Meteorological Operational-A (MetOp-A; launched 19 Oct 2006) ) satellite produced and used operationally in oceanographic analyses and forecasts by the US Naval Oceanographic Office (NAVO). The MetOp satellite program is a European undertaking providing weather data services for monitoring climate and improving weather forecasts. It was jointly established by the European Space Agency (ESA) and the European Organisation for the Exploitation of Met...\",\"Release Date\":\"10/26/2014\"},{\"Short Name\":\"NAVO-L2P-AVHRR17_L\",\"Long Name\":\"GHRSST Regional Bulk Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-17 satellite produced by NAVO\",\"Topic\":\"Sea Surfa
ce Temperature\",\"Abstract\":\"A regional Group for High Resolution Sea Surface Temperature (GHRSST) Level 2P dataset based on multi-channel sea surface temperature (SST) retrievals generated in real-time from the Advanced Very High Resolution Radiometer (AVHRR) on the NOAA-17 platform (launched 24 June 2002) produced and used operationally in oceanographic analyses and forecasts by the US Naval Oceanographic Office (NAVO). The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 1978. AVHRR instrumen...\",\"Release Date\":\"12/21/2005\"},{\"Short Name\":\"OSTM_L2_IGDR\",\"Long Name\":\"OSTM/JASON-2 INTERIM GEOPHYSICAL DATA RECORD\",\"Topic\":\"Significant Wave Height, Sea Surface Height\",\"Abstract\":\"The Interim Geophysical Data Records (IGDR) files from the
Ocean Surface Topography Mission (OSTM)/Jason-2 contain altimeter data, with a precision orbit of 2.5 cm accuracy, provided approximately 1-2 days after data collection. The instruments on OSTM make direct observations of the following quantities: altimeter range, significant wave height, ocean radar backscatter cross-section (a measure of wind speed), ionospheric electron content (derived by a simple formula), tropospheric water content, mean sea surface, Sea Surface Height Anomalies (SSHA), and position relative to the GPS satellite constellation. These data are distributed by NOAA NODC (National Ocean Data Center)...\",\"Release Date\":\"11/24/2009\"},{\"Short Name\":\"OSTM_L2_OGDR\",\"Long Name\":\"OSTM/JASON-2 OPERATIONAL GEOPHYSICAL DATA RECORD\",\"Topic\":\"Significant Wave Height, Sea Surface Height\",\"Abstract\":\"The Operational Geophysical Data Records (OGDR) files from the Ocean Surface Topography Mission (OSTM)/Jason-2 contain altimeter data, with a precision orbit o
f 10 cm accuracy, provided approximately 3-5 hours after data collection. The instruments on OSTM make direct observations of the following quantities: altimeter range, significant wave height, ocean radar backscatter cross-section (a measure of wind speed), ionospheric electron content (derived by a simple formula), tropospheric water content, mean sea surface, Sea Surface Height Anomalies (SSHA), and position relative to the GPS satellite constellation. These data are distributed by NOAA NODC (National Ocean Data Center)...\",\"Release Date\":\"11/24/2009\"},{\"Short Name\":\"EUR-L3P-GLOB_AVHRR_METOP_A\",\"Long Name\":\"GHRSST Level 3P Global Subskin Sea Surface Temperature from the Advanced Very High Resolution Radiometer (AVHRR) on the MetOp-A satellite\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A global Level 3 Group for HIgh Resolution Sea Surface Temperature (GHRSST) dataset from the Advanced Very High Resolution Radiometer (AVHRR) on the MetOp-A platform (launc
hed on 19 Oct 2006). This particular dataset is produced by the European Organization for the Exploitation of Meteorological Satellites (EUMETSAT), Ocean and Sea Ice Satellite Application Facility (OSI SAF) in France. The AVHRR is a space-borne scanning sensor on the National Oceanic and Atmospheric Administration (NOAA) family of Polar Orbiting Environmental Satellites (POES) having a operational legacy that traces back to the Television Infrared Observation Satellite-N (TIROS-N) launched in 1978. AVHRR instruments meas...\",\"Release Date\":\"08/08/2008\"},{\"Short Name\":\"JPL-L4UHblend-NCAMERICA-RTO_SST_Td\",\"Long Name\":\"GHRSST Level 4 RTO Terra MODIS-AMSRE Day North America Regional Blended Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at the JPL Physical Oceanography DAAC using weighted average
s on a regional 0.011 degree grid over the oceans off North and Central America (62N- 20S, 165W - 30W). This Research to Operations (RTO) analysis is based upon a composite of either nighttime or daytime GHRSST L2P skin SST from the Moderate Resolution Imaging Spectroradiometer (MODIS) on the NASA Aqua and Terra platforms, and subskin SST observations from the Advanced Microwave Scanning Radiometer-EOS (AMSRE). Four unique products (composites) are created: MODIS Terra/AMSRE day and night, and...\",\"Release Date\":\"09/23/2010\"},{\"Short Name\":\"NAVO-L4HR1m-GLOB-K10_SST\",\"Long Name\":\"GHRSST Level 4 K10_SST Global 1 meter Sea Surface Temperature Analysis\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at the Naval Oceanographic Office (NAVOCEANO) on a global 0.1 degree grid. The K10 L4 sea surface temperature analysis uses SST obse
rvations from the Advanced Very High Resolution Radiometer (AVHRR), the Advanced Microwave Scanning Radiometer for EOS (AMSR-E), and the Geostationary Operational Environmental Satellite (GOES) Imager. The age, reliability, and resolution of the data are used in the weighted average with the analysis tuned to represent SST at 1 meter depth. AVHRR Pathfinder 9km climatology is used when no new satellite SST retrievals are a...\",\"Release Date\":\"03/10/2008\"},{\"Short Name\":\"CMC0.2deg-CMC-L4-GLOB-v2.0\",\"Long Name\":\"GHRSST Level 4 CMC0.2deg Global Foundation Sea Surface Temperature Analysis (GDS version 2)\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature (SST) analysis produced daily on an operational basis at the Canadian Meteorological Center. This dataset merges infrared satellite SST at varying points in the time series from the (A)TSR series of radiometers from ERS-1, ERS-2
and Envisat, AVHRR from NOAA-16,17,18,19 and METOP-A, and microwave data from TMI, AMSR-E and Windsat in conjunction with in situ observations of SST from drifting buoys and ships from the ICOADS program. It uses the previous days analysis as the background field for the statistical interpolation used to assimilate the satellite and in situ observations. This dataset adheres...\",\"Release Date\":\"11/18/2012\"},{\"Short Name\":\"ALT_TIDE_GAUGE_L4_OST_SLA_US_WEST_COAST\",\"Long Name\":\"Gridded Altimeter Fields with Enhanced Coastal Coverage\",\"Topic\":\"Sea Surface Height, Ocean Currents\",\"Abstract\":\"The Gridded Altimeter Fields with Enhanced Coastal Coverage data product contains Sea Surface Height Anomalies (SSHA or SLA) and zonal and meridional geostrophic velocities for the US west coast encompassing 35.25 deg-48.5 deg N latitude and 227.75 deg-248.5 deg E longitude. This annually updated data product extends from October 14, 1992 through November 4, 2009. SSHA and curre
nt velocities are derived from the AVISO quarter degree DT UPD MSLA version 3.0 grids, 0.75 deg and greater away from the coast. Values within 0.75 deg of the coast are derived from tide gauge observations and interpolated out to the altimeter filled region. Details on how these data are derived can be found in: ...\",\"Release Date\":\"09/25/2010\"},{\"Short Name\":\"VIIRS_NPP-NAVO-L2P-v1.0\",\"Long Name\":\"GHRSST Level 2P Global 1 meter Sea Surface Temperature from the Visible Infrared Imaging Radiometer Suite (VIIRS) on the Suomi NPP satellite (GDS version 2)\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A global Group for High Resolution Sea Surface Temperature (GHRSST) Level 2P dataset based on retrievals from the Visible Infrared Imaging Radiometer Suite (VIIRS). This sensor resides on the Suomi National Polar-orbiting Operational Environmental Satellite System (NPOESS) Preparatory Project (NPP) satellite launched on 28 October 2011.\\r\\nThe VIIRS instrument is a
a 22-band, multi-spectral scanning radiometer with a 3040-km swath width that builds on the heritage of the MODIS , AVHRR and SeaWIFS sensors for sea surface temperature (SST) and ocean color. For the infrared bands for SST the effective pixel size is 740 meters at nadir and the pixel size variation across the swath is constrained ...\",\"Release Date\":\"04/10/2012\"},{\"Short Name\":\"OSDPD-L2P-MSG02\",\"Long Name\":\"GHRSST Level 2P Atlantic Regional Skin Sea Surface Temperature from the Spinning Enhanced Visible and InfraRed Imager (SEVIRI) on the Meteosat Second Generation (MSG-2) satellite\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"The Meteosat Second Generation (MSG) satellites are spin stabilized geostationary satellites operated by the European Organization for the Exploitation of Meteorological Satellites (EUMETSAT) to provide accurate weather monitoring data through its primary instrument the Spinning Enhanced Visible and InfraRed Imager (SEVIRI), which has t
he capacity to observe the Earth in 12 spectral channels. Eight of these channels are in the thermal infrared, providing among other information, observations of the temperatures of clouds, land and sea surfaces at approximately 5 km resolution with a 15 minute duty cycle. This Group for High Resolution Sea Surface Temperature (GHRSST) dataset produced by th...\",\"Release Date\":\"07/27/2009\"},{\"Short Name\":\"Geo_Polar_Blended_Night-OSPO-L4-GLOB-v1.0\",\"Long Name\":\"GHRSST Level 4 OSPO Global Nighttime Foundation Sea Surface Temperature Analysis (GDS version 2)\",\"Topic\":\"Sea Surface Temperature\",\"Abstract\":\"A Group for High Resolution Sea Surface Temperature (GHRSST) Level 4 sea surface temperature analysis produced daily on an operational basis at the Office of Satellite and Product Operations (OSPO) using optimal interpolation (OI) on a global 0.054 degree grid. The Geo-Polar Blended Sea Surface Temperature (SST) Analysis combines multi-satellite retrievals of sea su
rface temperature into a single analysis of SST. This analysis includes only nighttime data from sensors that include the Advanced Very High Resolution Radiometer (AVHRR), the Visible Infrared Imag
<TRUNCATED>
[02/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/jquery-1.10.2.min.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/jquery-1.10.2.min.js b/web/META-INF/resources/js/libs/jquery-1.10.2.min.js
new file mode 100755
index 0000000..da41706
--- /dev/null
+++ b/web/META-INF/resources/js/libs/jquery-1.10.2.min.js
@@ -0,0 +1,6 @@
+/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery-1.10.2.min.map
+*/
+(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;
if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){retur
n x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.ran
dom()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);fo
r(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t)
{e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length
=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply
(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<
<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?
:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.ge
tElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t
.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r
.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e
):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.
call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);wh
ile(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at
.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0]
.slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(
m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(
e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"
option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);retu
rn e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!
0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e
.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]
||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached
=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n
,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:functi
on(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},
when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.
getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.c
hecked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.d
isplay="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offs
etWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t
+}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,
embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeDat
a(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:functi
on(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.le
ngth>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while
(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+=""
:x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:funct
ion(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!=
=t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r
)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","c
ontentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g
=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.
test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i
)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.
isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t
=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.tar
get?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n
){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i
))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e)
{this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof
e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))
/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.len
gth>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},sibl
ings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!=
=n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","
</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domMani
p(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhites
pace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++
)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.
data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagNa
me!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.
nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=
x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle);
+u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,
$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style
&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||
x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.widt
h=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i
||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return I
t.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidde
n(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURI
Component(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return
this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x
.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text
/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),
this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn+
+)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.if
Modified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[
0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPr
efilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(
o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.usernam
e,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){v
ar n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.dur
ation,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[
r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&
(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(th
is),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};ret
urn a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});funct
<TRUNCATED>
[17/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/MetadataOpt.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/MetadataOpt.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/MetadataOpt.java
new file mode 100644
index 0000000..69dc878
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/MetadataOpt.java
@@ -0,0 +1,150 @@
+package gov.nasa.jpl.mudrod.recommendation.structure;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.utils.LabeledRowMatrix;
+import gov.nasa.jpl.mudrod.utils.MatrixUtil;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.function.PairFunction;
+import org.apache.spark.mllib.linalg.distributed.RowMatrix;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import scala.Tuple2;
+
+import java.io.Serializable;
+import java.util.*;
+
+public class MetadataOpt implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private String indexName;
+ private String metadataType;
+ private List<String> variables;
+
+ public static final String SPLIT_BLANK = " ";
+ public static final String SPLIT_COMMA = ",";
+
+ public MetadataOpt(Properties props) {
+ indexName = props.getProperty(MudrodConstants.ES_INDEX_NAME);
+ metadataType = props.getProperty("recom_metadataType");
+
+ variables = new ArrayList<>();
+ variables.add("DatasetParameter-Term");
+ variables.add("DatasetParameter-Variable");
+ variables.add("Dataset-Description");
+ variables.add("Dataset-LongName");
+ }
+
+ public JavaPairRDD<String, String> loadAll(ESDriver es, SparkDriver spark) throws Exception {
+ List<Tuple2<String, String>> datasetsTokens = this.loadMetadataFromES(es, variables);
+ return this.parallizeData(spark, datasetsTokens);
+ }
+
+ public JavaPairRDD<String, String> loadAll(ESDriver es, SparkDriver spark, List<String> variables) throws Exception {
+ List<Tuple2<String, String>> datasetsTokens = this.loadMetadataFromES(es, variables);
+ return this.parallizeData(spark, datasetsTokens);
+ }
+
+ private JavaPairRDD<String, String> parallizeData(SparkDriver spark, List<Tuple2<String, String>> datasetContent) {
+
+ JavaRDD<Tuple2<String, String>> datasetContentRDD = spark.sc.parallelize(datasetContent);
+
+ return datasetContentRDD.mapToPair(new PairFunction<Tuple2<String, String>, String, String>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, String> call(Tuple2<String, String> term) throws Exception {
+ return term;
+ }
+ });
+
+ }
+
+ public JavaPairRDD<String, List<String>> tokenizeData(JavaPairRDD<String, String> datasetsContentRDD, String splitter) throws Exception {
+
+ return datasetsContentRDD.mapToPair(new PairFunction<Tuple2<String, String>, String, List<String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, List<String>> call(Tuple2<String, String> arg) throws Exception {
+ String content = arg._2;
+ List<String> tokens = getTokens(content, splitter);
+
+ return new Tuple2<>(arg._1, tokens);
+ }
+ });
+
+ }
+
+ public List<String> getTokens(String str, String splitter) throws Exception {
+ String[] tokens = null;
+ if (splitter.equals(SPLIT_BLANK)) {
+ tokens = str.split(" ");
+ } else if (splitter.equals(SPLIT_COMMA)) {
+ tokens = str.split(",");
+ }
+ return java.util.Arrays.asList(tokens);
+ }
+
+ public List<Tuple2<String, String>> loadMetadataFromES(ESDriver es, List<String> variables) throws Exception {
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(indexName).setTypes(metadataType).setQuery(QueryBuilders.matchAllQuery()).setScroll(new TimeValue(60000)).setSize(100).execute()
+ .actionGet();
+
+ List<Tuple2<String, String>> datasetsTokens = new ArrayList<>();
+ while (true) {
+
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String shortName = (String) result.get("Dataset-ShortName");
+
+ String filedStr = "";
+ int size = variables.size();
+ for (int i = 0; i < size; i++) {
+ String filed = variables.get(i);
+ Object filedValue = result.get(filed);
+
+ if (filedValue != null) {
+ filedStr = es.customAnalyzing(indexName, filedValue.toString());
+ }
+ }
+
+ datasetsTokens.add(new Tuple2<String, String>(shortName, filedStr));
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ return datasetsTokens;
+ }
+
+ public LabeledRowMatrix tFIDFTokens(JavaPairRDD<String, List<String>> datasetTokensRDD, SparkDriver spark) {
+
+ LabeledRowMatrix labelMatrix = MatrixUtil.createDocWordMatrix(datasetTokensRDD, spark.sc);
+
+ RowMatrix docwordMatrix = labelMatrix.rowMatrix;
+
+ RowMatrix docwordTFIDFMatrix = MatrixUtil.createTFIDFMatrix(docwordMatrix);
+
+ labelMatrix.rowMatrix = docwordTFIDFMatrix;
+
+ return labelMatrix;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/RecomData.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/RecomData.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/RecomData.java
new file mode 100644
index 0000000..9025156
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/RecomData.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.recommendation.structure;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.sort.SortOrder;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.util.*;
+
+/**
+ * This class is used to test recommendation result similarity and session-level
+ * similarity
+ */
+public class RecomData extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ protected transient List<LinkedTerm> termList = new ArrayList<>();
+ DecimalFormat df = new DecimalFormat("#.00");
+ protected static final String INDEX_NAME = "indexName";
+ private static final String WEIGHT = "weight";
+
+ class LinkedTerm {
+ public String term = null;
+ public double weight = 0;
+ public String model = null;
+
+ public LinkedTerm(String str, double w, String m) {
+ term = str;
+ weight = w;
+ model = m;
+ }
+ }
+
+ public RecomData(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ public JsonObject getRecomDataInJson(String input, int num) {
+ String type = props.getProperty("metadataTermTFIDFSimType");
+ Map<String, Double> sortedOBSimMap = getRelatedData(type, input, num + 5);
+ JsonElement linkedJson = mapToJson(sortedOBSimMap, num);
+
+ // type = props.getProperty("metadataTermTFIDFSimType");
+ type = props.getProperty("metadataCodeSimType");
+
+ Map<String, Double> sortedMBSimMap = getRelatedData(type, input, num + 5);
+ JsonElement relatedJson = mapToJson(sortedMBSimMap, num);
+
+ JsonObject json = new JsonObject();
+
+ json.add("TFIDFSim", linkedJson);
+ json.add("TopicSim", relatedJson);
+
+ return json;
+ }
+
+ protected JsonElement mapToJson(Map<String, Double> wordweights, int num) {
+ Gson gson = new Gson();
+
+ List<JsonObject> nodes = new ArrayList<>();
+ Set<String> words = wordweights.keySet();
+ int i = 0;
+ for (String wordB : words) {
+ JsonObject node = new JsonObject();
+ node.addProperty("name", wordB);
+ node.addProperty("weight", wordweights.get(wordB));
+ nodes.add(node);
+
+ i += 1;
+ if (i >= num) {
+ break;
+ }
+ }
+
+ String nodesJson = gson.toJson(nodes);
+ JsonElement nodesElement = gson.fromJson(nodesJson, JsonElement.class);
+
+ return nodesElement;
+ }
+
+ public Map<String, Double> getRelatedData(String type, String input, int num) {
+ termList = new ArrayList<>();
+ Map<String, Double> termsMap = new HashMap<>();
+ Map<String, Double> sortedMap = new HashMap<>();
+ try {
+ List<LinkedTerm> links = getRelatedDataFromES(type, input, num);
+ int size = links.size();
+ for (int i = 0; i < size; i++) {
+ termsMap.put(links.get(i).term, links.get(i).weight);
+ }
+
+ sortedMap = sortMapByValue(termsMap); // terms_map will be empty
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return sortedMap;
+ }
+
+ public List<LinkedTerm> getRelatedDataFromES(String type, String input, int num) {
+ SearchRequestBuilder builder = es.getClient().prepareSearch(props.getProperty(INDEX_NAME)).setTypes(type).setQuery(QueryBuilders.termQuery("concept_A", input)).addSort(WEIGHT, SortOrder.DESC)
+ .setSize(num);
+
+ SearchResponse usrhis = builder.execute().actionGet();
+
+ for (SearchHit hit : usrhis.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String conceptB = (String) result.get("concept_B");
+
+ if (!conceptB.equals(input)) {
+ LinkedTerm lTerm = new LinkedTerm(conceptB, (double) result.get(WEIGHT), type);
+ termList.add(lTerm);
+ }
+ }
+
+ return termList;
+ }
+
+ public Map<String, Double> sortMapByValue(Map<String, Double> passedMap) {
+ List<String> mapKeys = new ArrayList<>(passedMap.keySet());
+ List<Double> mapValues = new ArrayList<>(passedMap.values());
+ Collections.sort(mapValues, Collections.reverseOrder());
+ Collections.sort(mapKeys, Collections.reverseOrder());
+
+ LinkedHashMap<String, Double> sortedMap = new LinkedHashMap<>();
+
+ Iterator<Double> valueIt = mapValues.iterator();
+ while (valueIt.hasNext()) {
+ Object val = valueIt.next();
+ Iterator<String> keyIt = mapKeys.iterator();
+
+ while (keyIt.hasNext()) {
+ Object key = keyIt.next();
+ String comp1 = passedMap.get(key).toString();
+ String comp2 = val.toString();
+
+ if (comp1.equals(comp2)) {
+ passedMap.remove(key);
+ mapKeys.remove(key);
+ sortedMap.put((String) key, (Double) val);
+ break;
+ }
+ }
+ }
+ return sortedMap;
+ }
+
+ public static void main(String[] args) throws IOException {
+
+ MudrodEngine me = new MudrodEngine();
+ Properties props = me.loadConfig();
+ ESDriver es = new ESDriver(me.getConfig());
+ RecomData test = new RecomData(props, es, null);
+
+ String input = "AQUARIUS_L3_SSS_SMIA_MONTHLY-CLIMATOLOGY_V4";
+ JsonObject json = test.getRecomDataInJson(input, 10);
+
+ System.out.println(json.toString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/package-info.java
new file mode 100644
index 0000000..99199ca
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes the data structure required by recommendation module.
+ */
+package gov.nasa.jpl.mudrod.recommendation.structure;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SVDAnalyzer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SVDAnalyzer.java b/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SVDAnalyzer.java
new file mode 100644
index 0000000..3e63b04
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SVDAnalyzer.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.semantics;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.utils.MatrixUtil;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.mllib.linalg.Vector;
+import org.apache.spark.mllib.linalg.distributed.RowMatrix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * ClassName: SVDAnalyzer Function: Analyze semantic relationship through SVD
+ * method
+ */
+public class SVDAnalyzer extends SemanticAnalyzer {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of SVDAnalyzer.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch drive
+ * @param spark the spark drive
+ */
+ public SVDAnalyzer(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * GetSVDMatrix: Create SVD matrix csv file from original csv file.
+ *
+ * @param csvFileName each row is a term, and each column is a document.
+ * @param svdDimention Dimension of SVD matrix
+ * @param svdMatrixFileName CSV file name of SVD matrix
+ */
+ public void getSVDMatrix(String csvFileName, int svdDimention, String svdMatrixFileName) {
+
+ JavaPairRDD<String, Vector> importRDD = MatrixUtil.loadVectorFromCSV(spark, csvFileName, 1);
+ JavaRDD<Vector> vectorRDD = importRDD.values();
+ RowMatrix wordDocMatrix = new RowMatrix(vectorRDD.rdd());
+ RowMatrix tfidfMatrix = MatrixUtil.createTFIDFMatrix(wordDocMatrix);
+ RowMatrix svdMatrix = MatrixUtil.buildSVDMatrix(tfidfMatrix, svdDimention);
+
+ List<String> rowKeys = importRDD.keys().collect();
+ List<String> colKeys = new ArrayList<>();
+ for (int i = 0; i < svdDimention; i++) {
+ colKeys.add("dimension" + i);
+ }
+ MatrixUtil.exportToCSV(svdMatrix, rowKeys, colKeys, svdMatrixFileName);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SemanticAnalyzer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SemanticAnalyzer.java b/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SemanticAnalyzer.java
new file mode 100644
index 0000000..be8b2b3
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/semantics/SemanticAnalyzer.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.semantics;
+
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.utils.LinkageTriple;
+import gov.nasa.jpl.mudrod.utils.MatrixUtil;
+import gov.nasa.jpl.mudrod.utils.SimilarityUtil;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.mllib.linalg.Vector;
+import org.apache.spark.mllib.linalg.distributed.CoordinateMatrix;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * ClassName: SemanticAnalyzer Function: Semantic analyzer
+ */
+public class SemanticAnalyzer extends MudrodAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of SemanticAnalyzer.
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch drive
+ * @param spark
+ * the spark drive
+ */
+ public SemanticAnalyzer(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Calculate term similarity from CSV matrix.
+ *
+ * @param csvFileName
+ * csv file of matrix, each row is a term, and each column is a
+ * dimension in feature space
+ * @return Linkage triple list
+ */
+ public List<LinkageTriple> calTermSimfromMatrix(String csvFileName) {
+ File f = new File(csvFileName);
+ if (!f.exists()) {
+ return null;
+ }
+ return this.calTermSimfromMatrix(csvFileName, 1);
+ }
+
+ /**
+ * Calculate term similarity from CSV matrix.
+ *
+ * @param csvFileName csv file of matrix, each row is a term, and each column is a
+ * dimension in feature space
+ * @param skipRow number of rows to skip in input CSV file e.g. header
+ * @return Linkage triple list
+ */
+ public List<LinkageTriple> calTermSimfromMatrix(String csvFileName, int skipRow) {
+
+ JavaPairRDD<String, Vector> importRDD = MatrixUtil.loadVectorFromCSV(spark, csvFileName, skipRow);
+ if (importRDD == null || importRDD.values().first().size() == 0) {
+ return null;
+ }
+
+ CoordinateMatrix simMatrix = SimilarityUtil.calculateSimilarityFromVector(importRDD.values());
+ JavaRDD<String> rowKeyRDD = importRDD.keys();
+ return SimilarityUtil.matrixToTriples(rowKeyRDD, simMatrix);
+ }
+
+ /**
+ * Calculate term similarity from CSV matrix.
+ *
+ * @param csvFileName csv file of matrix, each row is a term, and each column is a
+ * dimension in feature space
+ * @param simType the type of similary calculation to execute e.g.
+ * <ul>
+ * <li>{@link gov.nasa.jpl.mudrod.utils.SimilarityUtil#SIM_COSINE} - 3,</li>
+ * <li>{@link gov.nasa.jpl.mudrod.utils.SimilarityUtil#SIM_HELLINGER} - 2,</li>
+ * <li>{@link gov.nasa.jpl.mudrod.utils.SimilarityUtil#SIM_PEARSON} - 1</li>
+ * </ul>
+ * @param skipRow number of rows to skip in input CSV file e.g. header
+ * @return Linkage triple list
+ */
+ public List<LinkageTriple> calTermSimfromMatrix(String csvFileName, int simType, int skipRow) {
+
+ JavaPairRDD<String, Vector> importRDD = MatrixUtil.loadVectorFromCSV(spark, csvFileName, skipRow);
+ if (importRDD.values().first().size() == 0) {
+ return null;
+ }
+
+ JavaRDD<LinkageTriple> triples = SimilarityUtil.calculateSimilarityFromVector(importRDD, simType);
+
+ return triples.collect();
+ }
+
+ public void saveToES(List<LinkageTriple> tripleList, String index, String type) {
+ try {
+ LinkageTriple.insertTriples(es, tripleList, index, type);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method of saving linkage triples to Elasticsearch.
+ *
+ * @param tripleList
+ * linkage triple list
+ * @param index
+ * index name
+ * @param type
+ * type name
+ * @param bTriple
+ * bTriple
+ * @param bSymmetry
+ * bSymmetry
+ */
+ public void saveToES(List<LinkageTriple> tripleList, String index, String type, boolean bTriple, boolean bSymmetry) {
+ try {
+ LinkageTriple.insertTriples(es, tripleList, index, type, bTriple, bSymmetry);
+ } catch (IOException e) {
+ e.printStackTrace();
+
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/semantics/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/semantics/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/semantics/package-info.java
new file mode 100644
index 0000000..9c2e8ac
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/semantics/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes SVD transformation function, methods of calculating
+ * similarity from CSV, and saving triples into Elasticsearch
+ */
+package gov.nasa.jpl.mudrod.semantics;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ClickstreamImporter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ClickstreamImporter.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ClickstreamImporter.java
new file mode 100644
index 0000000..5cb130c
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ClickstreamImporter.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch;
+
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * Supports ability to import click stream data into Elasticsearch
+ * through .csv file
+ */
+public class ClickstreamImporter extends MudrodAbstract {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public ClickstreamImporter(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ addClickStreamMapping();
+ }
+
+ /**
+ * Method to add Elasticsearch mapping for click stream data
+ */
+ public void addClickStreamMapping() {
+ XContentBuilder Mapping;
+ try {
+ Mapping = jsonBuilder().startObject().startObject(
+ props.getProperty(MudrodConstants.CLICK_STREAM_MATRIX_TYPE)).startObject(
+ "properties").startObject("query").field("type", "string").field(
+ "index", "not_analyzed").endObject().startObject("dataID").field(
+ "type", "string").field("index", "not_analyzed").endObject()
+
+ .endObject().endObject().endObject();
+
+ es.getClient().admin().indices().preparePutMapping(
+ props.getProperty(MudrodConstants.ES_INDEX_NAME)).setType(
+ props.getProperty(MudrodConstants.CLICK_STREAM_MATRIX_TYPE)).setSource(
+ Mapping).execute().actionGet();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method to import click stream CSV into Elasticsearch
+ */
+ public void importfromCSVtoES() {
+ es.deleteType(props.getProperty(MudrodConstants.ES_INDEX_NAME),
+ props.getProperty(MudrodConstants.CLICK_STREAM_MATRIX_TYPE));
+ es.createBulkProcessor();
+
+ BufferedReader br = null;
+ String cvsSplitBy = ",";
+
+ try {
+ br = new BufferedReader(new FileReader(props.getProperty("clickstreamMatrix")));
+ String line = br.readLine();
+ // first item needs to be skipped
+ String[] dataList = line.split(cvsSplitBy);
+ while ((line = br.readLine()) != null) {
+ String[] clicks = line.split(cvsSplitBy);
+ for (int i = 1; i < clicks.length; i++) {
+ if (!"0.0".equals(clicks[i])) {
+ IndexRequest ir = new IndexRequest(props.getProperty(MudrodConstants.ES_INDEX_NAME),
+ props.getProperty(MudrodConstants.CLICK_STREAM_MATRIX_TYPE))
+ .source(jsonBuilder().startObject().field("query", clicks[0]).field(
+ "dataID", dataList[i]).field("clicks", clicks[i]).endObject());
+ es.getBulkProcessor().add(ir);
+ }
+ }
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ es.destroyBulkProcessor();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Dispatcher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Dispatcher.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Dispatcher.java
new file mode 100644
index 0000000..a0f3a2c
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Dispatcher.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch;
+
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.integration.LinkageIntegration;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.MatchQueryBuilder;
+import org.elasticsearch.index.query.MultiMatchQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+/**
+ * Supports ability to transform regular user query into a semantic query
+ */
+public class Dispatcher extends MudrodAbstract {
+ private static final Logger LOG = LoggerFactory.getLogger(Dispatcher.class);
+
+ public Dispatcher(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Method of getting semantically most related terms by number
+ *
+ * @param input regular input query
+ * @param num the number of most related terms
+ * @return a map from term to similarity
+ */
+ public Map<String, Double> getRelatedTerms(String input, int num) {
+ LinkageIntegration li = new LinkageIntegration(props, this.es, null);
+ Map<String, Double> sortedMap = li.appyMajorRule(input);
+ Map<String, Double> selected_Map = new HashMap<>();
+ int count = 0;
+ for (Entry<String, Double> entry : sortedMap.entrySet()) {
+ if (count < num) {
+ selected_Map.put(entry.getKey(), entry.getValue());
+ }
+ count++;
+ }
+ return selected_Map;
+ }
+
+ /**
+ * Method of getting semantically most related terms by similarity threshold
+ *
+ * @param input regular input query
+ * @param T value of threshold, raning from 0 to 1
+ * @return a map from term to similarity
+ */
+ public Map<String, Double> getRelatedTermsByT(String input, double T) {
+ LinkageIntegration li = new LinkageIntegration(this.props, this.es, null);
+ Map<String, Double> sortedMap = li.appyMajorRule(input);
+ Map<String, Double> selected_Map = new HashMap<>();
+
+ for (Entry<String, Double> entry : sortedMap.entrySet()) {
+ if (entry.getValue() >= T) {
+ selected_Map.put(entry.getKey(), entry.getValue());
+ }
+ }
+ return selected_Map;
+ }
+
+ /**
+ * Method of creating semantic query based on Threshold
+ *
+ * @param input regular query
+ * @param T threshold raning from 0 to 1
+ * @param query_operator query mode
+ * @return a multiMatch query builder
+ */
+ public BoolQueryBuilder createSemQuery(String input, double T, String query_operator) {
+ Map<String, Double> selected_Map = getRelatedTermsByT(input, T);
+ selected_Map.put(input, (double) 1);
+
+ String fieldsList[] = { "Dataset-Metadata", "Dataset-ShortName", "Dataset-LongName",
+ "DatasetParameter-Topic", "DatasetParameter-VariableDetail", "DatasetParameter-Category",
+ "DatasetParameter-Variable", "DatasetParameter-Term",
+ "DatasetSource-Source-LongName", "DatasetSource-Source-LongName-Full",
+ "DatasetSource-Source-ShortName", "DatasetSource-Source-ShortName-Full",
+ "DatasetSource-Sensor-LongName", "DatasetSource-Sensor-LongName-Full", "DatasetSource-Sensor-ShortName",
+ "DatasetSource-Sensor-ShortName-Full" };
+ BoolQueryBuilder qb = new BoolQueryBuilder();
+ for (Entry<String, Double> entry : selected_Map.entrySet()) {
+ if (query_operator.toLowerCase().trim().equals("phrase")) {
+ qb.should(QueryBuilders.multiMatchQuery(entry.getKey(), fieldsList).boost(entry.getValue().floatValue()).type(MultiMatchQueryBuilder.Type.PHRASE).tieBreaker((float) 0.5)); // when
+ // set
+ // to
+ // 1.0,
+ // it
+ // would
+ // be
+ // equal
+ // to
+ // "most
+ // fields"
+ // query
+ } else if (query_operator.toLowerCase().trim().equals("and")) {
+ qb.should(QueryBuilders.multiMatchQuery(entry.getKey(), fieldsList).boost(entry.getValue().floatValue()).operator(MatchQueryBuilder.DEFAULT_OPERATOR.AND).tieBreaker((float) 0.5));
+ } else {
+ qb.should(QueryBuilders.multiMatchQuery(entry.getKey(), fieldsList).boost(entry.getValue().floatValue()).operator(MatchQueryBuilder.DEFAULT_OPERATOR.OR).tieBreaker((float) 0.5));
+ }
+ }
+
+ // LOG.info(qb.toString());
+ return qb;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Ranker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Ranker.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Ranker.java
new file mode 100644
index 0000000..32830d5
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Ranker.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch;
+
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.ssearch.ranking.Learner;
+import gov.nasa.jpl.mudrod.ssearch.structure.SResult;
+import org.apache.spark.mllib.linalg.Vectors;
+import org.apache.spark.mllib.regression.LabeledPoint;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.*;
+
+/**
+ * Supports the ability to calculating ranking score
+ */
+public class Ranker extends MudrodAbstract implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ transient List<SResult> resultList = new ArrayList<>();
+
+ String learnerType = null;
+ Learner le = null;
+
+ public Ranker(Properties props, ESDriver es, SparkDriver spark, String learnerType) {
+ super(props, es, spark);
+ this.learnerType = learnerType;
+ le = new Learner(learnerType, spark, props.getProperty(MudrodConstants.SVM_SGD_MODEL));
+ }
+
+ /**
+ * Method of comparing results based on final score
+ */
+ public class ResultComparator implements Comparator<SResult> {
+ @Override
+ public int compare(SResult o1, SResult o2) {
+ return o2.below.compareTo(o1.below);
+ }
+ }
+
+ /**
+ * Method of calculating mean value
+ *
+ * @param attribute the attribute name that need to be calculated on
+ * @param resultList an array list of result
+ * @return mean value
+ */
+ private double getMean(String attribute, List<SResult> resultList) {
+ double sum = 0.0;
+ for (SResult a : resultList) {
+ sum += (double) SResult.get(a, attribute);
+ }
+ return getNDForm(sum / resultList.size());
+ }
+
+ /**
+ * Method of calculating variance value
+ *
+ * @param attribute the attribute name that need to be calculated on
+ * @param resultList an array list of result
+ * @return variance value
+ */
+ private double getVariance(String attribute, List<SResult> resultList) {
+ double mean = getMean(attribute, resultList);
+ double temp = 0.0;
+ double val;
+ for (SResult a : resultList) {
+ val = (Double) SResult.get(a, attribute);
+ temp += (mean - val) * (mean - val);
+ }
+
+ return getNDForm(temp / resultList.size());
+ }
+
+ /**
+ * Method of calculating standard variance
+ *
+ * @param attribute the attribute name that need to be calculated on
+ * @param resultList an array list of result
+ * @return standard variance
+ */
+ private double getStdDev(String attribute, List<SResult> resultList) {
+ return getNDForm(Math.sqrt(getVariance(attribute, resultList)));
+ }
+
+ /**
+ * Method of calculating Z score
+ *
+ * @param val the value of an attribute
+ * @param mean the mean value of an attribute
+ * @param std the standard deviation of an attribute
+ * @return Z score
+ */
+ private double getZscore(double val, double mean, double std) {
+ if (!equalComp(std, 0)) {
+ return getNDForm((val - mean) / std);
+ } else {
+ return 0;
+ }
+ }
+
+ private boolean equalComp(double a, double b) {
+ return Math.abs(a - b) < 0.0001;
+ }
+
+ /**
+ * Get the first N decimals of a double value
+ *
+ * @param d double value that needs to be processed
+ * @return processed double value
+ */
+ private double getNDForm(double d) {
+ DecimalFormat ndForm = new DecimalFormat("#.###");
+ return Double.valueOf(ndForm.format(d));
+ }
+
+ /**
+ * Method of ranking a list of result
+ *
+ * @param resultList result list
+ * @return ranked result list
+ */
+ public List<SResult> rank(List<SResult> resultList) {
+ for (int i = 0; i < resultList.size(); i++) {
+ for (int m = 0; m < SResult.rlist.length; m++) {
+ String att = SResult.rlist[m].split("_")[0];
+ double val = SResult.get(resultList.get(i), att);
+ double mean = getMean(att, resultList);
+ double std = getStdDev(att, resultList);
+ double score = getZscore(val, mean, std);
+ String scoreId = SResult.rlist[m];
+ SResult.set(resultList.get(i), scoreId, score);
+ }
+ }
+
+ // using collection.sort directly would cause an "not transitive" error
+ // this is because the training model is not a overfitting model
+ for (int j = 0; j < resultList.size(); j++) {
+ for (int k = 0; k < resultList.size(); k++) {
+ if (k != j) {
+ resultList.get(j).below += comp(resultList.get(j), resultList.get(k));
+ }
+ }
+ }
+
+ Collections.sort(resultList, new ResultComparator());
+ return resultList;
+ }
+
+ /**
+ * Method of compare two search resutls
+ *
+ * @param o1 search result 1
+ * @param o2 search result 2
+ * @return 1 if o1 is greater than o2, 0 otherwise
+ */
+ public int comp(SResult o1, SResult o2) {
+ List<Double> instList = new ArrayList<>();
+ for (int i = 0; i < SResult.rlist.length; i++) {
+ double o2Score = SResult.get(o2, SResult.rlist[i]);
+ double o1Score = SResult.get(o1, SResult.rlist[i]);
+ instList.add(o2Score - o1Score);
+ }
+
+ double[] ins = instList.stream().mapToDouble(i -> i).toArray();
+ LabeledPoint insPoint = new LabeledPoint(99.0, Vectors.dense(ins));
+ double prediction = le.classify(insPoint);
+ if (equalComp(prediction, 1)) { //different from weka where the return value is 1 or 2
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Searcher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Searcher.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Searcher.java
new file mode 100644
index 0000000..f407f92
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/Searcher.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.ssearch.structure.SResult;
+
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.sort.SortBuilder;
+import org.elasticsearch.search.sort.SortOrder;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Supports ability to performance semantic search with a given query
+ */
+public class Searcher extends MudrodAbstract implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ DecimalFormat NDForm = new DecimalFormat("#.##");
+ final Integer MAX_CHAR = 700;
+
+ public Searcher(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Method of converting processing level string into a number
+ *
+ * @param pro processing level string
+ * @return processing level number
+ */
+ public Double getProLevelNum(String pro) {
+ if (pro == null) {
+ return 1.0;
+ }
+ Double proNum;
+ Pattern p = Pattern.compile(".*[a-zA-Z].*");
+ if (pro.matches("[0-9]{1}[a-zA-Z]{1}")) {
+ proNum = Double.parseDouble(pro.substring(0, 1));
+ } else if (p.matcher(pro).find()) {
+ proNum = 1.0;
+ } else {
+ proNum = Double.parseDouble(pro);
+ }
+
+ return proNum;
+ }
+
+ public Double getPop(Double pop) {
+ if (pop > 1000) {
+ pop = 1000.0;
+ }
+ return pop;
+ }
+
+ /**
+ * Method of checking if query exists in a certain attribute
+ *
+ * @param strList attribute value in the form of ArrayList
+ * @param query query string
+ * @return 1 means query exists, 0 otherwise
+ */
+ public Double exists(ArrayList<String> strList, String query) {
+ Double val = 0.0;
+ if (strList != null) {
+ String str = String.join(", ", strList);
+ if (str != null && str.length() != 0 && str.toLowerCase().trim().contains(query)) {
+ val = 1.0;
+ }
+ }
+ return val;
+ }
+
+ /**
+ * Main method of semantic search
+ *
+ * @param index index name in Elasticsearch
+ * @param type type name in Elasticsearch
+ * @param query regular query string
+ * @param queryOperator query mode- query, or, and
+ * @return a list of search result
+ */
+ @SuppressWarnings("unchecked")
+ public List<SResult> searchByQuery(String index, String type, String query, String queryOperator, String rankOption) {
+ boolean exists = es.getClient().admin().indices().prepareExists(index).execute().actionGet().isExists();
+ if (!exists) {
+ return new ArrayList<>();
+ }
+
+ SortOrder order = null;
+ String sortFiled = "";
+ switch (rankOption) {
+ case "Rank-AllTimePopularity":
+ sortFiled = "Dataset-AllTimePopularity";
+ order = SortOrder.DESC;
+ break;
+ case "Rank-MonthlyPopularity":
+ sortFiled = "Dataset-MonthlyPopularity";
+ order = SortOrder.DESC;
+ break;
+ case "Rank-UserPopularity":
+ sortFiled = "Dataset-UserPopularity";
+ order = SortOrder.DESC;
+ break;
+ case "Rank-LongName-Full":
+ sortFiled = "Dataset-LongName.raw";
+ order = SortOrder.ASC;
+ break;
+ case "Rank-ShortName-Full":
+ sortFiled = "Dataset-ShortName.raw";
+ order = SortOrder.ASC;
+ break;
+ case "Rank-GridSpatialResolution":
+ sortFiled = "Dataset-GridSpatialResolution";
+ order = SortOrder.DESC;
+ break;
+ case "Rank-SatelliteSpatialResolution":
+ sortFiled = "Dataset-SatelliteSpatialResolution";
+ order = SortOrder.DESC;
+ break;
+ case "Rank-StartTimeLong-Long":
+ sortFiled = "DatasetCoverage-StartTimeLong-Long";
+ order = SortOrder.ASC;
+ break;
+ case "Rank-StopTimeLong-Long":
+ sortFiled = "DatasetCoverage-StopTimeLong-Long";
+ order = SortOrder.DESC;
+ break;
+ default:
+ sortFiled = "Dataset-ShortName.raw";
+ order = SortOrder.ASC;
+ break;
+ }
+
+ Dispatcher dp = new Dispatcher(this.getConfig(), this.getES(), null);
+ BoolQueryBuilder qb = dp.createSemQuery(query, 1.0, queryOperator);
+ List<SResult> resultList = new ArrayList<>();
+
+ SearchRequestBuilder builder = es.getClient().prepareSearch(index).setTypes(type).setQuery(qb).addSort(sortFiled, order).setSize(500).setTrackScores(true);
+ SearchResponse response = builder.execute().actionGet();
+
+ for (SearchHit hit : response.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ Double relevance = Double.valueOf(NDForm.format(hit.getScore()));
+ String shortName = (String) result.get("Dataset-ShortName");
+ String longName = (String) result.get("Dataset-LongName");
+
+ ArrayList<String> topicList = (ArrayList<String>) result.get("DatasetParameter-Variable");
+ String topic = "";
+ if (null != topicList) {
+ topic = String.join(", ", topicList);
+ }
+ String content = (String) result.get("Dataset-Description");
+
+ if (!"".equals(content)) {
+ int maxLength = (content.length() < MAX_CHAR) ? content.length() : MAX_CHAR;
+ content = content.trim().substring(0, maxLength - 1) + "...";
+ }
+
+ ArrayList<String> longdate = (ArrayList<String>) result.get("DatasetCitation-ReleaseDateLong");
+ Date date = new Date(Long.valueOf(longdate.get(0)).longValue());
+ SimpleDateFormat df2 = new SimpleDateFormat("MM/dd/yyyy");
+ String dateText = df2.format(date);
+
+ // start date
+ Long start = (Long) result.get("DatasetCoverage-StartTimeLong-Long");
+ Date startDate = new Date(start);
+ String startDateTxt = df2.format(startDate);
+
+ // end date
+ String end = (String) result.get("Dataset-DatasetCoverage-StopTimeLong");
+ String endDateTxt = "";
+ if ("".equals(end)) {
+ endDateTxt = "Present";
+ } else {
+ Date endDate = new Date(Long.valueOf(end));
+ endDateTxt = df2.format(endDate);
+ }
+
+ String processingLevel = (String) result.get("Dataset-ProcessingLevel");
+ Double proNum = getProLevelNum(processingLevel);
+
+ Double userPop = getPop(((Integer) result.get("Dataset-UserPopularity")).doubleValue());
+ Double allPop = getPop(((Integer) result.get("Dataset-AllTimePopularity")).doubleValue());
+ Double monthPop = getPop(((Integer) result.get("Dataset-MonthlyPopularity")).doubleValue());
+
+ List<String> sensors = (List<String>) result.get("DatasetSource-Sensor-ShortName");
+
+ SResult re = new SResult(shortName, longName, topic, content, dateText);
+
+ SResult.set(re, "term", relevance);
+ SResult.set(re, "releaseDate", Long.valueOf(longdate.get(0)).doubleValue());
+ SResult.set(re, "processingLevel", processingLevel);
+ SResult.set(re, "processingL", proNum);
+ SResult.set(re, "userPop", userPop);
+ SResult.set(re, "allPop", allPop);
+ SResult.set(re, "monthPop", monthPop);
+ SResult.set(re, "startDate", startDateTxt);
+ SResult.set(re, "endDate", endDateTxt);
+ SResult.set(re, "sensors", String.join(", ", sensors));
+
+ QueryBuilder queryLabelSearch = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("query", query)).must(QueryBuilders.termQuery("dataID", shortName));
+ SearchResponse labelRes = es.getClient().prepareSearch(index).setTypes("trainingranking").setQuery(queryLabelSearch).setSize(5).execute().actionGet();
+ String labelString = null;
+ for (SearchHit label : labelRes.getHits().getHits()) {
+ Map<String, Object> labelItem = label.getSource();
+ labelString = (String) labelItem.get("label");
+ }
+ SResult.set(re, "label", labelString);
+ resultList.add(re);
+ }
+
+ return resultList;
+ }
+
+ /**
+ * Method of semantic search to generate JSON string
+ *
+ * @param index index name in Elasticsearch
+ * @param type type name in Elasticsearch
+ * @param query regular query string
+ * @param queryOperator query mode- query, or, and
+ * @param rr selected ranking method
+ * @return search results
+ */
+ public String ssearch(String index, String type, String query, String queryOperator, String rankOption, Ranker rr) {
+ List<SResult> li = searchByQuery(index, type, query, queryOperator, rankOption);
+ if ("Rank-SVM".equals(rankOption)) {
+ li = rr.rank(li);
+ }
+ Gson gson = new Gson();
+ List<JsonObject> fileList = new ArrayList<>();
+
+ for (int i = 0; i < li.size(); i++) {
+ JsonObject file = new JsonObject();
+ file.addProperty("Short Name", (String) SResult.get(li.get(i), "shortName"));
+ file.addProperty("Long Name", (String) SResult.get(li.get(i), "longName"));
+ file.addProperty("Topic", (String) SResult.get(li.get(i), "topic"));
+ file.addProperty("Description", (String) SResult.get(li.get(i), "description"));
+ file.addProperty("Release Date", (String) SResult.get(li.get(i), "relase_date"));
+ fileList.add(file);
+
+ file.addProperty("Start/End Date", (String) SResult.get(li.get(i), "startDate") + " - " + (String) SResult.get(li.get(i), "endDate"));
+ file.addProperty("Processing Level", (String) SResult.get(li.get(i), "processingLevel"));
+
+ file.addProperty("Sensor", (String) SResult.get(li.get(i), "sensors"));
+ }
+ JsonElement fileListElement = gson.toJsonTree(fileList);
+
+ JsonObject pDResults = new JsonObject();
+ pDResults.add("PDResults", fileListElement);
+ return pDResults.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/package-info.java
new file mode 100644
index 0000000..da6bea3
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes classes for semantic search, such as click stream importer,
+ * query dispatcher, semantic searcher, and ranker (ranksvm, ordinal/linear regression)
+ */
+package gov.nasa.jpl.mudrod.ssearch;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/DataGenerator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/DataGenerator.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/DataGenerator.java
new file mode 100644
index 0000000..598ad61
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/DataGenerator.java
@@ -0,0 +1,313 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch.ranking;
+
+import au.com.bytecode.opencsv.CSVReader;
+import au.com.bytecode.opencsv.CSVWriter;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * SVMData is a program designed to create appropriate input data for the RankSVM
+ * algorithm that involves Pairwise Classification. Specifically, instead of working in
+ * the space of query-document vectors, e.g. x1, x2, x3, we transform them into a new space
+ * in which a pair of documents is represented as the difference between their feature vectors.
+ */
+public class DataGenerator {
+ private static String mySourceDir;
+ private static String myResultDir;
+ private static boolean isMultFiles;
+
+ private static String[] myHeader;
+ private static List<List<String>> myMasterList = new ArrayList<List<String>>();
+
+ // HashMap used for comparing evaluation classes
+ public static final HashMap<String, Integer> map1 = new HashMap<String, Integer>();
+
+ static {
+ map1.put("Excellent", 7);
+ map1.put("Very good", 6);
+ map1.put("Good", 5);
+ map1.put("OK", 4);
+ map1.put("Bad", 3);
+ map1.put("Very bad", 2);
+ map1.put("Terrible", 1);
+ }
+
+ /**
+ * Constructor which takes in path containing one or multiple files to process.
+ * Also takes in argument specifying whether or not a single file needs to be processed,
+ * or multiple files need to be processed.
+ *
+ * @param sourceDir directory containing single file or multiple files to be processed
+ * @param resultDir output folder
+ * @param multFiles true if multiple files in directory need to be processed and false if
+ * only a single file needs to be processed
+ */
+ public DataGenerator(String sourceDir, String resultDir, boolean multFiles) {
+ mySourceDir = sourceDir;
+ myResultDir = resultDir;
+ isMultFiles = multFiles;
+ }
+
+ /**
+ * Responsible for invoking the processing of data file(s) and their subsequent storage
+ * into a user specified directory.
+ */
+ public void process() {
+ parseFile();
+ writeCSVfile(myMasterList);
+ }
+
+ /**
+ * Parses the original user-specified CSV file, storing the contents for future calculations
+ * and formatting.
+ */
+ public static void parseFile() {
+ String[][] dataArr = null;
+ try {
+ String sourceDir = mySourceDir;
+
+ if (isMultFiles == true) // Case where multiple files have to be processed
+ {
+ // Iterate over files in directory
+ File directory = new File(sourceDir);
+ File[] directoryListing = directory.listFiles();
+
+ if (directoryListing != null) {
+ for (File child : directoryListing) {
+ CSVReader csvReader = new CSVReader(new FileReader(child));
+ List<String[]> list = csvReader.readAll();
+
+ // Store into 2D array by transforming array list to normal array
+ dataArr = new String[list.size()][];
+ dataArr = list.toArray(dataArr);
+
+ calculateVec(dataArr);
+
+ csvReader.close();
+ }
+ storeHead(dataArr); // Store the header
+ }
+ } else // Process only one file
+ {
+ File file = new File(sourceDir);
+
+ if (file != null) {
+ CSVReader csvReader = new CSVReader(new FileReader(file));
+ List<String[]> list = csvReader.readAll();
+
+ // Store into 2D array by transforming array list to normal array
+ dataArr = new String[list.size()][];
+ dataArr = list.toArray(dataArr);
+
+ storeHead(dataArr); // Store the header
+ calculateVec(dataArr);
+
+ csvReader.close();
+ }
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Performs the necessary vector calculations on each possible combination of vectors,
+ * also storing a value that indicates the evaluation.
+ *
+ * @param arr the parsed contents of the original CSV file
+ */
+ public static void calculateVec(String[][] arr) {
+ List<List<String>> listofLists = new ArrayList<List<String>>(); // Holds calculations
+
+ int rowStart = 1;
+ for (int row = rowStart; row < arr.length; row++) // Start at row 1 because row 0 is heading lol
+ {
+ for (int i = 1; i < arr.length - row; i++) {
+ List<String> colList = new ArrayList<String>(); // create vector to store all values inside of a column, which is stored inside 2D vector
+ for (int col = 0; col < arr[0].length - 1; col++) // Columns go until the next to last column
+ {
+ //System.out.println(col + " " + arr[row][col]);
+ // Extract double value from each cell
+ double x1 = Double.parseDouble(arr[row][col]);
+ double x2 = Double.parseDouble(arr[row + i][col]);
+
+ // Perform calculation for each cell
+ double result = x1 - x2;
+
+ // Convert this double value into string, and store inside array list
+ String strResult = Double.toString(result);
+ colList.add(strResult);
+ }
+
+ // Finally, add either 1, -1, or do not add row at all when encountering evaluation value
+ int addEvalNum = compareEvaluation(arr[row][arr[0].length - 1], arr[row + i][arr[0].length - 1]);
+ if (addEvalNum == 1) {
+ colList.add("1");
+ listofLists.add(colList); // Add this list to 2D list - row is finished now, move on
+ } else if (addEvalNum == -1) {
+ colList.add("-1");
+ listofLists.add(colList); // Add this list to 2D list - row is finished now, move on
+ }
+ // Else, they are equal, do not even add this row to 2D vector
+ }
+ }
+
+ // After all processing takes place, send to method that recreates data with equal # of 1's and -1's
+ List<List<String>> equalizedList = equalizeList(listofLists);
+ myMasterList.addAll(equalizedList);
+ }
+
+ /**
+ * Taking in two vector evaluation parameters, compares these two evaluations, returning a 1
+ * if the first evaluation is greater than the second, a -1 in the case the first evaluation is
+ * less than the second, and a 10 in the case that the two are equal, meaning this vector will
+ * not be used.
+ *
+ * @param eval1 evaluation from first vector
+ * @param eval2 evaluation from second vector
+ * @return 1 if first evaluation is greater than the second, -1 if first evaluation is less than the second, and
+ * 10 in the case that the two are equal
+ */
+ public static int compareEvaluation(String eval1, String eval2) {
+ int evalNum1 = map1.get(eval1);
+ int evalNum2 = map1.get(eval2);
+
+ if (evalNum1 > evalNum2) // ">" means it is more relevant - assign a 1
+ {
+ return 1;
+ } else if (evalNum1 < evalNum2) {
+ return -1;
+ } else {
+ return 10; // Return 10 if they are equal - signifies you cannot use the row
+ }
+ }
+
+ /**
+ * After vector calculations and new evaluation values are set, produces refined output data such that
+ * there is an equal or close to equal number of rows containing both "1" and "-1" as the new evaluation value.
+ *
+ * @param rawList originally calculated data from the input CSV file
+ * @return data that has an equal distribution of evaluation values
+ */
+ public static List<List<String>> equalizeList(List<List<String>> rawList) {
+ // Create two sets - one containing row index for +1 and the other for -1
+ List<Integer> pos1List = new ArrayList<Integer>();
+ List<Integer> neg1List = new ArrayList<Integer>();
+
+ for (int i = 0; i < rawList.size(); i++) // Iterate through all rows to get indexes
+ {
+ int evalNum = Integer.parseInt(rawList.get(i).get(rawList.get(0).size() - 1)); // Get 1 or -1 from original array list
+ if (evalNum == 1) {
+ pos1List.add(i); // Add row index that has 1
+ } else if (evalNum == -1) {
+ neg1List.add(i); // Add row index that has -1
+ }
+ }
+
+ int totPosCount = pos1List.size(); // Total # of 1's
+ int totNegCount = neg1List.size(); // Total # of -1's
+
+ if ((totPosCount - totNegCount) >= 1) // There are more 1's than -1's, equalize them
+ {
+ int indexOfPosList = 0; // Start getting indexes from the first index of positive index location list
+ while ((totPosCount - totNegCount) >= 1) // Keep going until we have acceptable amount of both +1 and -1
+ {
+ int pos1IndexVal = pos1List.get(indexOfPosList); // Get index from previously made list of indexes
+ for (int col = 0; col < rawList.get(0).size(); col++) // Go through elements of indexed row, negating it to transform to -1 row
+ {
+ double d = Double.parseDouble(rawList.get(pos1IndexVal).get(col)); // Transform to double first
+ d = d * -1; // Negate it
+ String negatedValue = Double.toString(d); // Change back to String
+ rawList.get(pos1IndexVal).set(col, negatedValue);// Put this value back into dat row
+ }
+
+ totPosCount--; // We changed a +1 row to a -1 row, decrement count of positives
+ totNegCount++; // Increment count of negatives
+ indexOfPosList++; // Get next +1 location in raw data
+ }
+ } else if ((totNegCount - totPosCount) > 1) // There are more -1's than 1's, equalize them
+ {
+ int indexOfNegList = 0;
+ while ((totNegCount - totPosCount) > 1) // Keep going until we have acceptable amount of both +1 and -1
+ {
+ int neg1IndexVal = neg1List.get(indexOfNegList); // Get index from previously made list of indexes
+ for (int col = 0; col < rawList.get(0).size(); col++) // Go through elements of indexed row, negating it to transform to +1 row
+ {
+ double d = Double.parseDouble(rawList.get(neg1IndexVal).get(col)); // Transform to double first
+ d = d * -1; // Negate it
+ String negatedValue = Double.toString(d); // Change back to String
+ rawList.get(neg1IndexVal).set(col, negatedValue);// Put this value back into dat row
+ }
+
+ totNegCount--; // We changed a -1 row to a +1 row, decrement count of negatives now
+ totPosCount++; // Increment count of positives
+ indexOfNegList++; // Get next -1 location in raw data
+ }
+ } else {
+ // Do nothing - rows are within acceptable equality bounds of plus or minus 1
+ }
+
+ return rawList;
+ }
+
+ /**
+ * Retrieves the heading from a file to be processed so it can be written to the output file later.
+ *
+ * @param arr 2D array containing the parsed information from input file
+ */
+ public static void storeHead(String[][] arr) {
+ myHeader = new String[arr[0].length]; // Reside private variable
+
+ for (int col = 0; col < arr[0].length; col++) {
+ myHeader[col] = arr[0][col];
+ }
+ }
+
+ /**
+ * Writes newly calculated and equally distributed vector data to user specified CSV file.
+ *
+ * @param list finalized vector data to write to user specified output file
+ */
+ public static void writeCSVfile(List<List<String>> list) {
+ String outputFile = myResultDir;
+ boolean alreadyExists = new File(outputFile).exists();
+
+ try {
+ CSVWriter csvOutput = new CSVWriter(new FileWriter(outputFile), ','); // Create new instance of CSVWriter to write to file output
+
+ if (!alreadyExists) {
+ csvOutput.writeNext(myHeader); // Write the text headers first before data
+
+ for (int i = 0; i < list.size(); i++) // Iterate through all rows in 2D array
+ {
+ String[] temp = new String[list.get(i).size()]; // Convert row array list in 2D array to regular string array
+ temp = list.get(i).toArray(temp);
+ csvOutput.writeNext(temp); // Write this array to the file
+ }
+ }
+
+ csvOutput.close(); // Close csvWriter
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Evaluator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Evaluator.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Evaluator.java
new file mode 100644
index 0000000..8edb6ad
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Evaluator.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch.ranking;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * Supports ability to evaluating ranking results
+ */
+public class Evaluator {
+ /**
+ * Method of calculating NDCG score
+ *
+ * @param list a list of integer with each integer element indicating
+ * the performance at its position
+ * @param K the number of elements needed to be included in the calculation
+ * @return NDCG score
+ */
+ public double getNDCG(int[] list, int K) {
+ double dcg = this.getDCG(list, K);
+ double idcg = this.getIDCG(list, K);
+ double ndcg = 0.0;
+ if (idcg > 0.0) {
+ ndcg = dcg / idcg;
+ }
+ return ndcg;
+ }
+
+ /**
+ * Method of getting the precision of a list at position K
+ *
+ * @param list a list of integer with each integer element indicating
+ * the performance at its position
+ * @param K the number of elements needed to be included in the calculation
+ * @return precision at K
+ */
+ public double getPrecision(int[] list, int K) {
+ int size = list.length;
+ if (size == 0 || K == 0) {
+ return 0;
+ }
+
+ if (K > size) {
+ K = size;
+ }
+
+ int rel_doc_num = this.getRelevantDocNum(list, K);
+ double precision = (double) rel_doc_num / (double) K;
+ return precision;
+ }
+
+ /**
+ * Method of getting the number of relevant element in a ranking results
+ *
+ * @param list a list of integer with each integer element indicating
+ * the performance at its position
+ * @param K the number of elements needed to be included in the calculation
+ * @return the number of relevant element
+ */
+ private int getRelevantDocNum(int[] list, int K) {
+ int size = list.length;
+ if (size == 0 || K == 0) {
+ return 0;
+ }
+
+ if (K > size) {
+ K = size;
+ }
+
+ int rel_num = 0;
+ for (int i = 0; i < K; i++) {
+ if (list[i] > 3) { // 3 refers to "OK"
+ rel_num++;
+ }
+ }
+ return rel_num;
+ }
+
+ /**
+ * Method of calculating DCG score from a list of ranking results
+ *
+ * @param list a list of integer with each integer element indicating
+ * the performance at its position
+ * @param K the number of elements needed to be included in the calculation
+ * @return DCG score
+ */
+ private double getDCG(int[] list, int K) {
+ int size = list.length;
+ if (size == 0 || K == 0) {
+ return 0.0;
+ }
+
+ if (K > size) {
+ K = size;
+ }
+
+ double dcg = list[0];
+ for (int i = 1; i < K; i++) {
+ int rel = list[i];
+ int pos = i + 1;
+ double rel_log = Math.log(pos) / Math.log(2);
+ dcg += rel / rel_log;
+ }
+ return dcg;
+ }
+
+ /**
+ * Method of calculating ideal DCG score from a list of ranking results
+ *
+ * @param list a list of integer with each integer element indicating
+ * the performance at its position
+ * @param K the number of elements needed to be included in the calculation
+ * @return IDCG score
+ */
+ private double getIDCG(int[] list, int K) {
+ Comparator<Integer> comparator = new Comparator<Integer>() {
+ @Override
+ public int compare(Integer o1, Integer o2) {
+ return o2.compareTo(o1);
+ }
+ };
+ List<Integer> sortlist = IntStream.of(list).boxed().collect(Collectors.toList());
+ ;
+ Collections.sort(sortlist, comparator);
+ int[] sortedArr = sortlist.stream().mapToInt(i -> i).toArray();
+ double idcg = this.getDCG(sortedArr, K);
+ return idcg;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Learner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Learner.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Learner.java
new file mode 100644
index 0000000..d1c5199
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/Learner.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch.ranking;
+
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.apache.spark.SparkContext;
+import org.apache.spark.mllib.classification.SVMModel;
+import org.apache.spark.mllib.regression.LabeledPoint;
+
+import java.io.Serializable;
+
+/**
+ * Supports the ability to importing classifier into memory
+ */
+public class Learner implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final String SPARKSVM = "SparkSVM";
+ SVMModel model = null;
+ transient SparkContext sc = null;
+
+ /**
+ * Constructor to load in spark SVM classifier
+ *
+ * @param classifierName classifier type
+ * @param skd an instance of spark driver
+ * @param svmSgdModel path to a trained model
+ */
+ public Learner(String classifierName, SparkDriver skd, String svmSgdModel) {
+ if (classifierName.equals(SPARKSVM)) {
+ sc = skd.sc.sc();
+ sc.addFile(svmSgdModel, true);
+ model = SVMModel.load(sc, svmSgdModel);
+ }
+ }
+
+ /**
+ * Method of classifying instance
+ *
+ * @param p the instance that needs to be classified
+ * @return the class id
+ */
+ public double classify(LabeledPoint p) {
+ return model.predict(p.features());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkFormatter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkFormatter.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkFormatter.java
new file mode 100644
index 0000000..ba46d41
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkFormatter.java
@@ -0,0 +1,55 @@
+package gov.nasa.jpl.mudrod.ssearch.ranking;
+
+import java.io.*;
+import java.text.DecimalFormat;
+
+public class SparkFormatter {
+ DecimalFormat NDForm = new DecimalFormat("#.###");
+
+ public SparkFormatter() {
+ }
+
+ public void toSparkSVMformat(String inputCSVFileName, String outputTXTFileName) {
+ File file = new File(outputTXTFileName);
+ if (file.exists()) {
+ file.delete();
+ }
+ try {
+ file.createNewFile();
+ FileWriter fw = new FileWriter(outputTXTFileName);
+ BufferedWriter bw = new BufferedWriter(fw);
+
+ BufferedReader br = new BufferedReader(new FileReader(inputCSVFileName));
+ br.readLine();
+ String line = br.readLine();
+ while (line != null) {
+ String[] list = line.split(",");
+ String output = "";
+ Double label = Double.parseDouble(list[list.length - 1].replace("\"", ""));
+ if (label == -1.0) {
+ output = "0 ";
+ } else if (label == 1.0) {
+ output = "1 ";
+ }
+
+ for (int i = 0; i < list.length - 1; i++) {
+ int index = i + 1;
+ output += index + ":" + NDForm.format(Double.parseDouble(list[i].replace("\"", ""))) + " ";
+ }
+ bw.write(output + "\n");
+
+ line = br.readLine();
+ }
+ br.close();
+ bw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ SparkFormatter sf = new SparkFormatter();
+ sf.toSparkSVMformat("C:/mudrodCoreTestData/rankingResults/inputDataForSVM.csv", "C:/mudrodCoreTestData/rankingResults/inputDataForSVM_spark.txt");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkSVM.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkSVM.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkSVM.java
new file mode 100644
index 0000000..1ddebf3
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/SparkSVM.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch.ranking;
+
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.mllib.classification.SVMModel;
+import org.apache.spark.mllib.classification.SVMWithSGD;
+import org.apache.spark.mllib.regression.LabeledPoint;
+import org.apache.spark.mllib.util.MLUtils;
+
+public class SparkSVM {
+
+ private SparkSVM() {
+ //public constructor
+ }
+
+ public static void main(String[] args) {
+ MudrodEngine me = new MudrodEngine();
+
+ JavaSparkContext jsc = me.startSparkDriver().sc;
+
+ String path = SparkSVM.class.getClassLoader().getResource("inputDataForSVM_spark.txt").toString();
+ JavaRDD<LabeledPoint> data = MLUtils.loadLibSVMFile(jsc.sc(), path).toJavaRDD();
+
+ // Run training algorithm to build the model.
+ int numIterations = 100;
+ final SVMModel model = SVMWithSGD.train(data.rdd(), numIterations);
+
+ // Save and load model
+ model.save(jsc.sc(), SparkSVM.class.getClassLoader().getResource("javaSVMWithSGDModel").toString());
+
+ jsc.sc().stop();
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/TrainingImporter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/TrainingImporter.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/TrainingImporter.java
new file mode 100644
index 0000000..ae48b55
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/TrainingImporter.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch.ranking;
+
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * Supports the ability to importing training set into Elasticsearch
+ */
+public class TrainingImporter extends MudrodAbstract {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public TrainingImporter(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ es.deleteAllByQuery(props.getProperty(MudrodConstants.ES_INDEX_NAME), "trainingranking", QueryBuilders.matchAllQuery());
+ addMapping();
+ }
+
+ /**
+ * Method of adding mapping to traning set type
+ */
+ public void addMapping() {
+ XContentBuilder Mapping;
+ try {
+ Mapping = jsonBuilder().startObject().startObject("trainingranking").startObject("properties").startObject("query").field("type", "string").field("index", "not_analyzed").endObject()
+ .startObject("dataID").field("type", "string").field("index", "not_analyzed").endObject().startObject("label").field("type", "string").field("index", "not_analyzed").endObject().endObject()
+ .endObject().endObject();
+
+ es.getClient().admin().indices().preparePutMapping(props.getProperty("indexName")).setType("trainingranking").setSource(Mapping).execute().actionGet();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method of importing training set in to Elasticsearch
+ *
+ * @param dataFolder the path to the traing set
+ * @throws IOException IOException
+ */
+ public void importTrainingSet(String dataFolder) throws IOException {
+ es.createBulkProcessor();
+
+ File[] files = new File(dataFolder).listFiles();
+ for (File file : files) {
+ BufferedReader br = new BufferedReader(new FileReader(file.getAbsolutePath()));
+ br.readLine();
+ String line = br.readLine();
+ while (line != null) {
+ String[] list = line.split(",");
+ String query = file.getName().replace(".csv", "");
+ if (list.length > 0) {
+ IndexRequest ir = new IndexRequest(props.getProperty("indexName"), "trainingranking")
+ .source(jsonBuilder().startObject().field("query", query).field("dataID", list[0]).field("label", list[list.length - 1]).endObject());
+ es.getBulkProcessor().add(ir);
+ }
+ line = br.readLine();
+ }
+ br.close();
+ }
+ es.destroyBulkProcessor();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/package-info.java
new file mode 100644
index 0000000..205e7a7
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/ranking/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes classes for importing training data, ML models,
+ * generating input data for RankSVM, and evaluating ranking results
+ */
+package gov.nasa.jpl.mudrod.ssearch.ranking;
\ No newline at end of file
[03/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/bootstrap.min.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/bootstrap.min.js b/web/META-INF/resources/js/libs/bootstrap.min.js
new file mode 100755
index 0000000..1a6258e
--- /dev/null
+++ b/web/META-INF/resources/js/libs/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.0.3 (http://getbootstrap.com)
+ * Copyright 2013 Twitter, Inc.
+ * Licensed under http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert"
)),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]'),b
=!0;if(a.length){var c=this.$element.find("input");"radio"===c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?b=!1:a.find(".active").removeClass("active")),b&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}b&&this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.
options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this
.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid.bs.carousel",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeC
lass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid.bs.carousel")},0)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid.bs.carousel")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data(
)),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.remov
eClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTra
nsitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function
(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled
")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.load(this
.options.remote)};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show(),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&
!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.rem
ove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal
",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigg
er:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefau
lts();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade")
;var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a
,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transitio
n&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeo
f c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tool
tip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getConte
nt=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.of
fsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarge
t=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.
find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [d
ata-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unp
in&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery);
\ No newline at end of file
[09/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/HybridRecomDatasetsResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/HybridRecomDatasetsResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/HybridRecomDatasetsResource.java
new file mode 100644
index 0000000..7ffc040
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/HybridRecomDatasetsResource.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.recommendation;
+
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import gov.nasa.jpl.mudrod.recommendation.structure.HybridRecommendation;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * A hybrid recommendation resource for datasets.
+ */
+@Path("/hrecommendation")
+public class HybridRecomDatasetsResource {
+
+ private MudrodEngine mEngine;
+
+ public HybridRecomDatasetsResource(@Context ServletContext sc) {
+ this.mEngine = (MudrodEngine) sc.getAttribute("MudrodInstance");
+ }
+
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD Hybrid Recommendation Datasets Resource: running correctly...</h1>").build();
+ }
+
+ @GET
+ @Path("/search")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response hybridRecommendation(@QueryParam("shortname") String shortName) {
+ JsonObject json = new JsonObject();
+ if (shortName != null) {
+ HybridRecommendation recom = new HybridRecommendation(mEngine.getConfig(), mEngine.getESDriver(), null);
+ json = new JsonObject();
+ json.add("HybridRecommendationData", recom.getRecomDataInJson(shortName, 10));
+ }
+ return Response.ok(json.toString(), MediaType.APPLICATION_JSON).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/RecomDatasetsResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/RecomDatasetsResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/RecomDatasetsResource.java
new file mode 100644
index 0000000..75e043c
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/RecomDatasetsResource.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.recommendation;
+
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import gov.nasa.jpl.mudrod.recommendation.structure.RecomData;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+;
+
+/**
+ * A Dataset recommendation resource.
+ */
+@Path("/recommendation")
+public class RecomDatasetsResource {
+
+ private MudrodEngine mEngine;
+
+ public RecomDatasetsResource(@Context ServletContext sc) {
+ this.mEngine = (MudrodEngine) sc.getAttribute("MudrodInstance");
+ }
+
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD Recommendation Datasets Resource: running correctly...</h1>").build();
+ }
+
+ @PUT
+ @Path("{shortname}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response hybridRecommendation(@PathParam("shortname") String shortName) {
+ JsonObject json = new JsonObject();
+ if (shortName != null) {
+ RecomData recom = new RecomData(mEngine.getConfig(), mEngine.getESDriver(), null);
+ json = new JsonObject();
+ json.add("RecommendationData", recom.getRecomDataInJson(shortName, 10));
+ }
+ return Response.ok(json.toString(), MediaType.APPLICATION_JSON).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/package-info.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/package-info.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/package-info.java
new file mode 100644
index 0000000..2ac9330
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/recommendation/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Mudrod recommendation resources.
+ */
+package gov.nasa.jpl.mudrod.services.recommendation;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java
new file mode 100644
index 0000000..ce20569
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchDatasetDetailResource.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.search;
+
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * A Dataset Detail Search Resource
+ */
+@Path("/datasetdetail")
+public class SearchDatasetDetailResource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SearchDatasetDetailResource.class);
+ private MudrodEngine mEngine;
+
+ public SearchDatasetDetailResource(@Context ServletContext sc) {
+ this.mEngine = (MudrodEngine) sc.getAttribute("MudrodInstance");
+ }
+
+ /**
+ * A simple health status checker for this resource.
+ *
+ * @return a static html response if the service is running correctly.
+ */
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD Dataset Detail Search Resource: running correctly...</h1>").build();
+ }
+
+ @GET
+ @Path("/search")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response searchDatasetDetail(@QueryParam("shortname") String shortName) {
+ Properties config = mEngine.getConfig();
+ String dataDetailJson = null;
+ try {
+ String query = "Dataset-ShortName:\"" + shortName + "\"";
+ dataDetailJson = mEngine.getESDriver().searchByQuery(config.getProperty(MudrodConstants.ES_INDEX_NAME), config.getProperty(MudrodConstants.RAW_METADATA_TYPE), query, true);
+ } catch (InterruptedException | ExecutionException | IOException e) {
+ LOG.error("Error whilst searching for a Dataset-ShortName: ", e);
+ }
+ LOG.info("Response received: {}", dataDetailJson);
+ return Response.ok(dataDetailJson, MediaType.APPLICATION_JSON).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchMetadataResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchMetadataResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchMetadataResource.java
new file mode 100644
index 0000000..b9dc501
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchMetadataResource.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.search;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import gov.nasa.jpl.mudrod.ssearch.Ranker;
+import gov.nasa.jpl.mudrod.ssearch.Searcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Properties;
+
+/**
+ * A Mudrod Metadata Search Resource
+ */
+@Path("/metadata")
+public class SearchMetadataResource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SearchMetadataResource.class);
+
+ private MudrodEngine mEngine;
+ private Searcher searcher;
+ private Ranker ranker;
+
+ public SearchMetadataResource(@Context ServletContext sc) {
+ this.mEngine = (MudrodEngine) sc.getAttribute("MudrodInstance");
+ this.searcher = (Searcher) sc.getAttribute("MudrodSearcher");
+ this.ranker = (Ranker) sc.getAttribute("MudrodRanker");
+ }
+
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD Metadata Search Resource: running correctly...</h1>").build();
+ }
+
+ @GET
+ @Path("/search")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response searchMetadata(@QueryParam("query") String query, @QueryParam("operator") String operator, @QueryParam("rankoption") String rankoption) {
+ Properties config = mEngine.getConfig();
+ String fileList = searcher
+ .ssearch(config.getProperty(MudrodConstants.ES_INDEX_NAME), config.getProperty(MudrodConstants.RAW_METADATA_TYPE), query, operator, //please replace it with and, or, phrase
+ rankoption, ranker);
+ Gson gson = new GsonBuilder().create();
+ String json = gson.toJson(gson.fromJson(fileList, JsonObject.class));
+ LOG.debug("Response received: {}", json);
+ return Response.ok(json, MediaType.APPLICATION_JSON).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchVocabResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchVocabResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchVocabResource.java
new file mode 100644
index 0000000..ab4c661
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SearchVocabResource.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.search;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.integration.LinkageIntegration;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * A Mudrod Search Vocabulary Resource
+ */
+@Path("/vocabulary")
+public class SearchVocabResource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SearchMetadataResource.class);
+
+ private MudrodEngine mEngine;
+
+ public SearchVocabResource(@Context ServletContext sc) {
+ this.mEngine = (MudrodEngine) sc.getAttribute("MudrodInstance");
+ }
+
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD Vocabulary Search Resource: running correctly...</h1>").build();
+ }
+
+ @GET
+ @Path("/search")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response searchVocabulary(@QueryParam("query") String concept) {
+ JsonObject json = new JsonObject();
+ if (concept != null) {
+ LinkageIntegration li = new LinkageIntegration(mEngine.getConfig(), mEngine.getESDriver(), null);
+ json = new JsonObject();
+ json.add("graph", li.getIngeratedListInJson(concept));
+ }
+ LOG.info("Response received: {}", json);
+ return Response.ok(new Gson().toJson(json), MediaType.APPLICATION_JSON).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SessionDetailResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SessionDetailResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SessionDetailResource.java
new file mode 100644
index 0000000..fcbe3c6
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/SessionDetailResource.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.search;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import gov.nasa.jpl.mudrod.weblog.structure.Session;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Servlet implementation class SessionDetail
+ */
+@Path("/sessiondetail")
+public class SessionDetailResource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SessionDetailResource.class);
+ private MudrodEngine mEngine;
+
+ /**
+ * Constructor
+ *
+ * @param sc an instantiated {@link javax.servlet.ServletContext}
+ */
+ public SessionDetailResource(@Context ServletContext sc) {
+ this.mEngine = (MudrodEngine) sc.getAttribute("MudrodInstance");
+ }
+
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD Session Detail Search Resource: running correctly...</h1>").build();
+ }
+
+ @POST
+ @Path("{CleanupType}-{SessionID}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ protected Response searchSessionDetail(@PathParam("CleanupType") String cleanupType, @PathParam("SessionID") String sessionID) {
+
+ JsonObject json = new JsonObject();
+ if (sessionID != null) {
+ Session session = new Session(mEngine.getConfig(), mEngine.getESDriver());
+ json = session.getSessionDetail(mEngine.getConfig().getProperty(MudrodConstants.ES_INDEX_NAME, "mudrod"), cleanupType, sessionID);
+ }
+ LOG.info("Response received: {}", json);
+ return Response.ok(new Gson().toJson(json), MediaType.APPLICATION_JSON).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/search/package-info.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/search/package-info.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/package-info.java
new file mode 100644
index 0000000..abcfb07
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/search/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Mudrod search-related resources.
+ */
+package gov.nasa.jpl.mudrod.services.search;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/service/src/main/resources/log4j.properties b/service/src/main/resources/log4j.properties
new file mode 100644
index 0000000..482a580
--- /dev/null
+++ b/service/src/main/resources/log4j.properties
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0 Unless
+#
+# required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS"
+# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language
+# governing permissions and limitations under the License.
+# Define some default values that can be overridden by system properties
+# Logging Threshold
+mudrod.root.logger=INFO,DRFA, stdout
+mudrod.log.dir=.
+mudrod.log.file=mudrod_service.log
+log4j.threshhold=ALL
+# RootLogger - DailyRollingFileAppender
+log4j.rootLogger=${mudrod.root.logger}
+#special logging requirements for some commandline tools
+log4j.logger.MudrodEngine=INFO,cmdstdout
+#
+# Daily Rolling File Appender
+#
+log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.DRFA.File=${mudrod.log.dir}/${mudrod.log.file}
+# Rollver at midnight
+log4j.appender.DRFA.DatePattern=.yyyy-MM-dd
+# 30-day backup
+#log4j.appender.DRFA.MaxBackupIndex=30
+log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout
+# Pattern format: Date LogLevel LoggerName LogMessage
+log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} - %m%n
+# Debugging Pattern format: Date LogLevel LoggerName (FileName:MethodName:LineNo) LogMessage
+#log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+#
+# stdout
+# Add *stdout* to rootlogger above if you want to use this
+#
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+#
+# plain layout used for commandline tools to output to console
+#
+log4j.appender.cmdstdout=org.apache.log4j.ConsoleAppender
+log4j.appender.cmdstdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.cmdstdout.layout.ConversionPattern=%m%n
+#
+# Rolling File Appender
+#
+#log4j.appender.RFA=org.apache.log4j.RollingFileAppender
+#log4j.appender.RFA.File=${hadoop.log.dir}/${hadoop.log.file}
+# Logfile size and and 30-day backups
+#log4j.appender.RFA.MaxFileSize=1MB
+#log4j.appender.RFA.MaxBackupIndex=30
+#log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} - %m%n
+#log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n
+# Custom Logging levels
+log4j.logger.akka=WARN
+log4j.logger.org.apache=WARN
+log4j.logger.gov.nasa.jpl.mudrod=INFO
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/webapp/META-INF/context.xml
----------------------------------------------------------------------
diff --git a/service/src/main/webapp/META-INF/context.xml b/service/src/main/webapp/META-INF/context.xml
new file mode 100644
index 0000000..1fc4b99
--- /dev/null
+++ b/service/src/main/webapp/META-INF/context.xml
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE.txt file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+-->
+<Context path="/mudrod-service">
+
+</Context>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/service/src/main/webapp/WEB-INF/web.xml b/service/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..38bb88e
--- /dev/null
+++ b/service/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <display-name>MUDROD</display-name>
+ <servlet>
+ <servlet-name>CXFServlet</servlet-name>
+ <servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
+ </servlet-class>
+ <init-param>
+ <param-name>jaxrs.serviceClasses</param-name>
+ <param-value>
+ gov.nasa.jpl.mudrod.services.autocomplete.AutoCompleteResource,
+ gov.nasa.jpl.mudrod.services.search.SearchDatasetDetailResource,
+ gov.nasa.jpl.mudrod.services.recommendation.HybridRecomDatasetsResource,
+ gov.nasa.jpl.mudrod.services.recommendation.RecomDatasetsResource,
+ gov.nasa.jpl.mudrod.services.search.SearchMetadataResource,
+ gov.nasa.jpl.mudrod.services.search.SearchVocabResource,
+ gov.nasa.jpl.mudrod.services.search.SessionDetailResource,
+ gov.nasa.jpl.mudrod.services.ontology.OntologyResource,
+ </param-value>
+ </init-param>
+ <init-param>
+ <param-name>jaxrs.providers</param-name>
+ <param-value>gov.nasa.jpl.mudrod.services.DefaultExceptionMapper</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <listener>
+ <listener-class>gov.nasa.jpl.mudrod.services.MudrodContextListener
+ </listener-class>
+ </listener>
+
+ <servlet-mapping>
+ <servlet-name>CXFServlet</servlet-name>
+ <url-pattern>/services/*</url-pattern>
+ </servlet-mapping>
+
+</web-app>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/sonar-project.properties
----------------------------------------------------------------------
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000..8b8e884
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,25 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# must be unique in a given SonarQube instance
+sonar.projectKey=gov.nasa.jpl.mudrod:mudrod-parent
+# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
+#sonar.projectName=Mudrod :: Parent
+#sonar.projectVersion=0.0.1-SNAPSHOT
+
+# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
+# This property is optional if sonar.modules is set.
+sonar.sources=.
+
+# Encoding of the source code. Default is default system encoding
+#sonar.sourceEncoding=UTF-8
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/.classpath
----------------------------------------------------------------------
diff --git a/web/.classpath b/web/.classpath
new file mode 100644
index 0000000..93e3cde
--- /dev/null
+++ b/web/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="META-INF" output="target/classes/META-INF" excluding="**/*.java"/>
+ <classpathentry kind="output" path="target/classes"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+</classpath>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/.project
----------------------------------------------------------------------
diff --git a/web/.project b/web/.project
new file mode 100644
index 0000000..c7705cb
--- /dev/null
+++ b/web/.project
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>mudrod-web</name>
+ <comment>MUDROD: Mining and Utilizing Dataset Relevancy from
+ Oceanographic Datasets
+ to Improve Data Discovery and Access. MUDROD is a semantic discovery and
+ search project
+ funded by NASA AIST (NNX15AM85G). NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment>
+ <projects/>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/web/.settings/org.eclipse.jdt.core.prefs b/web/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..45a6e0e
--- /dev/null
+++ b/web/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.5
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/web/.settings/org.eclipse.m2e.core.prefs b/web/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/web/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/.settings/org.eclipse.wst.common.component
----------------------------------------------------------------------
diff --git a/web/.settings/org.eclipse.wst.common.component b/web/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..0da6e11
--- /dev/null
+++ b/web/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="mudrod-web">
+ <wb-resource deploy-path="/" source-path="/META-INF"/>
+ <wb-resource deploy-path="/" source-path="/src/main/java"/>
+ </wb-module>
+</project-modules>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/.settings/org.eclipse.wst.common.project.facet.core.xml
----------------------------------------------------------------------
diff --git a/web/.settings/org.eclipse.wst.common.project.facet.core.xml b/web/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..a1f6907
--- /dev/null
+++ b/web/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="java" version="1.5"/>
+ <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/css/footer.css
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/css/footer.css b/web/META-INF/resources/css/footer.css
new file mode 100644
index 0000000..7e0732e
--- /dev/null
+++ b/web/META-INF/resources/css/footer.css
@@ -0,0 +1,19 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+express or implied. See the License for the specific language
+governing permissions and limitations under the License.
+*/
+
+/*
+
+This file can be used to provide customized css for the customized footer provided in partials/footer.html for the MUDROD website. It is currently left empty.
+
+*/
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/css/index.css
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/css/index.css b/web/META-INF/resources/css/index.css
new file mode 100644
index 0000000..8512cc0
--- /dev/null
+++ b/web/META-INF/resources/css/index.css
@@ -0,0 +1,445 @@
+html, body {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+}
+
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ background-color: black;
+}
+
+h1, h2, h3, p {
+ margin: 0 0 .2em 0;
+}
+
+.toolbar {
+ background-color: #2276ac;
+ height: 60px;
+}
+
+article, aside, details, figcaption, figure, header, hgroup, main, menu, nav, section, summary {
+ display: block;
+}
+
+header h1 {
+ margin: 0;
+}
+
+.toolbar a:link, .toolbar a:visited {
+ color: #fff;
+}
+
+header h1 > a {
+ margin-top: 10px;
+}
+
+a {
+ color: #428bca;
+ text-decoration: none;
+ background-color: transparent;
+}
+
+a:focus, a:hover {
+ text-decoration: none;
+}
+
+b, strong {
+ font-weight: bold;
+}
+
+a:link, a:visited {
+ color: #2980b9;
+}
+
+.view-area-fixed {
+ width: 100%;
+ padding-top: 1em;
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-position: 0 0;
+ background-image: url('../images/OceanWave.jpg');
+ background-color: transparent;
+ background-attachment: fixed;
+}
+
+.view-area-scroll {
+ width: 100%;
+ height: 800px;
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-position: 0 0;
+ background-image: url('../images/OceanWave.jpg');
+ background-color: transparent;
+ background-attachment: scroll;
+}
+
+.landing-dialog {
+ flex: 1;
+ padding: 6em;
+ width: 80%;
+ margin: 15em auto 15em;
+ color: #fff;
+ border-radius: 6px;
+ box-shadow: 0 0 20px 0 rgba(17, 17, 17, 0.7);
+}
+
+.landing-dialog-header, .noscript, .old-ie {
+ padding: 1em 1.5em;
+}
+
+.landing-dialog-header h2, .noscript h2, .old-ie h2 {
+ font-weight: normal;
+ margin: 0 0 .2em 0;
+ font-size: 2.2em;
+ text-shadow: 1px 1px 1px #111;
+}
+
+.searchBox {
+ height: 100px;
+ padding: .5em 0;
+ background: transparent;
+ margin-left: .5em;
+}
+
+.panel-title {
+ font-size: 1.5em;
+}
+
+.rankoption {
+ background-color: white;
+ color: black;
+ float: right;
+}
+
+.autocomplete {
+ overflow-y: auto;
+ height: 15em;
+ color: black;
+}
+
+.toolbar .form {
+ display: inline-block;
+}
+
+.toolbar p {
+ margin: 0;
+}
+
+.tt-input {
+ vertical-align: baseline !important;
+}
+
+input[type="text"], input[type="search"], input[type="password"], textarea {
+ padding: 5px;
+ outline: none;
+ min-width: 150px;
+ color: #424242;
+}
+
+.toolbar .tt-query, .toolbar .tt-hint, .toolbar .tt-input {
+ padding: 11px;
+ margin: 2px 0 0 20px;
+ width: 540px;
+ border: 1px solid #236d9e;
+ border-radius: 3px;
+ box-shadow: inset 0 1px 5px 1px rgba(0, 0, 0, 0.2);
+}
+
+.dropdown {
+ display: inline-block;
+ position: relative;
+}
+
+.button, input[type="button"], input[type="reset"], input[type="submit"], button {
+ text-decoration: none;
+ display: inline-block;
+ padding: 8px 12px;
+ border-radius: 3px;
+ outline: none;
+ color: #fff;
+}
+
+.toolbar .button, .toolbar input[type="button"], .toolbar input[type="reset"], .toolbar input[type="submit"] {
+ border: 1px solid #2c3e50;
+ background: #1a5981;
+ color: #fff;
+ text-shadow: none;
+}
+
+.btn-search, .btn-search:hover, .btn-search:focus, .btn-search:active, .btn-search.active, .open .dropdown-toggle.btn-search, .btn-search:active:focus, .btn-search:active:hover, .btn-search.active:hover, .btn-search.active:focus {
+ background-color: #1a5981;
+ border-color: #1a5981;
+ color: #FFFFFF;
+ padding: 9px 12px 9px 12px;
+ font-size: 1.3em;
+}
+
+.checkbox-inline, .radio-inline {
+ position: relative;
+ display: inline-block;
+ padding-left: 20px;
+ margin-bottom: 0;
+ font-weight: 400;
+ vertical-align: middle;
+ cursor: pointer;
+}
+
+.radio {
+ padding-left: 20px;
+}
+
+.radio.radio-inline {
+ margin-top: 0;
+}
+
+.radio input[type="radio"] {
+ opacity: 0;
+ z-index: 1;
+}
+
+.radio label {
+ display: inline-block;
+ vertical-align: middle;
+ position: relative;
+ padding-left: 5px;
+}
+
+.radio label::before {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ width: 17px;
+ height: 17px;
+ left: 0;
+ margin-left: -20px;
+ border: 1px solid #cccccc;
+ border-radius: 50%;
+ background-color: #fff;
+ -webkit-transition: border 0.15s ease-in-out;
+ -o-transition: border 0.15s ease-in-out;
+ transition: border 0.15s ease-in-out;
+}
+
+.radio label::after {
+ display: inline-block;
+ position: absolute;
+ content: " ";
+ width: 11px;
+ height: 11px;
+ left: 3px;
+ top: 3px;
+ margin-left: -20px;
+ border-radius: 50%;
+ background-color: #5bc0de;
+ -webkit-transform: scale(0, 0);
+ -ms-transform: scale(0, 0);
+ -o-transform: scale(0, 0);
+ transform: scale(0, 0);
+ -webkit-transition: -webkit-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+ -moz-transition: -moz-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+ -o-transition: -o-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+ transition: transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
+}
+
+.radio-info input[type="radio"]:checked + label::before {
+ border-color: #5bc0de;
+}
+
+.radio-info input[type="radio"] + label::after {
+ background-color: #5bc0de;
+}
+
+.radio input[type="radio"]:checked + label::after {
+ -webkit-transform: scale(1, 1);
+ -ms-transform: scale(1, 1);
+ -o-transform: scale(1, 1);
+ transform: scale(1, 1);
+}
+
+.radio-info input[type="radio"]:checked + label::after {
+ background-color: #5bc0de;
+}
+
+a {
+ cursor: pointer;
+}
+
+.sidenav {
+ height: 100%;
+ transition: 0.5s;
+}
+
+.sidenav a {
+ padding: 8px 8px 8px 5px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ text-decoration: none;
+ color: #2980b9;
+ display: block;
+ transition: 0.3s;
+}
+
+.sidenav a:hover, .offcanvas a:focus {
+ color: #8ab9e7;
+}
+
+.sidenav h4 a {
+ padding: 2px 8px 0 10px;
+ color: white;
+}
+
+.sidenav .learn-more a {
+ font-size: 0.9em;
+ font-style: italic;
+ text-align: center;
+}
+
+.no-gutter > [class*='col-'] {
+ padding-right: 5px;
+ padding-left: 5px;
+}
+
+.content-holder .post-holder {
+ padding-top: 0;
+}
+
+.post-holder .panel-body {
+ overflow-x: auto;
+}
+
+.post-holder .post {
+ background-color: #FFFFFF;
+ border-bottom: 1px solid #c3c3c3;
+ padding: 14px 16px;
+}
+
+.content-holder .heading-t3 {
+ height: 42px;
+ margin-bottom: 16px;
+}
+
+.content-holder .heading-t3, .heading-t3 {
+ background: #738dca;
+ padding: 0 18px 0 16px;
+ overflow: hidden;
+}
+
+.content-holder .heading-t3 .title {
+ display: inline-block;
+ vertical-align: top;
+ padding: 6px 8px;
+}
+
+.list-related-searches {
+ text-align: left;
+ border-bottom: 2px solid #069;
+ padding-bottom: 10px;
+ margin-bottom: 6px;
+ list-style: none;
+}
+
+.heading-t4 {
+ background: #fff;
+ border-top: 6px solid #738dca;
+ border-bottom: 6px solid #738dca;
+ overflow: hidden;
+ font-size: 1.2em;
+}
+
+.search-form {
+ position: relative;
+ margin-right: 20px;
+ margin-left: 20px;
+}
+
+.form-group {
+ margin-bottom: 15px;
+}
+
+.search-form button {
+ position: absolute;
+ right: 10px;
+ top: 3px;
+ border: 0;
+ padding: 0;
+ background: none;
+}
+
+.ico-search {
+ display: inline-block;
+ background: url(../images/sprite.png) no-repeat 0 0;
+ width: 17px;
+ height: 23px;
+}
+
+.search-form #query {
+ height: 28px;
+ border: 2px solid #39c;
+ border-radius: 14px;
+ line-height: 20px;
+ padding: 1px 35px 1px 15px;
+ width: 100%;
+ background: #f3f3f3;
+ box-shadow: none !important;
+}
+
+.searchOption {
+ color: white;
+}
+
+li {
+ cursor: default;
+}
+
+.search-ul {
+ position: absolute;
+ z-index: 1000;
+ min-width: 195px;
+ width: 20%;
+ list-style: none;
+ text-align: left;
+}
+
+#spinner {
+ text-align: center;
+}
+
+#spinner img{
+ height: 10em;
+}
+
+/* button recolor */
+.nav-pills > li.active > a, .btn-primary {
+ background-color: #069;
+ border-color: #069;
+ border-radius: 4px;
+}
+
+.mudrod-navbar {
+ margin-bottom: 0;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.mudrod-navbar #searchForm {
+ width: 50%;
+}
+
+.mudrod-navbar #searchForm .form-group {
+ width: 100%;
+}
+
+.mudrod-navbar #searchForm .form-group input {
+ width: 45%;
+}
+
+.mudrod-navbar .nav-item {
+ margin: 1em 0 0 1em;
+}
+
+.mudrod-footer {
+ color: white;
+ padding-left: 2em;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/css/main-header.css
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/css/main-header.css b/web/META-INF/resources/css/main-header.css
new file mode 100644
index 0000000..8494e09
--- /dev/null
+++ b/web/META-INF/resources/css/main-header.css
@@ -0,0 +1,19 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+express or implied. See the License for the specific language
+governing permissions and limitations under the License.
+*/
+
+/*
+
+This file can be used to provide customized css for the customized header provided in partials/main-header.html for the MUDROD website. It is currently left empty.
+
+*/
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/fonts/glyphicons-halflings-regular.eot
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/fonts/glyphicons-halflings-regular.eot b/web/META-INF/resources/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..b93a495
Binary files /dev/null and b/web/META-INF/resources/fonts/glyphicons-halflings-regular.eot differ
[18/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java
new file mode 100644
index 0000000..55ca51d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/LocalOntology.java
@@ -0,0 +1,392 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
+
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+
+import org.apache.jena.ontology.Individual;
+import org.apache.jena.ontology.OntClass;
+import org.apache.jena.ontology.OntModel;
+import org.apache.jena.ontology.OntModelSpec;
+import org.apache.jena.ontology.OntResource;
+import org.apache.jena.ontology.Restriction;
+import org.apache.jena.rdf.model.AnonId;
+import org.apache.jena.rdf.model.Literal;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.shared.PrefixMapping;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.PrintStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The LocalOntology implementation enables us to work with Ontology files
+ * whcih are cached locally and available on the runtime classpath e.g.
+ * in <code>src/main/resource/ontology/...</code>.
+ * From here we can test and iterate on how use of ontology can enhance search.
+ */
+public class LocalOntology implements Ontology {
+
+ public static final Logger LOG = LoggerFactory.getLogger(LocalOntology.class);
+
+ public static final String DELIMITER_SEARCHTERM = " ";
+
+ private Map<Object, Object> searchTerms = new HashMap<>();
+ private static OntologyParser parser;
+ private static OntModel ontologyModel;
+ private Ontology ontology;
+ private static Map<AnonId, String> mAnonIDs = new HashMap<>();
+ private static int mAnonCount = 0;
+ private List<String> ontArrayList;
+
+ public LocalOntology() {
+ //only initialize all the static variables
+ //if first time called to this ontology constructor
+ if (ontology == null) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info("Creating new ontology");
+ }
+ parser = new OwlParser();
+ ontology = this;
+ }
+ if (ontologyModel == null)
+ ontologyModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, null);
+ load();
+ }
+
+ /**
+ * Static accessor for {@link LocalOntology}
+ * instance implementation defined within <code>config.xml</code>.
+ *
+ * @return a {@link LocalOntology}
+ */
+ public Ontology getInstance() {
+ if (ontology == null) {
+ ontology = new LocalOntology();
+ }
+ return ontology;
+ }
+
+ /**
+ * Load the default <i>sweetAll.owl</i> ontology
+ * from <a href="https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl">
+ * https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl</a>
+ */
+ @Override
+ public void load() {
+ URL ontURL = null;
+ try {
+ ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl");
+ //ontURL = new URL("https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/reprDataProduct.owl");
+ } catch (MalformedURLException e) {
+ LOG.error("Error when attempting to create URL resource: ", e);
+ }
+ ontArrayList = new ArrayList<>();
+ try {
+ ontArrayList.add(ontURL.toURI().toString());
+ } catch (URISyntaxException e) {
+ LOG.error("Error in URL syntax, please check your Ontology resource: ", e);
+ }
+ if (!ontArrayList.isEmpty()) {
+ load(ontArrayList.stream().toArray(String[]::new));
+ }
+ }
+
+ /**
+ * Load a string array of local URIs which refernece .owl files.
+ */
+ @Override
+ public void load(String[] urls) {
+ for (int i = 0; i < urls.length; i++) {
+ String url = urls[i].trim();
+ if (!"".equals(url))
+ if (LOG.isInfoEnabled()) {
+ LOG.info("Reading and processing {}", url);
+ }
+ load(ontologyModel, url);
+ }
+ parser.parse(ontology, ontologyModel);
+ }
+
+ private void load(Object m, String url) {
+ try {
+ ((OntModel) m).read(url, null, null);
+ LOG.info("Successfully processed {}", url);
+ } catch (Exception e) {
+ LOG.error("Failed whilst attempting to read ontology {}: Error: ", url, e);
+ }
+ }
+
+ /**
+ * Get the {@link gov.nasa.jpl.mudrod.ontology.process.OntologyParser}
+ * implementation being used to process the input ontology resources.
+ * @return an {@link gov.nasa.jpl.mudrod.ontology.process.OntologyParser} implementation
+ */
+ public OntologyParser getParser() {
+ if (parser == null) {
+ parser = new OwlParser();
+ }
+ return parser;
+ }
+
+ /**
+ * Return the {@link org.apache.jena.ontology.OntModel} instance
+ * which created from input ontology resources.
+ * @return a constructed {@link org.apache.jena.ontology.OntModel}
+ */
+ public static OntModel getModel() {
+ return ontologyModel;
+ }
+
+ /**
+ * Return the loaded Ontology resources.
+ * @return a {@link java.util.List} of resources.
+ */
+ public List<String> getLoadedOntologyResources() {
+ if (ontArrayList != null) {
+ return ontArrayList;
+ } else {
+ return new ArrayList<>();
+ }
+ }
+ /**
+ * Not yet implemented.
+ */
+ @Override
+ public void merge(Ontology o) {
+ // not yet implemented
+ }
+
+ /**
+ * Retrieve all subclasses of entity(ies) hashed to searchTerm
+ * @param entitySearchTerm a query (keywords) for which to obtain
+ * subclasses.
+ * @return an {@link java.util.Iterator} containing the subclass as Strings.
+ */
+ @Override
+ public Iterator<String> subclasses(String entitySearchTerm) {
+ Map<OntResource, String> classMap = retrieve(entitySearchTerm);
+ Map<String, String> subclasses = new HashMap<>();
+
+ Iterator<OntResource> iter = classMap.keySet().iterator();
+ while (iter.hasNext()) {
+ OntResource resource = iter.next();
+
+ if (resource instanceof OntClass) {
+ //get subclasses N.B. we only get direct sub-classes e.g. direct children
+ //it is possible for us to navigate the entire class tree if we wish, we simply
+ //need to pass the .listSubClasses(true) boolean parameter.
+ for (Iterator<?> i = ((OntClass) resource).listSubClasses(); i.hasNext();) {
+ OntResource subclass = (OntResource) i.next();
+ for (Iterator<?> j = subclass.listLabels(null); j.hasNext();) {
+ Literal l = (Literal) j.next();
+ subclasses.put(l.toString(), "1");
+ }
+ }
+ //get individuals
+ for (Iterator<?> i = ((OntClass) resource).listInstances(); i.hasNext(); ) {
+ OntResource subclass = (OntResource) i.next();
+ for (Iterator<?> j = subclass.listLabels(null); j.hasNext();) {
+ Literal l = (Literal) j.next();
+ subclasses.put(l.toString(), "1");
+ }
+ }
+ } else if (resource instanceof Individual) {
+ for (Iterator<?> i = resource.listSameAs(); i.hasNext();) {
+ OntResource subclass = (OntResource) i.next();
+ for (Iterator<?> j = subclass.listLabels(null); j.hasNext();) {
+ Literal l = (Literal) j.next();
+ subclasses.put(l.toString(), "1");
+ }
+ }
+ }
+ }
+ return subclasses.keySet().iterator();
+ }
+
+ /**
+ * Retreives synonyms for an given phrase if the phrase
+ * is present in the ontology
+ * @param queryKeyPhrase an input string representing a phrase
+ * for which we wish to obtain synonyms.
+ * @return an {@link java.util.Iterator} containing synonyms string tokens
+ * or an empty if no synonyms exist for the given queryKeyPhrase.
+ */
+ @Override
+ public Iterator synonyms(String queryKeyPhrase) {
+
+ Map<?, ?> classMap = retrieve(queryKeyPhrase);
+
+ Map<Object, Object> synonyms = new HashMap<>();
+
+ Iterator<?> iter = classMap.keySet().iterator();
+ while (iter.hasNext()) {
+ OntResource resource = (OntResource) iter.next();
+
+ //listLabels
+ for (Iterator<?> i = resource.listLabels(null); i.hasNext();) {
+ Literal l = (Literal) i.next();
+ synonyms.put(l.toString(), "1");
+ }
+
+ if (resource instanceof Individual) {
+ //get all individuals same as this one
+ for (Iterator<?> i = resource.listSameAs(); i.hasNext();) {
+ Individual individual = (Individual) i.next();
+ //add labels
+ for (Iterator<?> j = individual.listLabels(null); j.hasNext();) {
+ Literal l = (Literal) i.next();
+ synonyms.put(l.toString(), "1");
+ }
+ }
+ } else if (resource instanceof OntClass) {
+ //list equivalent classes
+ for (Iterator<?> i = ((OntClass) resource).listEquivalentClasses(); i.hasNext();) {
+ OntClass equivClass = (OntClass) i.next();
+ //add labels
+ for (Iterator<?> j = equivClass.listLabels(null); j.hasNext();) {
+ Literal l = (Literal) j.next();
+ synonyms.put(l.toString(), "1");
+ }
+ }
+ }
+ }
+
+ return synonyms.keySet().iterator();
+ }
+
+ public void addSearchTerm(String label, OntResource resource) {
+ Map<OntResource, String> m = retrieve(label);
+ if (m == null) {
+ m = new HashMap<>();
+ }
+ m.put(resource, "1");
+ searchTerms.put(label.toLowerCase(), m);
+ }
+
+ /**
+ * A basic lookup function for retrieving keys (phrases or tokens)
+ * from the ontology search terms map. Right now only exact lookups
+ * will retrieve a result... this could be improved by using some
+ * advanced parsing logic... such as Lucene query parser.
+ * @param label the label (phrases or tokens) to retrieve from the
+ * ontology search terms map.
+ * @return an {@link java.util.Map} if there are match(es)
+ * or an empty {@link java.util.HashMap} if there are no
+ * matches.
+ */
+ public Map<OntResource, String> retrieve(String label) {
+ @SuppressWarnings("unchecked")
+ Map<OntResource, String> m = (Map<OntResource, String>) searchTerms.get(label.toLowerCase());
+ if (m == null) {
+ m = new HashMap<>();
+ }
+ return m;
+ }
+
+ protected static void renderHierarchy(PrintStream out, OntClass cls, List<Object> occurs, int depth) {
+ renderClassDescription(out, cls, depth);
+ out.println();
+
+ // recurse to the next level down
+ if (cls.canAs(OntClass.class) && !occurs.contains(cls)) {
+ for (Iterator<?> i = cls.listSubClasses(true); i.hasNext(); ) {
+ OntClass sub = (OntClass) i.next();
+
+ // we push this expression on the occurs list before we recurse
+ occurs.add(cls);
+ renderHierarchy(out, sub, occurs, depth + 1);
+ occurs.remove(cls);
+ }
+ for (Iterator<?> i = cls.listInstances(); i.hasNext(); ) {
+ Individual individual = (Individual) i.next();
+ renderURI(out, individual.getModel(), individual.getURI());
+ out.print(" [");
+ for (Iterator<?> j = individual.listLabels(null); j.hasNext(); ) {
+ out.print(((Literal) j.next()).getString() + ", ");
+ }
+ out.print("] ");
+ out.println();
+ }
+ }
+ }
+
+ public static void renderClassDescription(PrintStream out, OntClass c, int depth) {
+ indent(out, depth);
+
+ if (c.isRestriction()) {
+ renderRestriction(out, (Restriction) c.as(Restriction.class));
+ } else {
+ if (!c.isAnon()) {
+ out.print("Class ");
+ renderURI(out, c.getModel(), c.getURI());
+
+ out.print(c.getLocalName());
+
+ out.print(" [");
+ for (Iterator<?> i = c.listLabels(null); i.hasNext(); ) {
+ out.print(((Literal) i.next()).getString() + ", ");
+ }
+ out.print("] ");
+ } else {
+ renderAnonymous(out, c, "class");
+ }
+ }
+ }
+
+ protected static void renderRestriction(PrintStream out, Restriction r) {
+ if (!r.isAnon()) {
+ out.print("Restriction ");
+ renderURI(out, r.getModel(), r.getURI());
+ } else {
+ renderAnonymous(out, r, "restriction");
+ }
+
+ out.print(" on property ");
+ renderURI(out, r.getModel(), r.getOnProperty().getURI());
+ }
+
+ protected static void renderURI(PrintStream out, PrefixMapping prefixes, String uri) {
+ out.print(prefixes.expandPrefix(uri));
+ }
+
+ protected static void renderAnonymous(PrintStream out, Resource anon, String name) {
+ String anonID = mAnonIDs.get(anon.getId());
+ if (anonID == null) {
+ anonID = "a-" + mAnonCount++;
+ mAnonIDs.put(anon.getId(), anonID);
+ }
+
+ out.print("Anonymous ");
+ out.print(name);
+ out.print(" with ID ");
+ out.print(anonID);
+ }
+
+ protected static void indent(PrintStream out, int depth) {
+ for (int i = 0; i < depth; i++) {
+ out.print(" ");
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyLinkCal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyLinkCal.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyLinkCal.java
new file mode 100644
index 0000000..a68a0cb
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyLinkCal.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.concurrent.ExecutionException;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * Supports ability to parse and process FTP and HTTP log files
+ */
+public class OntologyLinkCal extends DiscoveryStepAbstract {
+
+ public OntologyLinkCal(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ es.deleteAllByQuery(props.getProperty("indexName"), props.getProperty("ontologyLinkageType"), QueryBuilders.matchAllQuery());
+ addSWEETMapping();
+ }
+
+ /**
+ * Method of adding mapping for triples extracted from SWEET
+ */
+ public void addSWEETMapping() {
+ XContentBuilder Mapping;
+ try {
+ Mapping = jsonBuilder().startObject().startObject(props.getProperty("ontologyLinkageType")).startObject("properties").startObject("concept_A").field("type", "string")
+ .field("index", "not_analyzed").endObject().startObject("concept_B").field("type", "string").field("index", "not_analyzed").endObject()
+
+ .endObject().endObject().endObject();
+
+ es.getClient().admin().indices().preparePutMapping(props.getProperty("indexName")).setType(props.getProperty("ontologyLinkageType")).setSource(Mapping).execute().actionGet();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Method of calculating and importing SWEET triples into Elasticsearch
+ */
+ @Override
+ public Object execute() {
+ es.deleteType(props.getProperty("indexName"), props.getProperty("ontologyLinkageType"));
+ es.createBulkProcessor();
+
+ BufferedReader br = null;
+ String line = "";
+ double weight = 0;
+
+ try {
+ br = new BufferedReader(new FileReader(props.getProperty("oceanTriples")));
+ while ((line = br.readLine()) != null) {
+ String[] strList = line.toLowerCase().split(",");
+ if (strList[1].equals("subclassof")) {
+ weight = 0.75;
+ } else {
+ weight = 0.9;
+ }
+
+ IndexRequest ir = new IndexRequest(props.getProperty("indexName"), props.getProperty("ontologyLinkageType")).source(
+ jsonBuilder().startObject().field("concept_A", es.customAnalyzing(props.getProperty("indexName"), strList[2]))
+ .field("concept_B", es.customAnalyzing(props.getProperty("indexName"), strList[0])).field("weight", weight).endObject());
+ es.getBulkProcessor().add(ir);
+
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ es.destroyBulkProcessor();
+ es.refreshIndex();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java
new file mode 100644
index 0000000..eca6252
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OntologyParser.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
+
+import org.apache.jena.ontology.OntClass;
+import org.apache.jena.ontology.OntModel;
+
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+
+import java.util.Iterator;
+
+/**
+ * Interface for specific ontology parsers e.g. .ttl, RDFXML,
+ * etc.
+ */
+public interface OntologyParser {
+
+ /**
+ * An ontology model (RDF graph) to parse for literals.
+ *
+ * @param ont the associated {@link gov.nasa.jpl.mudrod.ontology.Ontology}
+ * implementation processing the ontology operation(s).
+ * @param ontModel the {@link org.apache.jena.ontology.OntModel}
+ */
+ public void parse(Ontology ont, OntModel ontModel);
+
+ /**
+ * An ontology model (RDF graph) for which to obtain an
+ * {@link java.util.Iterator} instance of all root classes.
+ *
+ * @param ontModel the {@link org.apache.jena.ontology.OntModel}
+ * @return an {@link java.util.Iterator} instance containing all root classes.
+ */
+ public Iterator<OntClass> rootClasses(OntModel ontModel);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java
new file mode 100644
index 0000000..e43f04d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/OwlParser.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
+
+import org.apache.jena.ontology.Individual;
+import org.apache.jena.ontology.OntClass;
+import org.apache.jena.ontology.OntModel;
+import org.apache.jena.rdf.model.Literal;
+
+import com.esotericsoftware.minlog.Log;
+
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * {@link gov.nasa.jpl.mudrod.ontology.process.OntologyParser}
+ * implementation for <a href="http://www.w3.org/TR/owl-features/">W3C OWL</a>
+ * files.
+ */
+public class OwlParser implements OntologyParser {
+
+ private Ontology ont;
+ private List<OntClass> roots = new ArrayList<>();
+
+ public OwlParser() {
+ //default constructor
+ }
+
+ /**
+ * Parse OWL ontology files using Apache Jena
+ */
+ @Override
+ public void parse(Ontology ont, OntModel m) {
+ this.ont = ont;
+ for (Iterator<OntClass> i = rootClasses(m); i.hasNext(); ) {
+ OntClass c = i.next();
+
+ //dont deal with anonymous classes
+ if (c.isAnon()) {
+ continue;
+ }
+
+ parseClass(c, new ArrayList<>(), 0);
+ }
+ }
+
+ protected void parseClass(OntClass cls, List<Object> occurs, int depth) {
+ //dont deal with anonymous classes
+ if (cls.isAnon()) {
+ return;
+ }
+
+ //add cls to Ontology searchterms
+ //list labels
+ Iterator<?> labelIter = cls.listLabels(null);
+ //if has no labels
+ if (!labelIter.hasNext()) {
+ //add rdf:ID as a label
+ cls.addLabel(rdfidToLabel(cls.getLocalName()), null);
+ }
+ //reset the label iterator
+ labelIter = cls.listLabels(null);
+
+ while (labelIter.hasNext()) {
+ Literal l = (Literal) labelIter.next();
+ ((LocalOntology) ont).addSearchTerm(l.toString(), cls);
+ }
+
+ // recurse to the next level down
+ if (cls.canAs(OntClass.class) && !occurs.contains(cls)) {
+ //list subclasses
+ for (Iterator<?> i = cls.listSubClasses(true); i.hasNext(); ) {
+ OntClass sub = (OntClass) i.next();
+
+ // we push this expression on the occurs list before we recurse
+ occurs.add(cls);
+ parseClass(sub, occurs, depth + 1);
+ occurs.remove(cls);
+ }
+
+ //list instances
+ for (Iterator<?> i = cls.listInstances(); i.hasNext(); ) {
+ //add search terms for each instance
+
+ //list labels
+ Individual individual = (Individual) i.next();
+ for (Iterator<?> j = individual.listLabels(null); j.hasNext(); ) {
+ Literal l = (Literal) j.next();
+ ((LocalOntology) ont).addSearchTerm(l.toString(), individual);
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses out all root classes of the given
+ * {@link org.apache.jena.ontology.OntModel}
+ * @param m the {@link org.apache.jena.ontology.OntModel} we wish to obtain
+ * all root classes for.
+ * @return an {@link java.util.Iterator} of {@link org.apache.jena.ontology.OntClass}
+ * elements representing all root classes.
+ */
+ @Override
+ public Iterator<OntClass> rootClasses(OntModel m) {
+ Iterator<?> i = m.listClasses();
+ if (i.hasNext() && i.next() instanceof OntClass) {
+ //assume ontology has root classes
+ processSingle(m);
+ } else {
+ //check for presence of aggregate/collection ontologies such as sweetAll.owl
+ processCollection(m);
+ }
+
+ return roots.iterator();
+ }
+
+ private void processSingle(OntModel m) {
+ for (Iterator<?> i = m.listClasses(); i.hasNext(); ) {
+ OntClass c = (OntClass) i.next();
+ try {
+ // too confusing to list all the restrictions as root classes
+ if (c.isAnon()) {
+ continue;
+ }
+
+ if (c.hasSuperClass(m.getProfile().THING(), true) || c.getCardinality(m.getProfile().SUB_CLASS_OF()) == 0) {
+ // this class is directly descended from Thing
+ roots.add(c);
+ }
+ } catch (Exception e) {
+ Log.error("Error during extraction or root Classes from Ontology Model: ", e);
+ }
+ }
+ }
+
+ private void processCollection(OntModel m) {
+ for (Iterator<?> i = m.listSubModels(true); i.hasNext(); ) {
+ OntModel ontModel = (OntModel) i.next();
+ processSingle(ontModel);
+ }
+ }
+
+ public String rdfidToLabel(String idString) {
+ Pattern p = Pattern.compile("([a-z0-9])([A-Z])");
+ Matcher m = p.matcher(idString);
+
+ String labelString = idString;
+ while (m.find()) {
+ labelString = labelString.replaceAll(m.group(1) + m.group(2), m.group(1) + " " + m.group(2));
+ }
+ return labelString;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/package-info.java
new file mode 100644
index 0000000..3447426
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ontology/process/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes ontology processing classes.
+ */
+package gov.nasa.jpl.mudrod.ontology.process;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/package-info.java
new file mode 100644
index 0000000..1e5d8bf
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes the preprocessing, processing, and data structure used
+ * by recommendation module.
+ */
+package gov.nasa.jpl.mudrod.recommendation;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/ImportMetadata.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/ImportMetadata.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/ImportMetadata.java
new file mode 100644
index 0000000..c174f31
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/ImportMetadata.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.recommendation.pre;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.metadata.pre.ApiHarvester;
+import org.apache.commons.io.IOUtils;
+import org.elasticsearch.action.index.IndexRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.util.Properties;
+
+/**
+ * ClassName: Import Metadata to elasticsearch
+ */
+
+public class ImportMetadata extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(ApiHarvester.class);
+
+ public ImportMetadata(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting Metadata Harvesting");
+ startTime = System.currentTimeMillis();
+ addMetadataMapping();
+ importToES();
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("Finished Metadata Harvesting time elapsed: {}s", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ /**
+ * addMetadataMapping: Add mapping to index metadata in Elasticsearch. Please
+ * invoke this method before import metadata to Elasticsearch.
+ */
+ public void addMetadataMapping() {
+ String mappingJson = "{\r\n \"dynamic_templates\": " + "[\r\n " + "{\r\n \"strings\": " + "{\r\n \"match_mapping_type\": \"string\","
+ + "\r\n \"mapping\": {\r\n \"type\": \"string\"," + "\r\n \"analyzer\": \"csv\"\r\n }" + "\r\n }\r\n }\r\n ]\r\n}";
+
+ es.getClient().admin().indices().preparePutMapping(props.getProperty(MudrodConstants.ES_INDEX_NAME)).setType(props.getProperty("recom_metadataType")).setSource(mappingJson).execute().actionGet();
+
+ }
+
+ /**
+ * importToES: Index metadata into elasticsearch from local file directory.
+ * Please make sure metadata have been harvest from web service before
+ * invoking this method.
+ */
+ private void importToES() {
+ es.deleteType(props.getProperty("indexName"), props.getProperty("recom_metadataType"));
+
+ es.createBulkProcessor();
+ File directory = new File(props.getProperty(MudrodConstants.RAW_METADATA_PATH));
+ File[] fList = directory.listFiles();
+ for (File file : fList) {
+ InputStream is;
+ try {
+ is = new FileInputStream(file);
+ try {
+ String jsonTxt = IOUtils.toString(is);
+ JsonParser parser = new JsonParser();
+ JsonElement item = parser.parse(jsonTxt);
+ IndexRequest ir = new IndexRequest(props.getProperty(MudrodConstants.ES_INDEX_NAME), props.getProperty("recom_metadataType")).source(item.toString());
+
+ // preprocessdata
+
+ es.getBulkProcessor().add(ir);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ es.destroyBulkProcessor();
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/MetadataTFIDFGenerator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/MetadataTFIDFGenerator.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/MetadataTFIDFGenerator.java
new file mode 100644
index 0000000..02c74f0
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/MetadataTFIDFGenerator.java
@@ -0,0 +1,100 @@
+/**
+ * Project Name:mudrod-core
+ * File Name:TFIDFGenerator.java
+ * Package Name:gov.nasa.jpl.mudrod.recommendation.pre
+ * Date:Aug 22, 201612:39:52 PM
+ * Copyright (c) 2016, chenzhou1025@126.com All Rights Reserved.
+ */
+
+package gov.nasa.jpl.mudrod.recommendation.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.recommendation.structure.MetadataOpt;
+import gov.nasa.jpl.mudrod.utils.LabeledRowMatrix;
+import gov.nasa.jpl.mudrod.utils.MatrixUtil;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * ClassName: Generate TFIDF information of all metadata
+ */
+public class MetadataTFIDFGenerator extends DiscoveryStepAbstract {
+
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(MetadataTFIDFGenerator.class);
+
+ /**
+ * Creates a new instance of MatrixGenerator.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch drive
+ * @param spark the spark drive
+ */
+ public MetadataTFIDFGenerator(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+
+ LOG.info("Starting Dataset TF_IDF Matrix Generator");
+ startTime = System.currentTimeMillis();
+ try {
+ generateWordBasedTFIDF();
+ } catch (Exception e) {
+ LOG.error("Error during Dataset TF_IDF Matrix Generation: {}", e);
+ }
+ endTime = System.currentTimeMillis();
+
+ LOG.info("Dataset TF_IDF Matrix Generation complete, time elaspsed: {}s", (endTime - startTime) / 1000);
+
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ public LabeledRowMatrix generateWordBasedTFIDF() throws Exception {
+
+ MetadataOpt opt = new MetadataOpt(props);
+
+ JavaPairRDD<String, String> metadataContents = opt.loadAll(es, spark);
+
+ JavaPairRDD<String, List<String>> metadataWords = opt.tokenizeData(metadataContents, " ");
+
+ LabeledRowMatrix wordtfidfMatrix = opt.tFIDFTokens(metadataWords, spark);
+
+ MatrixUtil.exportToCSV(wordtfidfMatrix.rowMatrix, wordtfidfMatrix.rowkeys, wordtfidfMatrix.colkeys, props.getProperty("metadata_word_tfidf_matrix"));
+
+ return wordtfidfMatrix;
+ }
+
+ public LabeledRowMatrix generateTermBasedTFIDF() throws Exception {
+
+ MetadataOpt opt = new MetadataOpt(props);
+
+ List<String> variables = new ArrayList<>();
+ variables.add("DatasetParameter-Term");
+ variables.add("DatasetParameter-Variable");
+ variables.add("Dataset-ExtractTerm");
+
+ JavaPairRDD<String, String> metadataContents = opt.loadAll(es, spark, variables);
+
+ JavaPairRDD<String, List<String>> metadataTokens = opt.tokenizeData(metadataContents, ",");
+
+ LabeledRowMatrix tokentfidfMatrix = opt.tFIDFTokens(metadataTokens, spark);
+
+ MatrixUtil.exportToCSV(tokentfidfMatrix.rowMatrix, tokentfidfMatrix.rowkeys, tokentfidfMatrix.colkeys, props.getProperty("metadata_term_tfidf_matrix"));
+
+ return tokentfidfMatrix;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/NormalizeVariables.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/NormalizeVariables.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/NormalizeVariables.java
new file mode 100644
index 0000000..f5eaa9c
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/NormalizeVariables.java
@@ -0,0 +1,223 @@
+package gov.nasa.jpl.mudrod.recommendation.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+public class NormalizeVariables extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(NormalizeVariables.class);
+ // index name
+ private String indexName;
+ // type name of metadata in ES
+ private String metadataType;
+
+ /**
+ * Creates a new instance of OHEncoder.
+ *
+ * @param props the Mudrod configuration
+ * @param es an instantiated {@link ESDriver}
+ * @param spark an instantiated {@link SparkDriver}
+ */
+ public NormalizeVariables(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ indexName = props.getProperty("indexName");
+ metadataType = props.getProperty("recom_metadataType");
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("*****************processing metadata variables starts******************");
+ startTime = System.currentTimeMillis();
+
+ normalizeMetadataVariables(es);
+
+ endTime = System.currentTimeMillis();
+ LOG.info("*****************processing metadata variables ends******************Took {}s", (endTime - startTime) / 1000);
+
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ public void normalizeMetadataVariables(ESDriver es) {
+
+ es.createBulkProcessor();
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(indexName).setTypes(metadataType).setScroll(new TimeValue(60000)).setQuery(QueryBuilders.matchAllQuery()).setSize(100).execute()
+ .actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> metadata = hit.getSource();
+ Map<String, Object> updatedValues = new HashMap<>();
+
+ this.normalizeSpatialVariables(metadata, updatedValues);
+ this.normalizeTemporalVariables(metadata, updatedValues);
+ this.normalizeOtherVariables(metadata, updatedValues);
+
+ UpdateRequest ur = es.generateUpdateRequest(indexName, metadataType, hit.getId(), updatedValues);
+ es.getBulkProcessor().add(ur);
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ es.destroyBulkProcessor();
+ }
+
+ private void normalizeOtherVariables(Map<String, Object> metadata, Map<String, Object> updatedValues) {
+ String shortname = (String) metadata.get("Dataset-ShortName");
+ double versionNUm = getVersionNum(shortname);
+ updatedValues.put("Dataset-Derivative-VersionNum", versionNUm);
+
+ }
+
+ private Double getVersionNum(String version) {
+ if (version == null) {
+ return 0.0;
+ }
+ Double versionNum = 0.0;
+ Pattern p = Pattern.compile(".*[a-zA-Z].*");
+ if ("Operational/Near-Real-Time".equals(version)) {
+ versionNum = 2.0;
+ } else if (version.matches("[0-9]{1}[a-zA-Z]{1}")) {
+ versionNum = Double.parseDouble(version.substring(0, 1));
+ } else if (p.matcher(version).find()) {
+ versionNum = 0.0;
+ } else {
+ versionNum = Double.parseDouble(version);
+ if (versionNum >= 5) {
+ versionNum = 20.0;
+ }
+ }
+ return versionNum;
+ }
+
+ private void normalizeSpatialVariables(Map<String, Object> metadata, Map<String, Object> updatedValues) {
+
+ // get spatial resolution
+ Double spatialR;
+ if (metadata.get("Dataset-SatelliteSpatialResolution") != null) {
+ spatialR = (Double) metadata.get("Dataset-SatelliteSpatialResolution");
+ } else {
+ Double gridR = (Double) metadata.get("Dataset-GridSpatialResolution");
+ if (gridR != null) {
+ spatialR = 111 * gridR;
+ } else {
+ spatialR = 25.0;
+ }
+ }
+ updatedValues.put("Dataset-Derivative-SpatialResolution", spatialR);
+
+ // Transform Longitude and calculate coverage area
+ double top = parseDouble((String) metadata.get("DatasetCoverage-NorthLat"));
+ double bottom = parseDouble((String) metadata.get("DatasetCoverage-SouthLat"));
+ double left = parseDouble((String) metadata.get("DatasetCoverage-WestLon"));
+ double right = parseDouble((String) metadata.get("DatasetCoverage-EastLon"));
+
+ if (left > 180) {
+ left = left - 360;
+ }
+
+ if (right > 180) {
+ right = right - 360;
+ }
+
+ if (left == right) {
+ left = -180;
+ right = 180;
+ }
+
+ double area = (top - bottom) * (right - left);
+
+ updatedValues.put("DatasetCoverage-Derivative-EastLon", right);
+ updatedValues.put("DatasetCoverage-Derivative-WestLon", left);
+ updatedValues.put("DatasetCoverage-Derivative-NorthLat", top);
+ updatedValues.put("DatasetCoverage-Derivative-SouthLat", bottom);
+ updatedValues.put("DatasetCoverage-Derivative-Area", area);
+
+ // get processing level
+ String processingLevel = (String) metadata.get("Dataset-ProcessingLevel");
+ double dProLevel = this.getProLevelNum(processingLevel);
+ updatedValues.put("Dataset-Derivative-ProcessingLevel", dProLevel);
+ }
+
+ private void normalizeTemporalVariables(Map<String, Object> metadata, Map<String, Object> updatedValues) {
+
+ String trStr = (String) metadata.get("Dataset-TemporalResolution");
+ if ("".equals(trStr)) {
+ trStr = (String) metadata.get("Dataset-TemporalRepeat");
+ }
+
+ updatedValues.put("Dataset-Derivative-TemporalResolution", covertTimeUnit(trStr));
+ }
+
+ private Double covertTimeUnit(String str) {
+ Double timeInHour;
+ if (str.contains("Hour")) {
+ timeInHour = Double.parseDouble(str.split(" ")[0]);
+ } else if (str.contains("Day")) {
+ timeInHour = Double.parseDouble(str.split(" ")[0]) * 24;
+ } else if (str.contains("Week")) {
+ timeInHour = Double.parseDouble(str.split(" ")[0]) * 24 * 7;
+ } else if (str.contains("Month")) {
+ timeInHour = Double.parseDouble(str.split(" ")[0]) * 24 * 7 * 30;
+ } else if (str.contains("Year")) {
+ timeInHour = Double.parseDouble(str.split(" ")[0]) * 24 * 7 * 30 * 365;
+ } else {
+ timeInHour = 0.0;
+ }
+
+ return timeInHour;
+ }
+
+ public Double getProLevelNum(String pro) {
+ if (pro == null) {
+ return 1.0;
+ }
+ Double proNum = 0.0;
+ Pattern p = Pattern.compile(".*[a-zA-Z].*");
+ if (pro.matches("[0-9]{1}[a-zA-Z]{1}")) {
+ proNum = Double.parseDouble(pro.substring(0, 1));
+ } else if (p.matcher(pro).find()) {
+ proNum = 1.0;
+ } else {
+ proNum = Double.parseDouble(pro);
+ }
+
+ return proNum;
+ }
+
+ private double parseDouble(String strNumber) {
+ if (strNumber != null && strNumber.length() > 0) {
+ try {
+ return Double.parseDouble(strNumber);
+ } catch (Exception e) {
+ return -1;
+ }
+ } else
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/SessionCooccurence.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/SessionCooccurence.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/SessionCooccurence.java
new file mode 100644
index 0000000..2aecce3
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/SessionCooccurence.java
@@ -0,0 +1,152 @@
+/**
+ * Project Name:mudrod-core
+ * File Name:SessionCooccurenceMatrix.java
+ * Package Name:gov.nasa.jpl.mudrod.recommendation.pre
+ * Date:Aug 19, 20163:06:33 PM
+ * Copyright (c) 2016, chenzhou1025@126.com All Rights Reserved.
+ */
+
+package gov.nasa.jpl.mudrod.recommendation.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.utils.LabeledRowMatrix;
+import gov.nasa.jpl.mudrod.utils.MatrixUtil;
+import gov.nasa.jpl.mudrod.weblog.structure.SessionExtractor;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.function.PairFunction;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.Tuple2;
+
+import java.util.*;
+
+/**
+ * ClassName: SessionCooccurenceMatrix Function: Generate metadata session
+ * coocucurence matrix from web logs. Each row in the matrix is corresponding to
+ * a metadata, and each column is a session.
+ */
+public class SessionCooccurence extends DiscoveryStepAbstract {
+
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(SessionCooccurence.class);
+
+ /**
+ * Creates a new instance of SessionCooccurence.
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch drive
+ * @param spark
+ * the spark driver
+ */
+ public SessionCooccurence(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+
+ LOG.info("Starting dataset session-based similarity generation...");
+
+ startTime = System.currentTimeMillis();
+
+ // get all metadata session cooccurance data
+ SessionExtractor extractor = new SessionExtractor();
+ JavaPairRDD<String, List<String>> sessionDatasetRDD = extractor.bulidSessionDatasetRDD(props, es, spark);
+
+ // remove retired datasets
+ JavaPairRDD<String, List<String>> sessionFiltedDatasetsRDD = removeRetiredDataset(es, sessionDatasetRDD);
+ LabeledRowMatrix datasetSessionMatrix = MatrixUtil.createWordDocMatrix(sessionFiltedDatasetsRDD);
+
+ // export
+ MatrixUtil.exportToCSV(datasetSessionMatrix.rowMatrix, datasetSessionMatrix.rowkeys, datasetSessionMatrix.colkeys, props.getProperty("session_metadata_Matrix"));
+
+ endTime = System.currentTimeMillis();
+
+ LOG.info("Completed dataset session-based similarity generation. Time elapsed: {}s", (endTime - startTime) / 1000);
+
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ /**
+ * filter out-of-data metadata
+ *
+ * @param es
+ * the Elasticsearch drive
+ * @param userDatasetsRDD
+ * dataset extracted from session
+ * @return filtered session datasets
+ */
+ public JavaPairRDD<String, List<String>> removeRetiredDataset(ESDriver es, JavaPairRDD<String, List<String>> userDatasetsRDD) {
+
+ Map<String, String> nameMap = this.getOnServiceMetadata(es);
+
+ return userDatasetsRDD.mapToPair(new PairFunction<Tuple2<String, List<String>>, String, List<String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, List<String>> call(Tuple2<String, List<String>> arg0) throws Exception {
+ List<String> oriDatasets = arg0._2;
+ List<String> newDatasets = new ArrayList<>();
+ int size = oriDatasets.size();
+ for (int i = 0; i < size; i++) {
+ String name = oriDatasets.get(i);
+ if (nameMap.containsKey(name)) {
+ newDatasets.add(nameMap.get(name));
+ }
+ }
+ return new Tuple2<>(arg0._1, newDatasets);
+ }
+ });
+
+ }
+
+ /**
+ * getMetadataNameMap: Get on service metadata names, key is lowcase of short
+ * name and value is the original short name
+ *
+ * @param es
+ * the elasticsearch client
+ * @return a map from lower case metadata name to original metadata name
+ */
+ private Map<String, String> getOnServiceMetadata(ESDriver es) {
+
+ String indexName = props.getProperty(MudrodConstants.ES_INDEX_NAME);
+ String metadataType = props.getProperty("recom_metadataType");
+
+ Map<String, String> shortnameMap = new HashMap<>();
+ SearchResponse scrollResp = es.getClient().prepareSearch(indexName).setTypes(metadataType).setScroll(new TimeValue(60000)).setQuery(QueryBuilders.matchAllQuery()).setSize(100).execute()
+ .actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> metadata = hit.getSource();
+ String shortName = (String) metadata.get("Dataset-ShortName");
+ shortnameMap.put(shortName.toLowerCase(), shortName);
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ return shortnameMap;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/package-info.java
new file mode 100644
index 0000000..2febf96
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/pre/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes the preprocessing required by recommendation module.
+ */
+package gov.nasa.jpl.mudrod.recommendation.pre;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/AbstractBasedSimilarity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/AbstractBasedSimilarity.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/AbstractBasedSimilarity.java
new file mode 100644
index 0000000..b0e93fc
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/AbstractBasedSimilarity.java
@@ -0,0 +1,74 @@
+/**
+ * Project Name:mudrod-core
+ * File Name:TopicBasedCF.java
+ * Package Name:gov.nasa.jpl.mudrod.recommendation.process
+ * Date:Aug 22, 201610:45:55 AM
+ * Copyright (c) 2016, chenzhou1025@126.com All Rights Reserved.
+ */
+
+package gov.nasa.jpl.mudrod.recommendation.process;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.semantics.SVDAnalyzer;
+import gov.nasa.jpl.mudrod.utils.LinkageTriple;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * ClassName: Recommend metedata based on data content semantic similarity
+ */
+public class AbstractBasedSimilarity extends DiscoveryStepAbstract {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractBasedSimilarity.class);
+
+ /**
+ * Creates a new instance of TopicBasedCF.
+ *
+ * @param props the Mudrod configuration
+ * @param es the Elasticsearch client
+ * @param spark the spark drive
+ */
+ public AbstractBasedSimilarity(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+
+ LOG.info("*****************abstract similarity calculation starts******************");
+ startTime = System.currentTimeMillis();
+
+ try {
+ /*String topicMatrixFile = props.getProperty("metadata_term_tfidf_matrix");
+ SemanticAnalyzer analyzer = new SemanticAnalyzer(props, es, spark);
+ List<LinkageTriple> triples = analyzer
+ .calTermSimfromMatrix(topicMatrixFile);
+ analyzer.saveToES(triples, props.getProperty("indexName"),
+ props.getProperty("metadataTermTFIDFSimType"), true, true);*/
+
+ // for comparison
+ SVDAnalyzer svd = new SVDAnalyzer(props, es, spark);
+ svd.getSVDMatrix(props.getProperty("metadata_word_tfidf_matrix"), 150, props.getProperty("metadata_word_tfidf_matrix"));
+ List<LinkageTriple> tripleList = svd.calTermSimfromMatrix(props.getProperty("metadata_word_tfidf_matrix"));
+ svd.saveToES(tripleList, props.getProperty("indexName"), props.getProperty("metadataWordTFIDFSimType"), true, true);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ endTime = System.currentTimeMillis();
+ LOG.info("*****************abstract similarity calculation ends******************Took {}s", (endTime - startTime) / 1000);
+
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/VariableBasedSimilarity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/VariableBasedSimilarity.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/VariableBasedSimilarity.java
new file mode 100644
index 0000000..67aeeb8
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/VariableBasedSimilarity.java
@@ -0,0 +1,380 @@
+package gov.nasa.jpl.mudrod.recommendation.process;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.*;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+public class VariableBasedSimilarity extends DiscoveryStepAbstract implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(VariableBasedSimilarity.class);
+
+ private DecimalFormat df = new DecimalFormat("#.000");
+ // a map from variable to its type
+ public Map<String, Integer> variableTypes;
+ public Map<String, Integer> variableWeights;
+
+ private static final Integer VAR_SPATIAL = 1;
+ private static final Integer VAR_TEMPORAL = 2;
+ private static final Integer VAR_CATEGORICAL = 3;
+ private static final Integer VAR_ORDINAL = 4;
+
+ // index name
+ private String indexName;
+ // type name of metadata in ES
+ private String metadataType;
+ private String variableSimType;
+
+ /**
+ * Creates a new instance of OHEncoder.
+ *
+ * @param props the Mudrod configuration
+ * @param es an instantiated {@link ESDriver}
+ * @param spark an instantiated {@link SparkDriver}
+ */
+ public VariableBasedSimilarity(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+
+ indexName = props.getProperty("indexName");
+ metadataType = props.getProperty("recom_metadataType");
+ variableSimType = props.getProperty("metadataCodeSimType");
+ this.inital();
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("*****************calculating metadata variables based similarity starts******************");
+ startTime = System.currentTimeMillis();
+ es.deleteType(indexName, variableSimType);
+ addMapping(es, indexName, variableSimType);
+
+ VariableBasedSimilarity(es);
+ es.refreshIndex();
+ normalizeVariableWeight(es);
+ es.refreshIndex();
+ endTime = System.currentTimeMillis();
+ LOG.info("*****************calculating metadata variables based similarity ends******************Took {}s", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ public void inital() {
+ this.initVariableType();
+ this.initVariableWeight();
+ }
+
+ private void initVariableType() {
+ variableTypes = new HashMap<>();
+
+ variableTypes.put("DatasetParameter-Variable", VAR_CATEGORICAL);
+ variableTypes.put("DatasetRegion-Region", VAR_CATEGORICAL);
+ variableTypes.put("Dataset-ProjectionType", VAR_CATEGORICAL);
+ variableTypes.put("Dataset-ProcessingLevel", VAR_CATEGORICAL);
+ variableTypes.put("DatasetParameter-Topic", VAR_CATEGORICAL);
+ variableTypes.put("DatasetParameter-Term", VAR_CATEGORICAL);
+ variableTypes.put("DatasetParameter-Category", VAR_CATEGORICAL);
+ variableTypes.put("DatasetPolicy-DataFormat", VAR_CATEGORICAL);
+ variableTypes.put("Collection-ShortName", VAR_CATEGORICAL);
+ variableTypes.put("DatasetSource-Source-Type", VAR_CATEGORICAL);
+ variableTypes.put("DatasetSource-Source-ShortName", VAR_CATEGORICAL);
+ variableTypes.put("DatasetSource-Sensor-ShortName", VAR_CATEGORICAL);
+ variableTypes.put("DatasetPolicy-Availability", VAR_CATEGORICAL);
+ variableTypes.put("Dataset-Provider-ShortName", VAR_CATEGORICAL);
+
+ variableTypes.put("Dataset-Derivative-ProcessingLevel", VAR_ORDINAL);
+ variableTypes.put("Dataset-Derivative-TemporalResolution", VAR_ORDINAL);
+ variableTypes.put("Dataset-Derivative-SpatialResolution", VAR_ORDINAL);
+ }
+
+ private void initVariableWeight() {
+ variableWeights = new HashMap<>();
+
+ variableWeights.put("Dataset-Derivative-ProcessingLevel", 5);
+ variableWeights.put("DatasetParameter-Category", 5);
+ variableWeights.put("DatasetParameter-Variable", 5);
+ variableWeights.put("DatasetSource-Sensor-ShortName", 5);
+
+ variableWeights.put("DatasetPolicy-Availability", 4);
+ variableWeights.put("DatasetRegion-Region", 4);
+ variableWeights.put("DatasetSource-Source-Type", 4);
+ variableWeights.put("DatasetSource-Source-ShortName", 4);
+ variableWeights.put("DatasetParameter-Term", 4);
+ variableWeights.put("DatasetPolicy-DataFormat", 4);
+ variableWeights.put("Dataset-Derivative-SpatialResolution", 4);
+ variableWeights.put("Temporal_Covergae", 4);
+
+ variableWeights.put("DatasetParameter-Topic", 3);
+ variableWeights.put("Collection-ShortName", 3);
+ variableWeights.put("Dataset-Derivative-TemporalResolution", 3);
+ variableWeights.put("Spatial_Covergae", 3);
+
+ variableWeights.put("Dataset-ProjectionType", 1);
+ variableWeights.put("Dataset-Provider-ShortName", 1);
+ }
+
+ public void VariableBasedSimilarity(ESDriver es) {
+
+ es.createBulkProcessor();
+
+ List<Map<String, Object>> metadatas = new ArrayList<>();
+ SearchResponse scrollResp = es.getClient().prepareSearch(indexName).setTypes(metadataType).setScroll(new TimeValue(60000)).setQuery(QueryBuilders.matchAllQuery()).setSize(100).execute()
+ .actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> metadataA = hit.getSource();
+ metadatas.add(metadataA);
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ int size = metadatas.size();
+ for (int i = 0; i < size; i++) {
+ Map<String, Object> metadataA = metadatas.get(i);
+ String shortNameA = (String) metadataA.get("Dataset-ShortName");
+
+ for (int j = 0; j < size; j++) {
+ metadataA = metadatas.get(i);
+ Map<String, Object> metadataB = metadatas.get(j);
+ String shortNameB = (String) metadataB.get("Dataset-ShortName");
+
+ try {
+ XContentBuilder contentBuilder = jsonBuilder().startObject();
+ contentBuilder.field("concept_A", shortNameA);
+ contentBuilder.field("concept_B", shortNameB);
+
+ // spatial similarity
+ this.spatialSimilarity(metadataA, metadataB, contentBuilder);
+ // temporal similarity
+ this.temporalSimilarity(metadataA, metadataB, contentBuilder);
+ // categorical variables similarity
+ this.categoricalVariablesSimilarity(metadataA, metadataB, contentBuilder);
+ // ordinal variables similarity
+ this.ordinalVariablesSimilarity(metadataA, metadataB, contentBuilder);
+
+ contentBuilder.endObject();
+
+ IndexRequest ir = new IndexRequest(indexName, variableSimType).source(contentBuilder);
+ es.getBulkProcessor().add(ir);
+
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+
+ }
+ }
+
+ es.destroyBulkProcessor();
+ }
+
+ /*
+ * refer to P. Frontiera, R. Larson, and J. Radke (2008) A comparison of
+ geometric approaches to assessing spatial similarity for GIR.
+ International Journal of Geographical Information Science,
+ 22(3)
+ */
+ public void spatialSimilarity(Map<String, Object> metadataA, Map<String, Object> metadataB, XContentBuilder contentBuilder) throws IOException {
+
+ double topA = (double) metadataA.get("DatasetCoverage-Derivative-NorthLat");
+ double bottomA = (double) metadataA.get("DatasetCoverage-Derivative-SouthLat");
+ double leftA = (double) metadataA.get("DatasetCoverage-Derivative-WestLon");
+ double rightA = (double) metadataA.get("DatasetCoverage-Derivative-EastLon");
+ double areaA = (double) metadataA.get("DatasetCoverage-Derivative-Area");
+
+ double topB = (double) metadataB.get("DatasetCoverage-Derivative-NorthLat");
+ double bottomB = (double) metadataB.get("DatasetCoverage-Derivative-SouthLat");
+ double leftB = (double) metadataB.get("DatasetCoverage-Derivative-WestLon");
+ double rightB = (double) metadataB.get("DatasetCoverage-Derivative-EastLon");
+ double areaB = (double) metadataB.get("DatasetCoverage-Derivative-Area");
+
+ // Intersect area
+ double xOverlap = Math.max(0, Math.min(rightA, rightB) - Math.max(leftA, leftB));
+ double yOverlap = Math.max(0, Math.min(topA, topB) - Math.max(bottomA, bottomB));
+ double overlapArea = xOverlap * yOverlap;
+
+ // Calculate coverage similarity
+ double similarity = 0.0;
+ if (areaA > 0 && areaB > 0) {
+ similarity = (overlapArea / areaA + overlapArea / areaB) * 0.5;
+ }
+
+ contentBuilder.field("Spatial_Covergae_Sim", similarity);
+ }
+
+ public void temporalSimilarity(Map<String, Object> metadataA, Map<String, Object> metadataB, XContentBuilder contentBuilder) throws IOException {
+
+ double similarity = 0.0;
+ double startTimeA = Double.parseDouble((String) metadataA.get("Dataset-DatasetCoverage-StartTimeLong"));
+ String endTimeAStr = (String) metadataA.get("Dataset-DatasetCoverage-StopTimeLong");
+ double endTimeA = 0.0;
+ if ("".equals(endTimeAStr)) {
+ endTimeA = System.currentTimeMillis();
+ } else {
+ endTimeA = Double.parseDouble(endTimeAStr);
+ }
+ double timespanA = endTimeA - startTimeA;
+
+ double startTimeB = Double.parseDouble((String) metadataB.get("Dataset-DatasetCoverage-StartTimeLong"));
+ String endTimeBStr = (String) metadataB.get("Dataset-DatasetCoverage-StopTimeLong");
+ double endTimeB = 0.0;
+ if ("".equals(endTimeBStr)) {
+ endTimeB = System.currentTimeMillis();
+ } else {
+ endTimeB = Double.parseDouble(endTimeBStr);
+ }
+ double timespanB = endTimeB - startTimeB;
+
+ double intersect = 0.0;
+ if (startTimeB >= endTimeA || endTimeB <= startTimeA) {
+ intersect = 0.0;
+ } else if (startTimeB >= startTimeA && endTimeB <= endTimeA) {
+ intersect = timespanB;
+ } else if (startTimeA >= startTimeB && endTimeA <= endTimeB) {
+ intersect = timespanA;
+ } else {
+ intersect = (startTimeA > startTimeB) ? (endTimeB - startTimeA) : (endTimeA - startTimeB);
+ }
+
+ similarity = intersect / (Math.sqrt(timespanA) * Math.sqrt(timespanB));
+ contentBuilder.field("Temporal_Covergae_Sim", similarity);
+ }
+
+ public void categoricalVariablesSimilarity(Map<String, Object> metadataA, Map<String, Object> metadataB, XContentBuilder contentBuilder) throws IOException {
+
+ for (String variable : variableTypes.keySet()) {
+ Integer type = variableTypes.get(variable);
+ if (type != VAR_CATEGORICAL) {
+ continue;
+ }
+
+ double similarity = 0.0;
+ Object valueA = metadataA.get(variable);
+ Object valueB = metadataB.get(variable);
+ if (valueA instanceof ArrayList) {
+ ArrayList<String> aList = (ArrayList<String>) valueA;
+ ArrayList<String> bList = (ArrayList<String>) valueB;
+ if (aList != null && bList != null) {
+
+ int lengthA = aList.size();
+ int lengthB = bList.size();
+ List<String> newAList = new ArrayList<>(aList);
+ List<String> newBList = new ArrayList<>(bList);
+ newAList.retainAll(newBList);
+ similarity = newAList.size() / lengthA;
+ }
+
+ } else if (valueA instanceof String) {
+ if (valueA.equals(valueB)) {
+ similarity = 1.0;
+ }
+ }
+
+ contentBuilder.field(variable + "_Sim", similarity);
+ }
+ }
+
+ public void ordinalVariablesSimilarity(Map<String, Object> metadataA, Map<String, Object> metadataB, XContentBuilder contentBuilder) throws IOException {
+ for (String variable : variableTypes.keySet()) {
+ Integer type = variableTypes.get(variable);
+ if (type != VAR_ORDINAL) {
+ continue;
+ }
+
+ double similarity = 0.0;
+ Object valueA = metadataA.get(variable);
+ Object valueB = metadataB.get(variable);
+ if (valueA != null && valueB != null) {
+
+ double a = (double) valueA;
+ double b = (double) valueB;
+ if (a != 0.0) {
+ similarity = 1 - Math.abs(b - a) / a;
+ if (similarity < 0) {
+ similarity = 0.0;
+ }
+ }
+ }
+
+ contentBuilder.field(variable + "_Sim", similarity);
+ }
+ }
+
+ public static void addMapping(ESDriver es, String index, String type) {
+ XContentBuilder Mapping;
+ try {
+ Mapping = jsonBuilder().startObject().startObject(type).startObject("properties").startObject("concept_A").field("type", "string").field("index", "not_analyzed").endObject()
+ .startObject("concept_B").field("type", "string").field("index", "not_analyzed").endObject()
+
+ .endObject().endObject().endObject();
+
+ es.getClient().admin().indices().preparePutMapping(index).setType(type).setSource(Mapping).execute().actionGet();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void normalizeVariableWeight(ESDriver es) {
+
+ es.createBulkProcessor();
+
+ double totalWeight = 0.0;
+ for (String variable : variableWeights.keySet()) {
+ totalWeight += variableWeights.get(variable);
+ }
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(indexName).setTypes(variableSimType).setScroll(new TimeValue(60000)).setQuery(QueryBuilders.matchAllQuery()).setSize(100).execute()
+ .actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> similarities = hit.getSource();
+
+ double totalSim = 0.0;
+ for (String variable : variableWeights.keySet()) {
+ if (similarities.containsKey(variable + "_Sim")) {
+ double value = (double) similarities.get(variable + "_Sim");
+ double weight = variableWeights.get(variable);
+ totalSim += weight * value;
+ }
+ }
+
+ double weight = totalSim / totalWeight;
+ UpdateRequest ur = es.generateUpdateRequest(indexName, variableSimType, hit.getId(), "weight", weight);
+ es.getBulkProcessor().add(ur);
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ es.destroyBulkProcessor();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/package-info.java
new file mode 100644
index 0000000..84231f7
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes the processing required by recommendation module.
+ */
+package gov.nasa.jpl.mudrod.recommendation.process;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/sessionBasedCF.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/sessionBasedCF.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/sessionBasedCF.java
new file mode 100644
index 0000000..ae55769
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/process/sessionBasedCF.java
@@ -0,0 +1,74 @@
+/**
+ * Project Name:mudrod-core
+ * File Name:sessionBasedCF.java
+ * Package Name:gov.nasa.jpl.mudrod.recommendation.process
+ * Date:Aug 19, 20163:17:00 PM
+ * Copyright (c) 2016, chenzhou1025@126.com All Rights Reserved.
+ */
+
+package gov.nasa.jpl.mudrod.recommendation.process;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.semantics.SemanticAnalyzer;
+import gov.nasa.jpl.mudrod.utils.LinkageTriple;
+import gov.nasa.jpl.mudrod.utils.SimilarityUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * ClassName: Recommend metedata based on session level co-occurrence
+ */
+public class sessionBasedCF extends DiscoveryStepAbstract {
+
+ private static final Logger LOG = LoggerFactory.getLogger(sessionBasedCF.class);
+
+ /**
+ * Creates a new instance of sessionBasedCF.
+ *
+ * @param props
+ * the Mudrod configuration
+ * @param es
+ * the Elasticsearch drive
+ * @param spark
+ * the spark drive
+ */
+ public sessionBasedCF(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("*****************Session based metadata similarity starts******************");
+ startTime = System.currentTimeMillis();
+
+ try {
+ String session_metadatFile = props.getProperty("session_metadata_Matrix");
+ File f = new File(session_metadatFile);
+ if (f.exists()) {
+ SemanticAnalyzer analyzer = new SemanticAnalyzer(props, es, spark);
+ List<LinkageTriple> triples = analyzer.calTermSimfromMatrix(session_metadatFile, SimilarityUtil.SIM_PEARSON, 1);
+ analyzer.saveToES(triples, props.getProperty("indexName"), props.getProperty("metadataSessionBasedSimType"), true, false);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ endTime = System.currentTimeMillis();
+ LOG.info("*****************Session based metadata similarity ends******************Took {}s", (endTime - startTime) / 1000);
+
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/HybridRecommendation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/HybridRecommendation.java b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/HybridRecommendation.java
new file mode 100644
index 0000000..4163fda
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/recommendation/structure/HybridRecommendation.java
@@ -0,0 +1,274 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.recommendation.structure;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.sort.SortOrder;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.util.*;
+
+/**
+ * Recommend metadata using combination all two methods, including content-based
+ * similarity and session-level similarity
+ */
+public class HybridRecommendation extends DiscoveryStepAbstract {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ // recommended metadata list
+ protected transient List<LinkedTerm> termList = new ArrayList<>();
+ // format decimal
+ DecimalFormat df = new DecimalFormat("#.00");
+ // index name
+ protected static final String INDEX_NAME = "indexName";
+ private static final String WEIGHT = "weight";
+
+ /**
+ * recommended data class Date: Sep 12, 2016 2:25:28 AM
+ */
+ class LinkedTerm {
+ public String term = null;
+ public double weight = 0;
+ public String model = null;
+
+ public LinkedTerm(String str, double w, String m) {
+ term = str;
+ weight = w;
+ model = m;
+ }
+ }
+
+ public HybridRecommendation(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ /**
+ * Get recommended data for a giving dataset
+ *
+ * @param input: a giving dataset
+ * @param num: the number of recommended dataset
+ * @return recommended dataset in json format
+ */
+ public JsonObject getRecomDataInJson(String input, int num) {
+ JsonObject resultJson = new JsonObject();
+
+ String type = props.getProperty("metadataCodeSimType");
+ Map<String, Double> sortedVariableSimMap = getRelatedData(type, input, num + 10);
+
+ type = props.getProperty("metadataWordTFIDFSimType");
+ Map<String, Double> sortedAbstractSimMap = getRelatedData(type, input, num + 10);
+
+ type = props.getProperty("metadataSessionBasedSimType");
+ Map<String, Double> sortedSessionSimMap = getRelatedData(type, input, num + 10);
+
+ JsonElement variableSimJson = mapToJson(sortedVariableSimMap, num);
+ resultJson.add("variableSim", variableSimJson);
+ JsonElement abstractSimJson = mapToJson(sortedAbstractSimMap, num);
+ resultJson.add("abstractSim", abstractSimJson);
+ JsonElement sessionSimJson = mapToJson(sortedSessionSimMap, num);
+ resultJson.add("sessionSim", sessionSimJson);
+
+ Map<String, Double> hybirdSimMap = new HashMap<String, Double>();
+
+ for (String name : sortedAbstractSimMap.keySet()) {
+ hybirdSimMap.put(name, sortedAbstractSimMap.get(name) /** 0.4 */);
+ }
+
+ for (String name : sortedVariableSimMap.keySet()) {
+ if (hybirdSimMap.get(name) != null) {
+ double sim = hybirdSimMap.get(name) + sortedVariableSimMap.get(name) /** 0.3 */;
+ hybirdSimMap.put(name, Double.parseDouble(df.format(sim)));
+ } else {
+ double sim = sortedVariableSimMap.get(name);
+ hybirdSimMap.put(name, Double.parseDouble(df.format(sim)));
+ }
+ }
+
+ for (String name : sortedSessionSimMap.keySet()) {
+ if (hybirdSimMap.get(name) != null) {
+ double sim = hybirdSimMap.get(name) + sortedSessionSimMap.get(name) /** 0.1 */;
+ hybirdSimMap.put(name, Double.parseDouble(df.format(sim)));
+ } else {
+ double sim = sortedSessionSimMap.get(name);
+ hybirdSimMap.put(name, Double.parseDouble(df.format(sim)));
+ }
+ }
+
+ Map<String, Double> sortedHybirdSimMap = this.sortMapByValue(hybirdSimMap);
+
+ JsonElement linkedJson = mapToJson(sortedHybirdSimMap, num);
+ resultJson.add("linked", linkedJson);
+
+ return resultJson;
+ }
+
+ /**
+ * Method of converting hashmap to JSON
+ *
+ * @param wordweights a map from related metadata to weights
+ * @param num the number of converted elements
+ * @return converted JSON object
+ */
+ protected JsonElement mapToJson(Map<String, Double> wordweights, int num) {
+ Gson gson = new Gson();
+
+ List<JsonObject> nodes = new ArrayList<>();
+ Set<String> words = wordweights.keySet();
+ int i = 0;
+ for (String wordB : words) {
+ JsonObject node = new JsonObject();
+ node.addProperty("name", wordB);
+ node.addProperty("weight", wordweights.get(wordB));
+ nodes.add(node);
+
+ i += 1;
+ if (i >= num) {
+ break;
+ }
+ }
+
+ String nodesJson = gson.toJson(nodes);
+ JsonElement nodesElement = gson.fromJson(nodesJson, JsonElement.class);
+
+ return nodesElement;
+ }
+
+ /**
+ * Get recommend dataset for a giving dataset
+ *
+ * @param type recommend method
+ * @param input a giving dataset
+ * @param num the number of recommended dataset
+ * @return recommended dataset map, key is dataset name, value is similarity
+ * value
+ */
+ public Map<String, Double> getRelatedData(String type, String input, int num) {
+ termList = new ArrayList<>();
+ Map<String, Double> termsMap = new HashMap<>();
+ Map<String, Double> sortedMap = new HashMap<>();
+ try {
+ List<LinkedTerm> links = getRelatedDataFromES(type, input, num);
+ int size = links.size();
+ for (int i = 0; i < size; i++) {
+ termsMap.put(links.get(i).term, links.get(i).weight);
+ }
+
+ sortedMap = sortMapByValue(termsMap); // terms_map will be empty
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return sortedMap;
+ }
+
+ /**
+ * Get recommend dataset for a giving dataset
+ *
+ * @param type recommend method
+ * @param input a giving dataset
+ * @param num the number of recommended dataset
+ * @return recommended dataset list
+ */
+ public List<LinkedTerm> getRelatedDataFromES(String type, String input, int num) {
+
+ SearchRequestBuilder builder = es.getClient().prepareSearch(props.getProperty(INDEX_NAME)).setTypes(type).setQuery(QueryBuilders.termQuery("concept_A", input)).addSort(WEIGHT, SortOrder.DESC)
+ .setSize(num);
+
+ SearchResponse usrhis = builder.execute().actionGet();
+
+ for (SearchHit hit : usrhis.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String conceptB = (String) result.get("concept_B");
+
+ if (!conceptB.equals(input)) {
+ LinkedTerm lTerm = new LinkedTerm(conceptB, (double) result.get(WEIGHT), type);
+ termList.add(lTerm);
+ }
+ }
+
+ return termList;
+ }
+
+ /**
+ * Method of sorting a map by value
+ *
+ * @param passedMap input map
+ * @return sorted map
+ */
+ public Map<String, Double> sortMapByValue(Map<String, Double> passedMap) {
+ List<String> mapKeys = new ArrayList<>(passedMap.keySet());
+ List<Double> mapValues = new ArrayList<>(passedMap.values());
+ Collections.sort(mapValues, Collections.reverseOrder());
+ Collections.sort(mapKeys, Collections.reverseOrder());
+
+ LinkedHashMap<String, Double> sortedMap = new LinkedHashMap<>();
+
+ Iterator<Double> valueIt = mapValues.iterator();
+ while (valueIt.hasNext()) {
+ Object val = valueIt.next();
+ Iterator<String> keyIt = mapKeys.iterator();
+
+ while (keyIt.hasNext()) {
+ Object key = keyIt.next();
+ String comp1 = passedMap.get(key).toString();
+ String comp2 = val.toString();
+
+ if (comp1.equals(comp2)) {
+ passedMap.remove(key);
+ mapKeys.remove(key);
+ sortedMap.put((String) key, (Double) val);
+ break;
+ }
+ }
+ }
+ return sortedMap;
+ }
+
+ public static void main(String[] args) throws IOException {
+
+ MudrodEngine me = new MudrodEngine();
+ Properties props = me.loadConfig();
+ ESDriver es = new ESDriver(me.getConfig());
+ HybridRecommendation test = new HybridRecommendation(props, es, null);
+
+ // String input = "NSCAT_LEVEL_1.7_V2";
+ String input = "AQUARIUS_L3_SSS_SMIA_MONTHLY-CLIMATOLOGY_V4";
+ JsonObject json = test.getRecomDataInJson(input, 10);
+
+ System.out.println(json.toString());
+ }
+}
[12/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.classpath
----------------------------------------------------------------------
diff --git a/service/.classpath b/service/.classpath
new file mode 100644
index 0000000..5a115a3
--- /dev/null
+++ b/service/.classpath
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java" including="**/*.java"/>
+ <classpathentry kind="src" path="src/main/resources" excluding="**/*.java"/>
+ <classpathentry kind="output" path="target/classes"/>
+ <classpathentry kind="var" path="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/javax/ws/rs/javax.ws.rs-api/2.0.1/javax.ws.rs-api-2.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="src" path="/mudrod-core"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/code/gson/gson/2.5/gson-2.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/jdom/jdom/2.0.2/jdom-2.0.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/elasticsearch/5.2.0/elasticsearch-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-core/6.4.0/lucene-core-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-analyzers-common/6.4.0/lucene-analyzers-common-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-backward-codecs/6.4.0/lucene-backward-codecs-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-grouping/6.4.0/lucene-grouping-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-highlighter/6.4.0/lucene-highlighter-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-join/6.4.0/lucene-join-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-memory/6.4.0/lucene-memory-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-misc/6.4.0/lucene-misc-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-queries/6.4.0/lucene-queries-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-queryparser/6.4.0/lucene-queryparser-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-sandbox/6.4.0/lucene-sandbox-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-spatial/6.4.0/lucene-spatial-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-spatial-extras/6.4.0/lucene-spatial-extras-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-spatial3d/6.4.0/lucene-spatial3d-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-suggest/6.4.0/lucene-suggest-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/securesm/1.1/securesm-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sf/jopt-simple/jopt-simple/5.0.2/jopt-simple-5.0.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/carrotsearch/hppc/0.7.1/hppc-0.7.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/joda-time/joda-time/2.9.4/joda-time-2.9.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/yaml/snakeyaml/1.15/snakeyaml-1.15.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.8.6/jackson-core-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-smile/2.8.6/jackson-dataformat-smile-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.8.6/jackson-dataformat-yaml-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.8.6/jackson-dataformat-cbor-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/tdunning/t-digest/3.0/t-digest-3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/hdrhistogram/HdrHistogram/2.1.6/HdrHistogram-2.1.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/java/dev/jna/jna/4.2.2/jna-4.2.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/client/transport/5.2.0/transport-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/transport-netty3-client/5.2.0/transport-netty3-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/netty/netty/3.8.0.Final/netty-3.8.0.Final.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/reindex-client/5.2.0/reindex-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/client/rest/5.2.0/rest-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpcore/4.4.5/httpcore-4.4.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpasyncclient/4.1.2/httpasyncclient-4.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpcore-nio/4.4.5/httpcore-nio-4.4.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.3/commons-codec-1.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/lang-mustache-client/5.2.0/lang-mustache-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/spullara/mustache/java/compiler/0.9.3/compiler-0.9.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/percolator-client/5.2.0/percolator-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/elasticsearch-spark-20_2.11/5.2.0/elasticsearch-spark-20_2.11-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-sql_2.11/2.1.0/spark-sql_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/univocity/univocity-parsers/2.2.1/univocity-parsers-2.2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-sketch_2.11/2.1.0/spark-sketch_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-tags_2.11/2.1.0/spark-tags_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scalatest/scalatest_2.11/2.2.6/scalatest_2.11-2.2.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scala-library/2.11.8/scala-library-2.11.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scala-reflect/2.11.7/scala-reflect-2.11.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-xml_2.11/1.0.2/scala-xml_2.11-1.0.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/spark-project/spark/unused/1.0.0/unused-1.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-core_2.11/2.1.0/spark-core_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro-mapred/1.7.7/avro-mapred-1.7.7-hadoop2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro-ipc/1.7.7/avro-ipc-1.7.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro/1.7.7/avro-1.7.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/jackson/jackson-core-asl/1.9.13/jackson-core-asl-1.9.13.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/jackson/jackson-mapper-asl/1.9.13/jackson-mapper-asl-1.9.13.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/thoughtworks/paranamer/paranamer/2.6/paranamer-2.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/xerial/snappy/snappy-java/1.1.2.6/snappy-java-1.1.2.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-compress/1.4.1/commons-compress-1.4.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/tukaani/xz/1.0/xz-1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.16/slf4j-api-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro-ipc/1.7.7/avro-ipc-1.7.7-tests.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/twitter/chill_2.11/0.8.0/chill_2.11-0.8.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/twitter/chill-java/0.8.0/chill-java-0.8.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/esotericsoftware/kryo-shaded/3.0.3/kryo-shaded-3.0.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/esotericsoftware/minlog/1.3.0/minlog-1.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/objenesis/objenesis/2.1/objenesis-2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/xbean/xbean-asm5-shaded/4.4/xbean-asm5-shaded-4.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-client/2.2.0/hadoop-client-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-common/2.2.0/hadoop-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-annotations/2.2.0/hadoop-annotations-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/guava/guava/14.0.1/guava-14.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-cli/commons-cli/1.2/commons-cli-1.2.jar" sourcepath="M2_REPO/commons-cli/commons-cli/1.2/commons-cli-1.2-sources.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-math/2.1/commons-math-2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/xmlenc/xmlenc/0.52/xmlenc-0.52.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-httpclient/commons-httpclient/3.1/commons-httpclient-3.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-io/commons-io/2.1/commons-io-2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-net/commons-net/2.2/commons-net-2.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.17/log4j-1.2.17.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.5/commons-lang-2.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-configuration/commons-configuration/1.6/commons-configuration-1.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-digester/commons-digester/1.8/commons-digester-1.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils/1.7.0/commons-beanutils-1.7.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils-core/1.8.0/commons-beanutils-core-1.8.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.7.16/slf4j-log4j12-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/protobuf/protobuf-java/2.5.0/protobuf-java-2.5.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-auth/2.2.0/hadoop-auth-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/zookeeper/zookeeper/3.4.5/zookeeper-3.4.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-hdfs/2.2.0/hadoop-hdfs-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/mortbay/jetty/jetty-util/6.1.26/jetty-util-6.1.26.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-app/2.2.0/hadoop-mapreduce-client-app-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-common/2.2.0/hadoop-mapreduce-client-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-common/2.2.0/hadoop-yarn-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-api/2.2.0/hadoop-yarn-api-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/jettison/jettison/1.3.8/jettison-1.3.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/stax/stax-api/1.0.1/stax-api-1.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-client/2.2.0/hadoop-yarn-client-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-core/2.2.0/hadoop-mapreduce-client-core-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-server-common/2.2.0/hadoop-yarn-server-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-shuffle/2.2.0/hadoop-mapreduce-client-shuffle-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-jobclient/2.2.0/hadoop-mapreduce-client-jobclient-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-launcher_2.11/2.1.0/spark-launcher_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-network-common_2.11/2.1.0/spark-network-common_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/netty/netty-all/4.0.42.Final/netty-all-4.0.42.Final.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/fusesource/leveldbjni/leveldbjni-all/1.8/leveldbjni-all-1.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/core/jackson-databind/2.6.5/jackson-databind-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/core/jackson-annotations/2.6.5/jackson-annotations-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-network-shuffle_2.11/2.1.0/spark-network-shuffle_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-core/3.1.2/metrics-core-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-unsafe_2.11/2.1.0/spark-unsafe_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/java/dev/jets3t/jets3t/0.7.1/jets3t-0.7.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/curator/curator-recipes/2.4.0/curator-recipes-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/curator/curator-framework/2.4.0/curator-framework-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/curator/curator-client/2.4.0/curator-client-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-math3/3.4.1/commons-math3-3.4.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/jul-to-slf4j/1.7.16/jul-to-slf4j-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/jcl-over-slf4j/1.7.16/jcl-over-slf4j-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/ning/compress-lzf/1.0.3/compress-lzf-1.0.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/jpountz/lz4/lz4/1.3.0/lz4-1.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/roaringbitmap/RoaringBitmap/0.5.11/RoaringBitmap-0.5.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/json4s/json4s-jackson_2.11/3.2.11/json4s-jackson_2.11-3.2.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/json4s/json4s-core_2.11/3.2.11/json4s-core_2.11-3.2.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/json4s/json4s-ast_2.11/3.2.11/json4s-ast_2.11-3.2.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scalap/2.11.0/scalap-2.11.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scala-compiler/2.11.0/scala-compiler-2.11.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-parser-combinators_2.11/1.0.1/scala-parser-combinators_2.11-1.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/core/jersey-client/2.22.2/jersey-client-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/core/jersey-common/2.22.2/jersey-common-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/bundles/repackaged/jersey-guava/2.22.2/jersey-guava-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/hk2-api/2.4.0-b34/hk2-api-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/hk2-utils/2.4.0-b34/hk2-utils-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/external/aopalliance-repackaged/2.4.0-b34/aopalliance-repackaged-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/external/javax.inject/2.4.0-b34/javax.inject-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/hk2-locator/2.4.0-b34/hk2-locator-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/javassist/javassist/3.18.1-GA/javassist-3.18.1-GA.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/osgi-resource-locator/1.0.1/osgi-resource-locator-1.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/core/jersey-server/2.22.2/jersey-server-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/media/jersey-media-jaxb/2.22.2/jersey-media-jaxb-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/containers/jersey-container-servlet/2.22.2/jersey-container-servlet-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/containers/jersey-container-servlet-core/2.22.2/jersey-container-servlet-core-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/clearspring/analytics/stream/2.7.0/stream-2.7.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-jvm/3.1.2/metrics-jvm-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-json/3.1.2/metrics-json-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-graphite/3.1.2/metrics-graphite-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/module/jackson-module-scala_2.11/2.6.5/jackson-module-scala_2.11-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/module/jackson-module-paranamer/2.6.5/jackson-module-paranamer-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/ivy/ivy/2.4.0/ivy-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/oro/oro/2.0.8/oro-2.0.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/razorvine/pyrolite/4.13/pyrolite-4.13.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sf/py4j/py4j/0.10.4/py4j-0.10.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-crypto/1.0.0/commons-crypto-1.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-catalyst_2.11/2.1.0/spark-catalyst_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/janino/janino/3.0.0/janino-3.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/janino/commons-compiler/3.0.0/commons-compiler-3.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/antlr/antlr4-runtime/4.5.3/antlr4-runtime-4.5.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-column/1.8.1/parquet-column-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-common/1.8.1/parquet-common-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-encoding/1.8.1/parquet-encoding-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-hadoop/1.8.1/parquet-hadoop-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-format/2.3.0-incubating/parquet-format-2.3.0-incubating.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-jackson/1.8.1/parquet-jackson-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-streaming_2.11/2.1.0/spark-streaming_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-mllib_2.11/2.1.0/spark-mllib_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-graphx_2.11/2.1.0/spark-graphx_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-mllib-local_2.11/2.1.0/spark-mllib-local_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scalanlp/breeze_2.11/0.12/breeze_2.11-0.12.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scalanlp/breeze-macros_2.11/0.12/breeze-macros_2.11-0.12.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/core/1.1.2/core-1.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sourceforge/f2j/arpack_combined_all/0.1/arpack_combined_all-0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sf/opencsv/opencsv/2.3/opencsv-2.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/rwl/jtransforms/2.4.0/jtransforms-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/spire-math/spire_2.11/0.7.4/spire_2.11-0.7.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/spire-math/spire-macros_2.11/0.7.4/spire-macros_2.11-0.7.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/chuusai/shapeless_2.11/2.0.0/shapeless_2.11-2.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/jpmml/pmml-model/1.2.15/pmml-model-1.2.15.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/jpmml/pmml-schema/1.2.15/pmml-schema-1.2.15.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-osx-x86_64/1.1/netlib-native_ref-osx-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/native_ref-java/1.1/native_ref-java-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/jniloader/1.1/jniloader-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-linux-x86_64/1.1/netlib-native_ref-linux-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-linux-i686/1.1/netlib-native_ref-linux-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-win-x86_64/1.1/netlib-native_ref-win-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-win-i686/1.1/netlib-native_ref-win-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-linux-armhf/1.1/netlib-native_ref-linux-armhf-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-osx-x86_64/1.1/netlib-native_system-osx-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/native_system-java/1.1/native_system-java-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-linux-x86_64/1.1/netlib-native_system-linux-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-linux-i686/1.1/netlib-native_system-linux-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-linux-armhf/1.1/netlib-native_system-linux-armhf-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-win-x86_64/1.1/netlib-native_system-win-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-win-i686/1.1/netlib-native_system-win-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/logging/log4j/log4j-api/2.6.2/log4j-api-2.6.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/logging/log4j/log4j-core/2.6.2/log4j-core-2.6.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-core/3.3.0/jena-core-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-iri/3.3.0/jena-iri-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/xerces/xercesImpl/2.11.0/xercesImpl-2.11.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-base/3.3.0/jena-base-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-shaded-guava/3.3.0/jena-shaded-guava-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-csv/1.3/commons-csv-1.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/andrewoma/dexx/collection/0.6/collection-0.6.jar"/>
+ <classpathentry kind="src" path="/mudrod-web"/>
+ <classpathentry kind="var" path="M2_REPO/junit/junit/4.12/junit-4.12.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/cxf/cxf-rt-frontend-jaxrs/3.1.7/cxf-rt-frontend-jaxrs-3.1.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/cxf/cxf-core/3.1.7/cxf-core-3.1.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/woodstox-core-asl/4.4.1/woodstox-core-asl-4.4.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/woodstox/stax2-api/3.1.4/stax2-api-3.1.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/ws/xmlschema/xmlschema-core/2.2.1/xmlschema-core-2.2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/cxf/cxf-rt-transports-http/3.1.7/cxf-rt-transports-http-3.1.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/cxf/cxf-rt-rs-client/3.1.7/cxf-rt-rs-client-3.1.7.jar"/>
+</classpath>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.project
----------------------------------------------------------------------
diff --git a/service/.project b/service/.project
new file mode 100644
index 0000000..dc371df
--- /dev/null
+++ b/service/.project
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>mudrod-service</name>
+ <comment>Mudrod WebService implementation. NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment>
+ <projects>
+ <project>mudrod-core</project>
+ <project>mudrod-web</project>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ <nature>org.eclipse.wst.jsdt.core.jsNature</nature>
+ </natures>
+</projectDescription>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/.jsdtscope
----------------------------------------------------------------------
diff --git a/service/.settings/.jsdtscope b/service/.settings/.jsdtscope
new file mode 100644
index 0000000..2418123
--- /dev/null
+++ b/service/.settings/.jsdtscope
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry excluding="**/bower_components/*|**/node_modules/*|**/*.min.js" kind="src" path="src/main/webapp"/>
+ <classpathentry kind="src" path="target/m2e-wtp/web-resources"/>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
+ <attributes>
+ <attribute name="hide" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
+ <classpathentry kind="output" path=""/>
+</classpath>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.core.resources.prefs
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.core.resources.prefs b/service/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..abdea9a
--- /dev/null
+++ b/service/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding/<project>=UTF-8
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.jdt.core.prefs b/service/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..6e80039
--- /dev/null
+++ b/service/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.8
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.m2e.core.prefs b/service/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/service/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.wst.common.component
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.wst.common.component b/service/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..8255907
--- /dev/null
+++ b/service/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="mudrod-service-0.0.1-SNAPSHOT">
+ <wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
+ <wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
+ <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
+ <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
+ <dependent-module archiveName="mudrod-core-0.0.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/mudrod-core/mudrod-core">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="mudrod-web-0.0.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/mudrod-web/mudrod-web">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <property name="context-root" value="mudrod-service"/>
+ <property name="java-output-path" value="/mudrod-service/target/classes"/>
+ </wb-module>
+</project-modules>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/service/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..cc81385
--- /dev/null
+++ b/service/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,7 @@
+<root>
+ <facet id="jst.jaxrs">
+ <node name="libprov">
+ <attribute name="provider-id" value="jaxrs-no-op-library-provider"/>
+ </node>
+ </facet>
+</root>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.wst.common.project.facet.core.xml
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.wst.common.project.facet.core.xml b/service/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..fac1799
--- /dev/null
+++ b/service/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <fixed facet="wst.jsdt.web"/>
+ <installed facet="java" version="1.8"/>
+ <installed facet="jst.web" version="3.0"/>
+ <installed facet="jst.jaxrs" version="2.0"/>
+ <installed facet="wst.jsdt.web" version="1.0"/>
+</faceted-project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.wst.jsdt.ui.superType.container
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.wst.jsdt.ui.superType.container b/service/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/service/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.wst.jsdt.ui.superType.name
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.wst.jsdt.ui.superType.name b/service/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 0000000..05bd71b
--- /dev/null
+++ b/service/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/.settings/org.eclipse.wst.validation.prefs
----------------------------------------------------------------------
diff --git a/service/.settings/org.eclipse.wst.validation.prefs b/service/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 0000000..04cad8c
--- /dev/null
+++ b/service/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,2 @@
+disabled=06target
+eclipse.preferences.version=1
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/lib/all-1.1.2.pom
----------------------------------------------------------------------
diff --git a/service/lib/all-1.1.2.pom b/service/lib/all-1.1.2.pom
new file mode 100644
index 0000000..577dd32
--- /dev/null
+++ b/service/lib/all-1.1.2.pom
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.github.fommil.netlib</groupId>
+ <artifactId>parent</artifactId>
+ <version>1.1</version>
+ </parent>
+
+ <artifactId>all</artifactId>
+ <packaging>pom</packaging>
+ <version>1.1.2</version>
+
+ <dependencies>
+ <dependency>
+ <!-- WORKAROUND: https://github.com/sbt/sbt/issues/861 -->
+ <groupId>net.sourceforge.f2j</groupId>
+ <artifactId>arpack_combined_all</artifactId>
+ <version>0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>core</artifactId>
+ <version>1.1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-osx-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-linux-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-linux-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-win-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-win-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-linux-armhf</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-osx-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-linux-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-linux-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-linux-armhf</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-win-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-win-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/lib/apache-jena-libs-3.1.0.pom
----------------------------------------------------------------------
diff --git a/service/lib/apache-jena-libs-3.1.0.pom b/service/lib/apache-jena-libs-3.1.0.pom
new file mode 100644
index 0000000..3fdb874
--- /dev/null
+++ b/service/lib/apache-jena-libs-3.1.0.pom
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
+ license agreements. See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership. The ASF licenses this file to
+ You under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of
+ the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
+ by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ OF ANY KIND, either express or implied. See the License for the specific
+ language governing permissions and limitations under the License. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>apache-jena-libs</artifactId>
+ <packaging>pom</packaging>
+ <name>Apache Jena - Libraries POM</name>
+ <version>3.1.0</version>
+
+ <parent>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-parent</artifactId>
+ <version>16</version>
+ <relativePath>../jena-parent</relativePath>
+ </parent>
+
+ <!-- Need if the parent is a snapshot -->
+ <repositories>
+ <repository>
+ <id>apache.snapshots</id>
+ <name>Apache Snapshot Repository</name>
+ <url>http://repository.apache.org/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ </repository>
+ </repositories>
+
+ <description>A convenience POM artifact that may be referenced to pull in all the standard Jena Libraries (Core, ARQ, IRI, and TDB) with a single dependency.</description>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-tdb</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/mudrod_service.log
----------------------------------------------------------------------
diff --git a/service/mudrod_service.log b/service/mudrod_service.log
new file mode 100644
index 0000000..0279492
--- /dev/null
+++ b/service/mudrod_service.log
@@ -0,0 +1,83 @@
+2017-05-23 13:13:44,494 INFO main.MudrodEngine - File specified by environment variable MUDROD_CONFIG='' could not be loaded. (No such file or directory)
+2017-05-23 13:13:44,497 INFO main.MudrodEngine - Loaded config file from file:/Users/lmcgibbn/.m2/repository/gov/nasa/jpl/mudrod/mudrod-core/0.0.1-SNAPSHOT/mudrod-core-0.0.1-SNAPSHOT.jar!/config.xml
+2017-05-23 13:13:47,139 WARN util.NativeCodeLoader - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
+2017-05-23 13:13:47,244 WARN util.Utils - Your hostname, LMC-056430 resolves to a loopback address: 127.0.0.1; using 192.168.1.76 instead (on interface en0)
+2017-05-23 13:13:47,245 WARN util.Utils - Set SPARK_LOCAL_IP if you need to bind to another address
+2017-05-23 13:13:47,755 INFO util.log - Logging initialized @122745ms
+2017-05-23 13:13:47,839 INFO server.Server - jetty-9.2.z-SNAPSHOT
+2017-05-23 13:13:47,855 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@72d7c0c7{/jobs,null,AVAILABLE}
+2017-05-23 13:13:47,855 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@24d27ecb{/jobs/json,null,AVAILABLE}
+2017-05-23 13:13:47,856 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@f9f0007{/jobs/job,null,AVAILABLE}
+2017-05-23 13:13:47,856 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@1877f689{/jobs/job/json,null,AVAILABLE}
+2017-05-23 13:13:47,856 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@546adcb8{/stages,null,AVAILABLE}
+2017-05-23 13:13:47,856 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@63f9c4d8{/stages/json,null,AVAILABLE}
+2017-05-23 13:13:47,856 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@14916f98{/stages/stage,null,AVAILABLE}
+2017-05-23 13:13:47,857 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@33f5003d{/stages/stage/json,null,AVAILABLE}
+2017-05-23 13:13:47,857 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@31f895e7{/stages/pool,null,AVAILABLE}
+2017-05-23 13:13:47,858 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@1c8a5804{/stages/pool/json,null,AVAILABLE}
+2017-05-23 13:13:47,858 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@37819a2{/storage,null,AVAILABLE}
+2017-05-23 13:13:47,858 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@18170518{/storage/json,null,AVAILABLE}
+2017-05-23 13:13:47,858 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@6d35ec50{/storage/rdd,null,AVAILABLE}
+2017-05-23 13:13:47,859 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@2331c38a{/storage/rdd/json,null,AVAILABLE}
+2017-05-23 13:13:47,859 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@60476b47{/environment,null,AVAILABLE}
+2017-05-23 13:13:47,859 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@40589d92{/environment/json,null,AVAILABLE}
+2017-05-23 13:13:47,859 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@24daea5{/executors,null,AVAILABLE}
+2017-05-23 13:13:47,859 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@2f4d10f5{/executors/json,null,AVAILABLE}
+2017-05-23 13:13:47,859 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@740b5b08{/executors/threadDump,null,AVAILABLE}
+2017-05-23 13:13:47,860 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@703bec16{/executors/threadDump/json,null,AVAILABLE}
+2017-05-23 13:13:47,864 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@1f6c4c32{/static,null,AVAILABLE}
+2017-05-23 13:13:47,865 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@58e12d92{/,null,AVAILABLE}
+2017-05-23 13:13:47,865 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@761cfe9d{/api,null,AVAILABLE}
+2017-05-23 13:13:47,865 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@5968e714{/jobs/job/kill,null,AVAILABLE}
+2017-05-23 13:13:47,865 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@24982dd7{/stages/stage/kill,null,AVAILABLE}
+2017-05-23 13:13:47,870 INFO server.ServerConnector - Started ServerConnector@51802db6{HTTP/1.1}{0.0.0.0:4040}
+2017-05-23 13:13:47,870 INFO server.Server - Started @122861ms
+2017-05-23 13:13:48,164 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@3c955f63{/metrics/json,null,AVAILABLE}
+2017-05-23 13:13:49,245 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@3e265583{/SQL,null,AVAILABLE}
+2017-05-23 13:13:49,246 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@246c4e78{/SQL/json,null,AVAILABLE}
+2017-05-23 13:13:49,246 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@244de4dd{/SQL/execution,null,AVAILABLE}
+2017-05-23 13:13:49,246 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@531cd63f{/SQL/execution/json,null,AVAILABLE}
+2017-05-23 13:13:49,247 INFO handler.ContextHandler - Started o.s.j.s.ServletContextHandler@4d6227e0{/static/sql,null,AVAILABLE}
+2017-05-23 13:13:49,286 INFO util.Version - Elasticsearch Hadoop v5.2.0 [d85a257f9f]
+2017-05-23 13:13:51,980 WARN hadoop.ParquetRecordReader - Can not initialize counter due to context is not a instance of TaskInputOutputContext, but is org.apache.hadoop.mapreduce.task.TaskAttemptContextImpl
+2017-05-23 13:13:52,299 INFO ontology.OntologyFactory - Using ontology extension: Local
+2017-05-23 13:13:52,302 INFO process.LocalOntology - Creating new ontology
+2017-05-23 13:13:52,692 WARN impl.RDFDefaultErrorHandler - unknown-source: {W136} Relative URIs are not permitted in RDF: specifically <ont-policy.rdf>
+2017-05-23 13:22:10,558 WARN utils.JAXRSUtils - No operation matching request path "/mudrod-service/services/ontology/subclasses" is found, Relative Path: /subclasses, HTTP Method: GET, ContentType: */*, Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,. Please enable FINE/TRACE log level for more details.
+2017-05-23 13:22:10,578 WARN impl.WebApplicationExceptionMapper - javax.ws.rs.ClientErrorException: HTTP 404 Not Found
+ at org.apache.cxf.jaxrs.utils.SpecExceptions.toHttpException(SpecExceptions.java:117)
+ at org.apache.cxf.jaxrs.utils.ExceptionUtils.toHttpException(ExceptionUtils.java:169)
+ at org.apache.cxf.jaxrs.utils.JAXRSUtils.findTargetMethod(JAXRSUtils.java:529)
+ at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:177)
+ at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:77)
+ at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
+ at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
+ at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:254)
+ at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
+ at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
+ at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
+ at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:180)
+ at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299)
+ at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:223)
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
+ at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:274)
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
+ at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
+ at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
+ at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
+ at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
+ at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
+ at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
+ at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
+ at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
+ at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
+ at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
+ at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
+ at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
+ at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
+ at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
+ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
+ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
+ at java.lang.Thread.run(Thread.java:745)
+
[21/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
SDAP-1 Import all code under the SDAP SGA
Project: http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/commit/7b76fa16
Tree: http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/tree/7b76fa16
Diff: http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/diff/7b76fa16
Branch: refs/heads/master
Commit: 7b76fa16848fed24ba3a10abb53049de0985d84f
Parents:
Author: Lewis John McGibbney <le...@gmail.com>
Authored: Fri Oct 27 15:34:34 2017 -0700
Committer: Lewis John McGibbney <le...@gmail.com>
Committed: Fri Oct 27 15:34:34 2017 -0700
----------------------------------------------------------------------
LICENSE-2.0.txt | 202 ++
README.md | 141 ++
codecov.yml | 27 +
core/.classpath | 224 ++
.../Maven_Ant_Builder.launch | 25 +
core/.project | 36 +
core/.settings/org.eclipse.core.resources.prefs | 4 +
core/.settings/org.eclipse.jdt.core.prefs | 8 +
core/.settings/org.eclipse.m2e.core.prefs | 4 +
core/.settings/org.eclipse.wst.common.component | 8 +
...rg.eclipse.wst.common.project.facet.core.xml | 5 +
core/lib/all-1.1.2.pom | 102 +
core/lib/apache-jena-libs-3.1.0.pom | 51 +
core/maven-eclipse.xml | 8 +
core/mudrod.log | 81 +
core/mudrod.log.2017-06-14 | 9 +
core/pom.xml | 324 +++
core/src/main/assembly/bin.xml | 50 +
core/src/main/assembly/zipSVMWithSGDModel.xml | 30 +
.../DiscoveryEngineAbstract.java | 46 +
.../discoveryengine/DiscoveryStepAbstract.java | 50 +
.../MetadataDiscoveryEngine.java | 75 +
.../mudrod/discoveryengine/MudrodAbstract.java | 108 +
.../OntologyDiscoveryEngine.java | 71 +
.../mudrod/discoveryengine/RecommendEngine.java | 77 +
.../discoveryengine/WeblogDiscoveryEngine.java | 199 ++
.../mudrod/discoveryengine/package-info.java | 19 +
.../gov/nasa/jpl/mudrod/driver/ESDriver.java | 572 +++++
.../gov/nasa/jpl/mudrod/driver/SparkDriver.java | 95 +
.../nasa/jpl/mudrod/driver/package-info.java | 18 +
.../mudrod/integration/LinkageIntegration.java | 324 +++
.../jpl/mudrod/integration/package-info.java | 18 +
.../nasa/jpl/mudrod/main/MudrodConstants.java | 123 +
.../gov/nasa/jpl/mudrod/main/MudrodEngine.java | 457 ++++
.../gov/nasa/jpl/mudrod/main/package-info.java | 17 +
.../nasa/jpl/mudrod/metadata/package-info.java | 18 +
.../jpl/mudrod/metadata/pre/ApiHarvester.java | 177 ++
.../mudrod/metadata/pre/MatrixGenerator.java | 85 +
.../jpl/mudrod/metadata/pre/package-info.java | 17 +
.../metadata/process/MetadataAnalyzer.java | 88 +
.../mudrod/metadata/process/package-info.java | 17 +
.../metadata/structure/MetadataExtractor.java | 145 ++
.../metadata/structure/PODAACMetadata.java | 337 +++
.../mudrod/metadata/structure/package-info.java | 17 +
.../gov/nasa/jpl/mudrod/ontology/Ontology.java | 67 +
.../jpl/mudrod/ontology/OntologyFactory.java | 83 +
.../nasa/jpl/mudrod/ontology/package-info.java | 17 +
.../mudrod/ontology/pre/AggregateTriples.java | 225 ++
.../jpl/mudrod/ontology/pre/package-info.java | 17 +
.../ontology/process/EsipCOROntology.java | 69 +
.../ontology/process/EsipPortalOntology.java | 72 +
.../mudrod/ontology/process/LocalOntology.java | 392 +++
.../ontology/process/OntologyLinkCal.java | 113 +
.../mudrod/ontology/process/OntologyParser.java | 47 +
.../jpl/mudrod/ontology/process/OwlParser.java | 171 ++
.../mudrod/ontology/process/package-info.java | 17 +
.../jpl/mudrod/recommendation/package-info.java | 18 +
.../recommendation/pre/ImportMetadata.java | 111 +
.../pre/MetadataTFIDFGenerator.java | 100 +
.../recommendation/pre/NormalizeVariables.java | 223 ++
.../recommendation/pre/SessionCooccurence.java | 152 ++
.../mudrod/recommendation/pre/package-info.java | 17 +
.../process/AbstractBasedSimilarity.java | 74 +
.../process/VariableBasedSimilarity.java | 380 +++
.../recommendation/process/package-info.java | 17 +
.../recommendation/process/sessionBasedCF.java | 74 +
.../structure/HybridRecommendation.java | 274 ++
.../recommendation/structure/MetadataOpt.java | 150 ++
.../recommendation/structure/RecomData.java | 196 ++
.../recommendation/structure/package-info.java | 17 +
.../nasa/jpl/mudrod/semantics/SVDAnalyzer.java | 72 +
.../jpl/mudrod/semantics/SemanticAnalyzer.java | 148 ++
.../nasa/jpl/mudrod/semantics/package-info.java | 18 +
.../jpl/mudrod/ssearch/ClickstreamImporter.java | 114 +
.../gov/nasa/jpl/mudrod/ssearch/Dispatcher.java | 128 +
.../gov/nasa/jpl/mudrod/ssearch/Ranker.java | 192 ++
.../gov/nasa/jpl/mudrod/ssearch/Searcher.java | 282 +++
.../nasa/jpl/mudrod/ssearch/package-info.java | 18 +
.../mudrod/ssearch/ranking/DataGenerator.java | 313 +++
.../jpl/mudrod/ssearch/ranking/Evaluator.java | 145 ++
.../jpl/mudrod/ssearch/ranking/Learner.java | 60 +
.../mudrod/ssearch/ranking/SparkFormatter.java | 55 +
.../jpl/mudrod/ssearch/ranking/SparkSVM.java | 49 +
.../ssearch/ranking/TrainingImporter.java | 91 +
.../mudrod/ssearch/ranking/package-info.java | 18 +
.../jpl/mudrod/ssearch/structure/SResult.java | 183 ++
.../mudrod/ssearch/structure/package-info.java | 17 +
.../jpl/mudrod/utils/ESTransportClient.java | 55 +
.../gov/nasa/jpl/mudrod/utils/HttpRequest.java | 61 +
.../nasa/jpl/mudrod/utils/LabeledRowMatrix.java | 38 +
.../nasa/jpl/mudrod/utils/LinkageTriple.java | 192 ++
.../gov/nasa/jpl/mudrod/utils/MatrixUtil.java | 488 ++++
.../java/gov/nasa/jpl/mudrod/utils/RDDUtil.java | 53 +
.../java/gov/nasa/jpl/mudrod/utils/SVDUtil.java | 118 +
.../nasa/jpl/mudrod/utils/SimilarityUtil.java | 277 ++
.../gov/nasa/jpl/mudrod/utils/package-info.java | 18 +
.../nasa/jpl/mudrod/weblog/package-info.java | 18 +
.../partition/KGreedyPartitionSolver.java | 142 ++
.../partition/ThePartitionProblemSolver.java | 8 +
.../mudrod/weblog/partition/logPartitioner.java | 33 +
.../mudrod/weblog/pre/ClickStreamGenerator.java | 74 +
.../jpl/mudrod/weblog/pre/CrawlerDetection.java | 252 ++
.../jpl/mudrod/weblog/pre/HistoryGenerator.java | 139 +
.../jpl/mudrod/weblog/pre/ImportLogFile.java | 343 +++
.../nasa/jpl/mudrod/weblog/pre/LogAbstract.java | 228 ++
.../weblog/pre/RankingTrainDataGenerator.java | 54 +
.../jpl/mudrod/weblog/pre/RemoveRawLog.java | 56 +
.../jpl/mudrod/weblog/pre/SessionGenerator.java | 452 ++++
.../jpl/mudrod/weblog/pre/SessionStatistic.java | 312 +++
.../jpl/mudrod/weblog/pre/package-info.java | 18 +
.../weblog/process/ClickStreamAnalyzer.java | 79 +
.../weblog/process/UserHistoryAnalyzer.java | 66 +
.../jpl/mudrod/weblog/process/package-info.java | 17 +
.../weblog/structure/ApacheAccessLog.java | 129 +
.../mudrod/weblog/structure/ClickStream.java | 188 ++
.../mudrod/weblog/structure/Coordinates.java | 21 +
.../jpl/mudrod/weblog/structure/FtpLog.java | 64 +
.../nasa/jpl/mudrod/weblog/structure/GeoIp.java | 46 +
.../weblog/structure/RankingTrainData.java | 147 ++
.../jpl/mudrod/weblog/structure/RequestUrl.java | 294 +++
.../jpl/mudrod/weblog/structure/Session.java | 287 +++
.../weblog/structure/SessionExtractor.java | 532 ++++
.../mudrod/weblog/structure/SessionNode.java | 344 +++
.../mudrod/weblog/structure/SessionTree.java | 521 ++++
.../jpl/mudrod/weblog/structure/WebLog.java | 89 +
.../mudrod/weblog/structure/package-info.java | 17 +
core/src/main/resources/config.xml | 129 +
core/src/main/resources/elastic_mappings.json | 68 +
core/src/main/resources/elastic_settings.json | 36 +
.../resources/javaSVMWithSGDModel/data/_SUCCESS | 0
.../javaSVMWithSGDModel/data/_common_metadata | Bin 0 -> 1022 bytes
.../javaSVMWithSGDModel/data/_metadata | Bin 0 -> 1757 bytes
...8ae03-6b61-4931-ba29-27304de5a584.gz.parquet | Bin 0 -> 1806 bytes
.../javaSVMWithSGDModel/metadata/_SUCCESS | 0
.../javaSVMWithSGDModel/metadata/part-00000 | 1 +
core/src/main/resources/log4j.properties | 63 +
core/src/main/resources/log4j2.properties | 63 +
.../nasa/jpl/mudrod/main/TestMudrodEngine.java | 303 +++
.../ontology/process/TestLocalOntology.java | 226 ++
docker/Dockerfile | 105 +
docker/README.md | 52 +
docker/config/elasticsearch.yml | 5 +
docker/run_services.sh | 17 +
eclipse-codeformat.xml | 773 ++++++
pom.xml | 556 ++++
service/.classpath | 230 ++
service/.project | 31 +
service/.settings/.jsdtscope | 13 +
.../.settings/org.eclipse.core.resources.prefs | 4 +
service/.settings/org.eclipse.jdt.core.prefs | 8 +
service/.settings/org.eclipse.m2e.core.prefs | 4 +
.../.settings/org.eclipse.wst.common.component | 16 +
...ipse.wst.common.project.facet.core.prefs.xml | 7 +
...rg.eclipse.wst.common.project.facet.core.xml | 8 +
.../org.eclipse.wst.jsdt.ui.superType.container | 1 +
.../org.eclipse.wst.jsdt.ui.superType.name | 1 +
.../.settings/org.eclipse.wst.validation.prefs | 2 +
service/lib/all-1.1.2.pom | 102 +
service/lib/apache-jena-libs-3.1.0.pom | 51 +
service/mudrod_service.log | 83 +
service/mudrod_service.log.2016-10-13 | 1064 ++++++++
service/pom.xml | 258 ++
.../main/assembly/LICENSE-server-embedded.txt | 219 ++
service/src/main/assembly/LICENSE-with-deps.txt | 217 ++
.../src/main/assembly/LICENSE-without-deps.txt | 206 ++
.../main/assembly/NOTICE-server-embedded.txt | 4 +
service/src/main/assembly/NOTICE-with-deps.txt | 6 +
.../src/main/assembly/NOTICE-without-deps.txt | 4 +
service/src/main/assembly/README.txt | 110 +
.../src/main/assembly/prepare-war-legals.xml | 48 +
service/src/main/assembly/server-embedded.xml | 87 +
service/src/main/assembly/with-deps.xml | 59 +
service/src/main/assembly/without-deps.xml | 56 +
service/src/main/bin/mudrodserver | 87 +
service/src/main/bin/mudrodserver.bat | 102 +
.../mudrod/services/DefaultExceptionMapper.java | 45 +
.../mudrod/services/MudrodContextListener.java | 73 +
.../services/autocomplete/AutoCompleteData.java | 34 +
.../autocomplete/AutoCompleteResource.java | 65 +
.../services/autocomplete/package-info.java | 17 +
.../services/ontology/OntologyResource.java | 88 +
.../mudrod/services/ontology/package-info.java | 17 +
.../nasa/jpl/mudrod/services/package-info.java | 17 +
.../HybridRecomDatasetsResource.java | 59 +
.../recommendation/RecomDatasetsResource.java | 60 +
.../services/recommendation/package-info.java | 17 +
.../search/SearchDatasetDetailResource.java | 71 +
.../services/search/SearchMetadataResource.java | 73 +
.../services/search/SearchVocabResource.java | 65 +
.../services/search/SessionDetailResource.java | 69 +
.../mudrod/services/search/package-info.java | 17 +
service/src/main/resources/log4j.properties | 63 +
service/src/main/webapp/META-INF/context.xml | 18 +
service/src/main/webapp/WEB-INF/web.xml | 55 +
sonar-project.properties | 25 +
web/.classpath | 6 +
web/.project | 31 +
web/.settings/org.eclipse.jdt.core.prefs | 8 +
web/.settings/org.eclipse.m2e.core.prefs | 4 +
web/.settings/org.eclipse.wst.common.component | 6 +
...rg.eclipse.wst.common.project.facet.core.xml | 5 +
web/META-INF/resources/css/footer.css | 19 +
web/META-INF/resources/css/index.css | 445 ++++
web/META-INF/resources/css/main-header.css | 19 +
.../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes
.../fonts/glyphicons-halflings-regular.svg | 550 ++++
.../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes
.../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes
.../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes
web/META-INF/resources/images/OceanWave.jpg | Bin 0 -> 862628 bytes
web/META-INF/resources/images/searching.png | Bin 0 -> 3306 bytes
web/META-INF/resources/images/spinner.gif | Bin 0 -> 310431 bytes
web/META-INF/resources/images/sprite.png | Bin 0 -> 2023 bytes
web/META-INF/resources/index.html | 60 +
web/META-INF/resources/js/app.js | 49 +
web/META-INF/resources/js/controllers.js | 210 ++
.../resources/js/libs/angular-cookies.min.js | 8 +
web/META-INF/resources/js/libs/angular-mocks.js | 2382 ++++++++++++++++++
.../resources/js/libs/angular-resource.min.js | 13 +
.../resources/js/libs/angular-route.min.js | 15 +
web/META-INF/resources/js/libs/angular.min.js | 250 ++
web/META-INF/resources/js/libs/bootstrap.min.js | 7 +
.../resources/js/libs/jquery-1.10.2.min.js | 6 +
.../resources/js/libs/underscore-min.js | 6 +
web/META-INF/resources/js/services.js | 127 +
.../resources/partials/datasetResults.html | 152 ++
web/META-INF/resources/partials/footer.html | 19 +
.../resources/partials/main-header.html | 19 +
.../resources/partials/metadataResults.html | 50 +
.../resources/partials/navbar-plain.html | 35 +
.../resources/partials/navbar-search.html | 62 +
.../resources/partials/search-in-progress.html | 12 +
.../resources/partials/search-results.html | 116 +
web/META-INF/resources/partials/search.html | 58 +
web/pom.xml | 50 +
235 files changed, 27007 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/LICENSE-2.0.txt
----------------------------------------------------------------------
diff --git a/LICENSE-2.0.txt b/LICENSE-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c606271
--- /dev/null
+++ b/README.md
@@ -0,0 +1,141 @@
+# MUDROD
+## Mining and Utilizing Dataset Relevancy from Oceanographic Datasets to Improve Data Discovery and Access
+
+[](http://www.apache.org/licenses/LICENSE-2.0)
+[](https://travis-ci.org/mudrod/mudrod)
+[](https://hub.docker.com/r/mudrod/mudrod/) [](https://microbadger.com/images/mudrod/mudrod "Get your own image badge on microbadger.com")
+[](https://codecov.io/gh/mudrod/mudrod)
+[](https://sonarqube.com/dashboard/index/gov.nasa.jpl.mudrod:mudrod-parent)
+
+<img src="http://geant4.slac.stanford.edu/Space06/NASAJPLlogo.jpg" align="right" width="300" />
+<img src="http://www.iucrc.org/sites/default/files/centerLogo.png" align="right" width="170" />
+
+[MUDROD](https://esto.nasa.gov/forum/estf2015/presentations/Yang_S8P1_ESTF2015.pdf)
+is a semantic discovery and search project funded by NASA AIST (NNX15AM85G).
+
+# Software requirements:
+ * Java 8
+ * Git
+ * Apache Maven 3.X
+ * Elasticsearch v5.X
+ * Kibana v4
+ * Apache Spark v2.0.0
+ * Apache Tomcat 7.X
+
+# Installation
+
+## Docker Container
+We strongly advise all users to save time and effort by consulting the [Dockerfile documentation](https://github.com/mudrod/mudrod/tree/master/docker)
+for guidance on how to quickly use Docker to deploy Mudrod.
+
+## From source
+1. Ensure you have Elasticsearch running locally and that the configuration in [config.xml](https://github.com/mudrod/mudrod/blob/master/core/src/main/resources/config.xml) reflects your ES cluster.
+2. Update the `svmSgdModel` configuration option in [config.xml](https://github.com/mudrod/mudrod/blob/master/core/src/main/resources/config.xml). There is a line in config.xml that looks like
+ ```
+ <para name="svmSgdModel">file://YOUNEEDTOCHANGETHIS</para>
+ ```
+ It needs to be changed to an absolute filepath on your system. For example:
+ ```
+ <para name="svmSgdModel">file:///Users/user/githubprojects/mudrod/core/src/main/resources/javaSVMWithSGDModel</para>
+ ```
+3. (Optional) Depending on your computer's configuration you might run into an error when starting the application: `“Service 'sparkDriver' could not bind on port 0”`. The easiest [fix](http://stackoverflow.com/q/29906686/953327) is to export the environment variable `SPARK_LOCAL_IP=127.0.0.1 ` and then start the service.
+
+```
+$ git clone https://github.com/mudrod/mudrod.git
+$ cd mudrod
+$ mvn clean install
+$ cd service
+$ mvn tomcat7:run
+```
+You will now be able to access the Mudrod Web Application at [http://localhost:8080/mudrod-service](http://localhost:8080/mudrod-service). **N.B.** The service should not be run this way in production.
+
+# Documentation
+
+In another window...
+```
+$ cd mudrod
+$ ./core/target/appassembler/bin/mudrod-engine -h
+usage: MudrodEngine: 'logDir' argument is mandatory. User must also
+ provide an ingest method. [-a] [-esHost <host_name>] [-esPort
+ <port_num>] [-esTCPPort <port_num>] [-f] [-h] [-l] -logDir
+ </path/to/log/directory> [-p] [-s] [-v]
+ -a,--addSimFromMetadataAndOnto begin adding
+ metadata and
+ ontology results
+ -esHost,--elasticSearchHost <host_name> elasticsearch
+ cluster unicast
+ host
+ -esPort,--elasticSearchHTTPPort <port_num> elasticsearch
+ HTTP/REST port
+ -esTCPPort,--elasticSearchTransportTCPPort <port_num> elasticsearch
+ transport TCP
+ port
+ -f,--fullIngest begin full ingest
+ Mudrod workflow
+ -h,--help show this help
+ message
+ -l,--logIngest begin log ingest
+ without any
+ processing only
+ -logDir,--logDirectory </path/to/log/directory> the log directory
+ to be processed
+ by Mudrod
+ -p,--processingWithPreResults begin processing
+ with
+ preprocessing
+ results
+ -s,--sessionReconstruction begin session
+ reconstruction
+ -v,--vocabSimFromLog begin similarity
+ calulation from
+ web log Mudrod
+ workflow
+```
+
+## Deploying to Apache Tomcat (or any other Servlet container)
+Once you have built the codebase as above, merely copy the genrated .war artifact to the servlet deployment directory. In Tomcat (for example), this would look as follows
+```
+$ cp mudrod/service/target/mudrod-service-${version}-SNAPSHOT.war $CATALINA_HOME/webapps/
+```
+Once Tomcat hot deploys the .war artifact, you will be able to browse to the running application similar to what is shown above [http://localhost:8080/mudrod-service](http://localhost:8080/mudrod-service)
+
+# Publications
+* Jiang, Y., Li, Y., Yang, C., Liu, K., Armstrong, E.M., Huang, T., Moroni, D.F. and Finch, C.J., 2017. [A comprehensive methodology for discovering semantic relationships among geospatial vocabularies using oceanographic data discovery as an example](http://www.tandfonline.com/eprint/JgGYJBk4mhdt5NFjEx8f/full). International Journal of Geographical Information Science, pp.1-19.
+* Jiang, Y., Y. Li, C. Yang, K. Liu, E. M. Armstrong, T. Huang, D. Moroni & L. Mcgibbney (2016) Towards intelligent geospatial discovery: a machine learning ranking framework (Accepted). International Journal of Digital Earth
+* Jiang, Y., Y. Li, C. Yang, E. M. Armstrong, T. Huang & D. Moroni (2016) [Reconstructing Sessions from Data Discovery and Access Logs to Build a Semantic Knowledge Base for Improving Data Discovery](http://www.mdpi.com/2220-9964/5/5/54#stats ). ISPRS International Journal of Geo-Information, 5, 54.
+* Y. Li, Jiang, Y., C. Yang, K. Liu, E. M. Armstrong, T. Huang & D. Moroni (2016) Leverage cloud computing to improve data access log mining. IEEE Oceans 2016.
+
+## Mudrod Wiki
+
+https://github.com/mudrod/mudrod/wiki
+
+## Java API Documentation
+
+```
+$ mvn javadoc:aggregate
+$ open target/site/apidocs/index.html
+```
+
+## REST API Documentation
+
+```
+$ mvn clean install
+$ open service/target/miredot/index.html
+```
+The REST API documentation can also be seen at [https://mudrod.github.io/miredot](https://mudrod.github.io/miredot).
+
+# Team members:
+
+ * Chaowei (Phil) Yang - [NSF Spatiotemporal Innovation Center](http://stcenter.net/), George Mason University
+ * [Yongyao Jiang](https://www.linkedin.com/in/yongyao-jiang-42516164) - [NSF Spatiotemporal Innovation Center](http://stcenter.net/), George Mason University
+ * Yun Li - [NSF Spatiotemporal Innovation Center](http://stcenter.net/), George Mason University
+ * Edward M Armstrong - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov)
+ * Thomas Huang - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov)
+ * David Moroni - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov)
+ * Chris Finch - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov)
+ * [Lewis John Mcgibbney](https://www.linkedin.com/in/lmcgibbney) - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov)
+ * [Frank Greguska](https://www.linkedin.com/in/frankgreguska/) - [Jet Propulsion Laboratory](http://www.jpl.nasa.gov/), [NASA](http://www.nasa.gov)
+
+# License
+This source code is licensed under the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0), a
+copy of which is shipped with this project.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/codecov.yml
----------------------------------------------------------------------
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000..e77a686
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,27 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0 Unless
+#
+# required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS"
+# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language
+# governing permissions and limitations under the License.
+
+coverage:
+ precision: 2
+ round: down
+ range: "70...100"
+
+ status:
+ project: yes
+
+ patch: yes
+
+ changes: yes
+
+comment:
+ layout: "header, diff, changes"
+ behavior: default
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.classpath
----------------------------------------------------------------------
diff --git a/core/.classpath b/core/.classpath
new file mode 100644
index 0000000..ac5dfed
--- /dev/null
+++ b/core/.classpath
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/test/java" output="target/test-classes" including="**/*.java"/>
+ <classpathentry kind="src" path="src/main/java" including="**/*.java"/>
+ <classpathentry kind="src" path="src/main/resources" excluding="javaSVMWithSGDModel/**|**/*.java"/>
+ <classpathentry kind="src" path="target" including="javaSVMWithSGDModel.zip" excluding="**/*.java"/>
+ <classpathentry kind="src" path="/usr/local/mudrod" including="LICENSE.txt|NOTICE.txt" excluding="**/*.java"/>
+ <classpathentry kind="output" path="target/classes"/>
+ <classpathentry kind="var" path="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/javax/ws/rs/javax.ws.rs-api/2.0.1/javax.ws.rs-api-2.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/javax/validation/validation-api/1.1.0.Final/validation-api-1.1.0.Final.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/code/gson/gson/2.5/gson-2.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/jdom/jdom/2.0.2/jdom-2.0.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/elasticsearch/5.2.0/elasticsearch-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-core/6.4.0/lucene-core-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-analyzers-common/6.4.0/lucene-analyzers-common-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-backward-codecs/6.4.0/lucene-backward-codecs-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-grouping/6.4.0/lucene-grouping-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-highlighter/6.4.0/lucene-highlighter-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-join/6.4.0/lucene-join-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-memory/6.4.0/lucene-memory-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-misc/6.4.0/lucene-misc-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-queries/6.4.0/lucene-queries-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-queryparser/6.4.0/lucene-queryparser-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-sandbox/6.4.0/lucene-sandbox-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-spatial/6.4.0/lucene-spatial-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-spatial-extras/6.4.0/lucene-spatial-extras-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-spatial3d/6.4.0/lucene-spatial3d-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-suggest/6.4.0/lucene-suggest-6.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/securesm/1.1/securesm-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sf/jopt-simple/jopt-simple/5.0.2/jopt-simple-5.0.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/carrotsearch/hppc/0.7.1/hppc-0.7.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/joda-time/joda-time/2.9.4/joda-time-2.9.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/yaml/snakeyaml/1.15/snakeyaml-1.15.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.8.6/jackson-core-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-smile/2.8.6/jackson-dataformat-smile-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.8.6/jackson-dataformat-yaml-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.8.6/jackson-dataformat-cbor-2.8.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/tdunning/t-digest/3.0/t-digest-3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/hdrhistogram/HdrHistogram/2.1.6/HdrHistogram-2.1.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/java/dev/jna/jna/4.2.2/jna-4.2.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/client/transport/5.2.0/transport-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/transport-netty3-client/5.2.0/transport-netty3-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/netty/netty/3.8.0.Final/netty-3.8.0.Final.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/reindex-client/5.2.0/reindex-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/client/rest/5.2.0/rest-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpcore/4.4.5/httpcore-4.4.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpasyncclient/4.1.2/httpasyncclient-4.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/httpcomponents/httpcore-nio/4.4.5/httpcore-nio-4.4.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.3/commons-codec-1.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/lang-mustache-client/5.2.0/lang-mustache-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/spullara/mustache/java/compiler/0.9.3/compiler-0.9.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/plugin/percolator-client/5.2.0/percolator-client-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/elasticsearch/elasticsearch-spark-20_2.11/5.2.0/elasticsearch-spark-20_2.11-5.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-sql_2.11/2.1.0/spark-sql_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/univocity/univocity-parsers/2.2.1/univocity-parsers-2.2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-sketch_2.11/2.1.0/spark-sketch_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-tags_2.11/2.1.0/spark-tags_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scalatest/scalatest_2.11/2.2.6/scalatest_2.11-2.2.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scala-library/2.11.8/scala-library-2.11.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scala-reflect/2.11.7/scala-reflect-2.11.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-xml_2.11/1.0.2/scala-xml_2.11-1.0.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/spark-project/spark/unused/1.0.0/unused-1.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-core_2.11/2.1.0/spark-core_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro-mapred/1.7.7/avro-mapred-1.7.7-hadoop2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro-ipc/1.7.7/avro-ipc-1.7.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro/1.7.7/avro-1.7.7.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/jackson/jackson-core-asl/1.9.13/jackson-core-asl-1.9.13.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/jackson/jackson-mapper-asl/1.9.13/jackson-mapper-asl-1.9.13.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/thoughtworks/paranamer/paranamer/2.6/paranamer-2.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/xerial/snappy/snappy-java/1.1.2.6/snappy-java-1.1.2.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-compress/1.4.1/commons-compress-1.4.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/tukaani/xz/1.0/xz-1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.16/slf4j-api-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/avro/avro-ipc/1.7.7/avro-ipc-1.7.7-tests.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/twitter/chill_2.11/0.8.0/chill_2.11-0.8.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/twitter/chill-java/0.8.0/chill-java-0.8.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/esotericsoftware/kryo-shaded/3.0.3/kryo-shaded-3.0.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/esotericsoftware/minlog/1.3.0/minlog-1.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/objenesis/objenesis/2.1/objenesis-2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/xbean/xbean-asm5-shaded/4.4/xbean-asm5-shaded-4.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-client/2.2.0/hadoop-client-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-common/2.2.0/hadoop-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-annotations/2.2.0/hadoop-annotations-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/guava/guava/14.0.1/guava-14.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-cli/commons-cli/1.2/commons-cli-1.2.jar" sourcepath="M2_REPO/commons-cli/commons-cli/1.2/commons-cli-1.2-sources.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-math/2.1/commons-math-2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/xmlenc/xmlenc/0.52/xmlenc-0.52.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-httpclient/commons-httpclient/3.1/commons-httpclient-3.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-io/commons-io/2.1/commons-io-2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-net/commons-net/2.2/commons-net-2.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.17/log4j-1.2.17.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-lang/commons-lang/2.5/commons-lang-2.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-configuration/commons-configuration/1.6/commons-configuration-1.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-digester/commons-digester/1.8/commons-digester-1.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils/1.7.0/commons-beanutils-1.7.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/commons-beanutils/commons-beanutils-core/1.8.0/commons-beanutils-core-1.8.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.7.16/slf4j-log4j12-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/google/protobuf/protobuf-java/2.5.0/protobuf-java-2.5.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-auth/2.2.0/hadoop-auth-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/zookeeper/zookeeper/3.4.5/zookeeper-3.4.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-hdfs/2.2.0/hadoop-hdfs-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/mortbay/jetty/jetty-util/6.1.26/jetty-util-6.1.26.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-app/2.2.0/hadoop-mapreduce-client-app-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-common/2.2.0/hadoop-mapreduce-client-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-common/2.2.0/hadoop-yarn-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-api/2.2.0/hadoop-yarn-api-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/jettison/jettison/1.3.8/jettison-1.3.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/stax/stax-api/1.0.1/stax-api-1.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-client/2.2.0/hadoop-yarn-client-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-core/2.2.0/hadoop-mapreduce-client-core-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-yarn-server-common/2.2.0/hadoop-yarn-server-common-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-shuffle/2.2.0/hadoop-mapreduce-client-shuffle-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/hadoop/hadoop-mapreduce-client-jobclient/2.2.0/hadoop-mapreduce-client-jobclient-2.2.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-launcher_2.11/2.1.0/spark-launcher_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-network-common_2.11/2.1.0/spark-network-common_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/netty/netty-all/4.0.42.Final/netty-all-4.0.42.Final.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-lang3/3.5/commons-lang3-3.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/fusesource/leveldbjni/leveldbjni-all/1.8/leveldbjni-all-1.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/core/jackson-databind/2.6.5/jackson-databind-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/core/jackson-annotations/2.6.5/jackson-annotations-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-network-shuffle_2.11/2.1.0/spark-network-shuffle_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-core/3.1.2/metrics-core-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-unsafe_2.11/2.1.0/spark-unsafe_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/java/dev/jets3t/jets3t/0.7.1/jets3t-0.7.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/curator/curator-recipes/2.4.0/curator-recipes-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/curator/curator-framework/2.4.0/curator-framework-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/curator/curator-client/2.4.0/curator-client-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-math3/3.4.1/commons-math3-3.4.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/jul-to-slf4j/1.7.16/jul-to-slf4j-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/slf4j/jcl-over-slf4j/1.7.16/jcl-over-slf4j-1.7.16.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/ning/compress-lzf/1.0.3/compress-lzf-1.0.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/jpountz/lz4/lz4/1.3.0/lz4-1.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/roaringbitmap/RoaringBitmap/0.5.11/RoaringBitmap-0.5.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/json4s/json4s-jackson_2.11/3.2.11/json4s-jackson_2.11-3.2.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/json4s/json4s-core_2.11/3.2.11/json4s-core_2.11-3.2.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/json4s/json4s-ast_2.11/3.2.11/json4s-ast_2.11-3.2.11.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scalap/2.11.0/scalap-2.11.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/scala-compiler/2.11.0/scala-compiler-2.11.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scala-lang/modules/scala-parser-combinators_2.11/1.0.1/scala-parser-combinators_2.11-1.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/core/jersey-client/2.22.2/jersey-client-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/core/jersey-common/2.22.2/jersey-common-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/bundles/repackaged/jersey-guava/2.22.2/jersey-guava-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/hk2-api/2.4.0-b34/hk2-api-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/hk2-utils/2.4.0-b34/hk2-utils-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/external/aopalliance-repackaged/2.4.0-b34/aopalliance-repackaged-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/external/javax.inject/2.4.0-b34/javax.inject-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/hk2-locator/2.4.0-b34/hk2-locator-2.4.0-b34.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/javassist/javassist/3.18.1-GA/javassist-3.18.1-GA.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/hk2/osgi-resource-locator/1.0.1/osgi-resource-locator-1.0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/core/jersey-server/2.22.2/jersey-server-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/media/jersey-media-jaxb/2.22.2/jersey-media-jaxb-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/containers/jersey-container-servlet/2.22.2/jersey-container-servlet-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/glassfish/jersey/containers/jersey-container-servlet-core/2.22.2/jersey-container-servlet-core-2.22.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/clearspring/analytics/stream/2.7.0/stream-2.7.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-jvm/3.1.2/metrics-jvm-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-json/3.1.2/metrics-json-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/io/dropwizard/metrics/metrics-graphite/3.1.2/metrics-graphite-3.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/module/jackson-module-scala_2.11/2.6.5/jackson-module-scala_2.11-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/fasterxml/jackson/module/jackson-module-paranamer/2.6.5/jackson-module-paranamer-2.6.5.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/ivy/ivy/2.4.0/ivy-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/oro/oro/2.0.8/oro-2.0.8.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/razorvine/pyrolite/4.13/pyrolite-4.13.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sf/py4j/py4j/0.10.4/py4j-0.10.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-crypto/1.0.0/commons-crypto-1.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-catalyst_2.11/2.1.0/spark-catalyst_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/janino/janino/3.0.0/janino-3.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/codehaus/janino/commons-compiler/3.0.0/commons-compiler-3.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/antlr/antlr4-runtime/4.5.3/antlr4-runtime-4.5.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-column/1.8.1/parquet-column-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-common/1.8.1/parquet-common-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-encoding/1.8.1/parquet-encoding-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-hadoop/1.8.1/parquet-hadoop-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-format/2.3.0-incubating/parquet-format-2.3.0-incubating.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/parquet/parquet-jackson/1.8.1/parquet-jackson-1.8.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-streaming_2.11/2.1.0/spark-streaming_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-mllib_2.11/2.1.0/spark-mllib_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-graphx_2.11/2.1.0/spark-graphx_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/spark/spark-mllib-local_2.11/2.1.0/spark-mllib-local_2.11-2.1.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scalanlp/breeze_2.11/0.12/breeze_2.11-0.12.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/scalanlp/breeze-macros_2.11/0.12/breeze-macros_2.11-0.12.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/core/1.1.2/core-1.1.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sourceforge/f2j/arpack_combined_all/0.1/arpack_combined_all-0.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/net/sf/opencsv/opencsv/2.3/opencsv-2.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/rwl/jtransforms/2.4.0/jtransforms-2.4.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/spire-math/spire_2.11/0.7.4/spire_2.11-0.7.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/spire-math/spire-macros_2.11/0.7.4/spire-macros_2.11-0.7.4.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/chuusai/shapeless_2.11/2.0.0/shapeless_2.11-2.0.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/jpmml/pmml-model/1.2.15/pmml-model-1.2.15.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/jpmml/pmml-schema/1.2.15/pmml-schema-1.2.15.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-osx-x86_64/1.1/netlib-native_ref-osx-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/native_ref-java/1.1/native_ref-java-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/jniloader/1.1/jniloader-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-linux-x86_64/1.1/netlib-native_ref-linux-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-linux-i686/1.1/netlib-native_ref-linux-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-win-x86_64/1.1/netlib-native_ref-win-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-win-i686/1.1/netlib-native_ref-win-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_ref-linux-armhf/1.1/netlib-native_ref-linux-armhf-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-osx-x86_64/1.1/netlib-native_system-osx-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/native_system-java/1.1/native_system-java-1.1.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-linux-x86_64/1.1/netlib-native_system-linux-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-linux-i686/1.1/netlib-native_system-linux-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-linux-armhf/1.1/netlib-native_system-linux-armhf-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-win-x86_64/1.1/netlib-native_system-win-x86_64-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/fommil/netlib/netlib-native_system-win-i686/1.1/netlib-native_system-win-i686-1.1-natives.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/logging/log4j/log4j-api/2.6.2/log4j-api-2.6.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/logging/log4j/log4j-core/2.6.2/log4j-core-2.6.2.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-core/3.3.0/jena-core-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-iri/3.3.0/jena-iri-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/xerces/xercesImpl/2.11.0/xercesImpl-2.11.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-base/3.3.0/jena-base-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/jena/jena-shaded-guava/3.3.0/jena-shaded-guava-3.3.0.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-csv/1.3/commons-csv-1.3.jar"/>
+ <classpathentry kind="var" path="M2_REPO/com/github/andrewoma/dexx/collection/0.6/collection-0.6.jar"/>
+ <classpathentry kind="var" path="M2_REPO/junit/junit/4.12/junit-4.12.jar"/>
+ <classpathentry kind="var" path="M2_REPO/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar"/>
+</classpath>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.externalToolBuilders/Maven_Ant_Builder.launch
----------------------------------------------------------------------
diff --git a/core/.externalToolBuilders/Maven_Ant_Builder.launch b/core/.externalToolBuilders/Maven_Ant_Builder.launch
new file mode 100644
index 0000000..960f867
--- /dev/null
+++ b/core/.externalToolBuilders/Maven_Ant_Builder.launch
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
+ <booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,clean"/>
+ <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
+ <booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+ <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="mudrod-core"/>
+ <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${build_project}/maven-eclipse.xml"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${build_project}"/>
+ <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${project}"/>
+ <booleanAttribute key="org.eclipse.debug.core.capture_output" value="false"/>
+ <stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version='1.0'?><launchConfigurationWorkingSet editPageId='org.eclipse.ui.resourceWorkingSetPage' factoryID='org.eclipse.ui.internal.WorkingSetFactory' label='workingSet' name='workingSet'><item factoryID='org.eclipse.ui.internal.model.ResourceFactory' path='mudrod-core' type='4'/></launchConfigurationWorkingSet>}"/>
+ <stringAttribute key="process_factory_id" value="org.eclipse.ant.ui.remoteAntProcessFactory"/>
+ <booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
+ <booleanAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON" value="false"/>
+ <booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
+ <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
+ <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+ <listEntry value="1"/>
+ </listAttribute>
+ <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+ <listEntry value="/mudrod-core/maven-eclipse.xml"/>
+ </listAttribute>
+</launchConfiguration>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.project
----------------------------------------------------------------------
diff --git a/core/.project b/core/.project
new file mode 100644
index 0000000..540ea77
--- /dev/null
+++ b/core/.project
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>mudrod-core</name>
+ <comment>Core Mudrod library implementation. NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment>
+ <projects/>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+ <arguments>
+ <dictionary>
+ <key>LaunchConfigHandle</key>
+ <value><project>/.externalToolBuilders/Maven_Ant_Builder.launch</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.settings/org.eclipse.core.resources.prefs
----------------------------------------------------------------------
diff --git a/core/.settings/org.eclipse.core.resources.prefs b/core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..abdea9a
--- /dev/null
+++ b/core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding/<project>=UTF-8
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/core/.settings/org.eclipse.jdt.core.prefs b/core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..6e80039
--- /dev/null
+++ b/core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.8
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/core/.settings/org.eclipse.m2e.core.prefs b/core/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/core/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.settings/org.eclipse.wst.common.component
----------------------------------------------------------------------
diff --git a/core/.settings/org.eclipse.wst.common.component b/core/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..64b0918
--- /dev/null
+++ b/core/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="mudrod-core">
+ <wb-resource deploy-path="/" source-path="/src/main/java"/>
+ <wb-resource deploy-path="/" source-path="/src/main/resources"/>
+ <wb-resource deploy-path="/" source-path="/target"/>
+ <wb-resource deploy-path="/" source-path="/local/mudrod"/>
+ </wb-module>
+</project-modules>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/.settings/org.eclipse.wst.common.project.facet.core.xml
----------------------------------------------------------------------
diff --git a/core/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..fb95c45
--- /dev/null
+++ b/core/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="java" version="1.8"/>
+ <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/lib/all-1.1.2.pom
----------------------------------------------------------------------
diff --git a/core/lib/all-1.1.2.pom b/core/lib/all-1.1.2.pom
new file mode 100644
index 0000000..577dd32
--- /dev/null
+++ b/core/lib/all-1.1.2.pom
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.github.fommil.netlib</groupId>
+ <artifactId>parent</artifactId>
+ <version>1.1</version>
+ </parent>
+
+ <artifactId>all</artifactId>
+ <packaging>pom</packaging>
+ <version>1.1.2</version>
+
+ <dependencies>
+ <dependency>
+ <!-- WORKAROUND: https://github.com/sbt/sbt/issues/861 -->
+ <groupId>net.sourceforge.f2j</groupId>
+ <artifactId>arpack_combined_all</artifactId>
+ <version>0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>core</artifactId>
+ <version>1.1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-osx-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-linux-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-linux-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-win-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-win-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_ref-linux-armhf</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-osx-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-linux-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-linux-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-linux-armhf</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-win-x86_64</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>netlib-native_system-win-i686</artifactId>
+ <version>${project.parent.version}</version>
+ <classifier>natives</classifier>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/lib/apache-jena-libs-3.1.0.pom
----------------------------------------------------------------------
diff --git a/core/lib/apache-jena-libs-3.1.0.pom b/core/lib/apache-jena-libs-3.1.0.pom
new file mode 100644
index 0000000..3fdb874
--- /dev/null
+++ b/core/lib/apache-jena-libs-3.1.0.pom
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
+ license agreements. See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership. The ASF licenses this file to
+ You under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of
+ the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
+ by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ OF ANY KIND, either express or implied. See the License for the specific
+ language governing permissions and limitations under the License. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>apache-jena-libs</artifactId>
+ <packaging>pom</packaging>
+ <name>Apache Jena - Libraries POM</name>
+ <version>3.1.0</version>
+
+ <parent>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-parent</artifactId>
+ <version>16</version>
+ <relativePath>../jena-parent</relativePath>
+ </parent>
+
+ <!-- Need if the parent is a snapshot -->
+ <repositories>
+ <repository>
+ <id>apache.snapshots</id>
+ <name>Apache Snapshot Repository</name>
+ <url>http://repository.apache.org/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ </repository>
+ </repositories>
+
+ <description>A convenience POM artifact that may be referenced to pull in all the standard Jena Libraries (Core, ARQ, IRI, and TDB) with a single dependency.</description>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-tdb</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/maven-eclipse.xml
----------------------------------------------------------------------
diff --git a/core/maven-eclipse.xml b/core/maven-eclipse.xml
new file mode 100644
index 0000000..427ace4
--- /dev/null
+++ b/core/maven-eclipse.xml
@@ -0,0 +1,8 @@
+<project default="copy-resources">
+ <target name="init"/>
+ <target name="copy-resources" depends="init">
+ <copy todir="target/classes/META-INF" filtering="false">
+ <fileset dir="/usr/local/mudrod" includes="LICENSE.txt|NOTICE.txt" excludes="**/*.java"/>
+ </copy>
+ </target>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/mudrod.log
----------------------------------------------------------------------
diff --git a/core/mudrod.log b/core/mudrod.log
new file mode 100644
index 0000000..8374b97
--- /dev/null
+++ b/core/mudrod.log
@@ -0,0 +1,81 @@
+2017-10-03 13:56:28,310 INFO process.LocalOntology - Creating new ontology
+2017-10-03 13:56:29,221 WARN impl.RDFDefaultErrorHandler - unknown-source: {W136} Relative URIs are not permitted in RDF: specifically <ont-policy.rdf>
+2017-10-03 13:56:29,309 INFO process.LocalOntology - Reading and processing https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
+2017-10-03 13:56:29,668 ERROR process.LocalOntology - Failed whilst attempting to read ontology https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl: Error:
+org.apache.jena.shared.DoesNotExistException: https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
+ at org.apache.jena.rdfxml.xmlinput.JenaReader.read(JenaReader.java:97)
+ at org.apache.jena.rdf.model.impl.ModelCom.read(ModelCom.java:263)
+ at org.apache.jena.ontology.impl.OntModelImpl.readDelegate(OntModelImpl.java:3090)
+ at org.apache.jena.ontology.impl.OntModelImpl.read(OntModelImpl.java:2182)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.load(LocalOntology.java:133)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.load(LocalOntology.java:126)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.load(LocalOntology.java:111)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.<init>(LocalOntology.java:74)
+ at gov.nasa.jpl.mudrod.ontology.process.TestLocalOntology.setUp(TestLocalOntology.java:53)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+ at java.lang.reflect.Method.invoke(Method.java:498)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
+ at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
+ at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
+ at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
+ at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
+ at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
+ at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:367)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:274)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:161)
+ at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290)
+ at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242)
+ at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121)
+2017-10-03 13:56:29,678 INFO process.LocalOntology - Creating new ontology
+2017-10-03 13:56:29,678 INFO process.LocalOntology - Reading and processing https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
+2017-10-03 13:56:29,695 ERROR process.LocalOntology - Failed whilst attempting to read ontology https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl: Error:
+org.apache.jena.shared.DoesNotExistException: https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
+ at org.apache.jena.rdfxml.xmlinput.JenaReader.read(JenaReader.java:97)
+ at org.apache.jena.rdf.model.impl.ModelCom.read(ModelCom.java:263)
+ at org.apache.jena.ontology.impl.OntModelImpl.readDelegate(OntModelImpl.java:3090)
+ at org.apache.jena.ontology.impl.OntModelImpl.read(OntModelImpl.java:2182)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.load(LocalOntology.java:133)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.load(LocalOntology.java:126)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.load(LocalOntology.java:111)
+ at gov.nasa.jpl.mudrod.ontology.process.LocalOntology.<init>(LocalOntology.java:74)
+ at gov.nasa.jpl.mudrod.ontology.process.TestLocalOntology.setUp(TestLocalOntology.java:53)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
+ at java.lang.reflect.Method.invoke(Method.java:498)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
+ at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
+ at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
+ at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
+ at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
+ at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
+ at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:367)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:274)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
+ at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:161)
+ at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290)
+ at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242)
+ at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121)
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/mudrod.log.2017-06-14
----------------------------------------------------------------------
diff --git a/core/mudrod.log.2017-06-14 b/core/mudrod.log.2017-06-14
new file mode 100644
index 0000000..7bc924a
--- /dev/null
+++ b/core/mudrod.log.2017-06-14
@@ -0,0 +1,9 @@
+2017-06-14 10:01:56,775 INFO process.LocalOntology - Creating new ontology
+2017-06-14 10:01:57,575 WARN impl.RDFDefaultErrorHandler - unknown-source: {W136} Relative URIs are not permitted in RDF: specifically <ont-policy.rdf>
+2017-06-14 10:01:57,647 INFO process.LocalOntology - Reading and processing https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
+2017-06-14 10:02:04,930 WARN impl.RDFDefaultErrorHandler - https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/reprSciUnits.owl(line 683 column 44): {W105} Redefinition of ID: lux
+2017-06-14 10:02:04,930 WARN impl.RDFDefaultErrorHandler - https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/reprSciUnits.owl(line 635 column 44): {W105} Previous definition of 'lux'.
+2017-06-14 10:02:15,572 INFO process.LocalOntology - Successfully processed https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
+2017-06-14 10:02:18,889 INFO process.LocalOntology - Creating new ontology
+2017-06-14 10:02:18,889 INFO process.LocalOntology - Reading and processing https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
+2017-06-14 10:02:18,898 INFO process.LocalOntology - Successfully processed https://raw.githubusercontent.com/ESIPFed/sweet/master/2.4/sweetAll.owl
[16/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/SResult.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/SResult.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/SResult.java
new file mode 100644
index 0000000..33b6233
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/SResult.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.ssearch.structure;
+
+import java.lang.reflect.Field;
+
+/**
+ * Data structure class for search result
+ */
+public class SResult {
+ public static final String rlist[] = { "term_score", "releaseDate_score", /*"versionNum_score",*/
+ "processingL_score", "allPop_score", "monthPop_score", "userPop_score"/*, "termAndv_score"*/ };
+ String shortName = null;
+ String longName = null;
+ String topic = null;
+ String description = null;
+ String relase_date = null;
+
+ public Double final_score = 0.0;
+ public Double term_score = 0.0;
+ public Double releaseDate_score = 0.0;
+ public Double versionNum_score = 0.0;
+ public Double processingL_score = 0.0;
+ public Double click_score = 0.0;
+ public Double allPop_score = 0.0;
+ public Double monthPop_score = 0.0;
+ public Double userPop_score = 0.0;
+ public Double termAndv_score = 0.0;
+ public Integer below = 0;
+
+ public Double Dataset_LongName_score = null;
+ public Double Dataset_Metadata_score = null;
+ public Double DatasetParameter_Term_score = null;
+ public Double DatasetSource_Source_LongName_score = null;
+ public Double DatasetSource_Sensor_LongName_score = null;
+
+ public String version = null;
+ public String processingLevel = null;
+ public String latency = null;
+ public String stopDateLong = null;
+ public String stopDateFormat = null;
+ public Double spatialR_Sat = null;
+ public Double spatialR_Grid = null;
+ public String temporalR = null;
+
+ public Double releaseDate = null;
+ public Double click = null;
+ public Double term = null;
+ public Double versionNum = null;
+ public Double processingL = null;
+ public Double allPop = null;
+ public Double monthPop = null;
+ public Double userPop = null;
+ public Double termAndv = null;
+
+ public Double Dataset_LongName = null;
+ public Double Dataset_Metadata = null;
+ public Double DatasetParameter_Term = null;
+ public Double DatasetSource_Source_LongName = null;
+ public Double DatasetSource_Sensor_LongName = null;
+
+ public Double prediction = 0.0;
+ public String label = null;
+
+ //add by quintinali
+ public String startDate;
+ public String endDate;
+ public String sensors;
+
+ /**
+ * @param shortName short name of dataset
+ * @param longName long name of dataset
+ * @param topic topic of dataset
+ * @param description description of dataset
+ * @param date release date of dataset
+ */
+ public SResult(String shortName, String longName, String topic, String description, String date) {
+ this.shortName = shortName;
+ this.longName = longName;
+ this.topic = topic;
+ this.description = description;
+ this.relase_date = date;
+ }
+
+ public SResult(SResult sr) {
+ for (int i = 0; i < rlist.length; i++) {
+ set(this, rlist[i], get(sr, rlist[i]));
+ }
+ }
+
+ /**
+ * Method of getting export header
+ *
+ * @param delimiter the delimiter used to separate strings
+ * @return header
+ */
+ public static String getHeader(String delimiter) {
+ String str = "";
+ for (int i = 0; i < rlist.length; i++) {
+ str += rlist[i] + delimiter;
+ }
+ str = str + "label" + "\n";
+ return "ShortName" + delimiter + "below" + delimiter + str;
+ }
+
+ /**
+ * Method of get a search results as string
+ *
+ * @param delimiter the delimiter used to separate strings
+ * @return search result as string
+ */
+ public String toString(String delimiter) {
+ String str = "";
+ for (int i = 0; i < rlist.length; i++) {
+ double score = get(this, rlist[i]);
+ str += score + delimiter;
+ }
+ str = str + label + "\n";
+ return shortName + delimiter + below + delimiter + str;
+ }
+
+ /**
+ * Generic setter method
+ *
+ * @param object instance of SResult
+ * @param fieldName field name that needs to be set on
+ * @param fieldValue field value that needs to be set to
+ * @return 1 means success, and 0 otherwise
+ */
+ public static boolean set(Object object, String fieldName, Object fieldValue) {
+ Class<?> clazz = object.getClass();
+ while (clazz != null) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ field.set(object, fieldValue);
+ return true;
+ } catch (NoSuchFieldException e) {
+ clazz = clazz.getSuperclass();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Generic getter method
+ *
+ * @param object instance of SResult
+ * @param fieldName field name of search result
+ * @param <V> data type
+ * @return the value of the filed in the object
+ */
+ @SuppressWarnings("unchecked")
+ public static <V> V get(Object object, String fieldName) {
+ Class<?> clazz = object.getClass();
+ while (clazz != null) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return (V) field.get(object);
+ } catch (NoSuchFieldException e) {
+ clazz = clazz.getSuperclass();
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/package-info.java
new file mode 100644
index 0000000..a0f9ce5
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/ssearch/structure/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes data structure needed for ranking process
+ */
+package gov.nasa.jpl.mudrod.ssearch.structure;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/ESTransportClient.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/ESTransportClient.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/ESTransportClient.java
new file mode 100644
index 0000000..151ac8d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/ESTransportClient.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package gov.nasa.jpl.mudrod.utils;
+
+import org.elasticsearch.client.transport.TransportClient;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.reindex.ReindexPlugin;
+import org.elasticsearch.percolator.PercolatorPlugin;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.script.mustache.MustachePlugin;
+import org.elasticsearch.transport.Netty3Plugin;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * A builder to create an instance of {@link TransportClient} This class
+ * pre-installs the {@link Netty3Plugin}, for the client. These plugins are all
+ * elasticsearch core modules required.
+ */
+@SuppressWarnings({ "unchecked", "varargs" })
+public class ESTransportClient extends TransportClient {
+
+ private static final Collection<Class<? extends Plugin>> PRE_INSTALLED_PLUGINS = Collections
+ .unmodifiableList(Arrays.asList(ReindexPlugin.class, PercolatorPlugin.class, MustachePlugin.class, Netty3Plugin.class));
+
+ @SafeVarargs
+ public ESTransportClient(Settings settings, Class<? extends Plugin>... plugins) {
+ this(settings, Arrays.asList(plugins));
+ }
+
+ public ESTransportClient(Settings settings, Collection<Class<? extends Plugin>> plugins) {
+ super(settings, Settings.EMPTY, addPlugins(plugins, PRE_INSTALLED_PLUGINS), null);
+
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/HttpRequest.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/HttpRequest.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/HttpRequest.java
new file mode 100644
index 0000000..be0a46d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/HttpRequest.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ * ClassName: HttpRequest
+ * Function: Http request tool.
+ */
+public class HttpRequest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HttpRequest.class);
+
+ public HttpRequest() {
+ }
+
+ public String getRequest(String requestUrl) {
+ String line = null;
+ try {
+ URL url = new URL(requestUrl);
+
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ connection.setConnectTimeout(5000);
+ connection.setReadTimeout(5000);
+ int code = connection.getResponseCode();
+ if (code != HttpURLConnection.HTTP_OK) {
+ line = "{\"exception\":\"Service failed\"}";
+ LOG.info(line);
+ } else {
+ InputStream content = connection.getInputStream();
+ BufferedReader in = new BufferedReader(new InputStreamReader(content));
+ line = in.readLine();
+ }
+ } catch (Exception e) {
+ line = "{\"exception\":\"No service was found\"}";
+ LOG.error(line);
+ }
+ return line;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/LabeledRowMatrix.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/LabeledRowMatrix.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/LabeledRowMatrix.java
new file mode 100644
index 0000000..d1d144b
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/LabeledRowMatrix.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.utils;
+
+import org.apache.spark.mllib.linalg.distributed.RowMatrix;
+
+import java.util.List;
+
+/**
+ * ClassName: LabeledRowMatrix
+ * Function: LabeledRowMatrix strut.
+ */
+public class LabeledRowMatrix {
+
+ // words: matrix row titles
+ public List<String> rowkeys;
+ // docs: matrix column titles
+ public List<String> colkeys;
+ // wordDocMatrix: a matrix in which each row is corresponding to a term and
+ // each column is a doc.
+ public RowMatrix rowMatrix;
+
+ public LabeledRowMatrix() {
+ // TODO Auto-generated constructor stub
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/LinkageTriple.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/LinkageTriple.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/LinkageTriple.java
new file mode 100644
index 0000000..90b1568
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/LinkageTriple.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.utils;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.elasticsearch.search.sort.SortOrder;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.List;
+import java.util.Map;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * ClassName: LinkageTriple Function: Vocabulary linkage operations
+ */
+public class LinkageTriple implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ // keyAId: ID of term A
+ public long keyAId;
+ // keyBId: ID of term B
+ public long keyBId;
+ // weight: The relationship between term A and Term B
+ public double weight;
+ // keyA: TermA
+ public String keyA;
+ // keyB: TermB
+ public String keyB;
+ // df: Format number
+ public static DecimalFormat df = new DecimalFormat("#.00");
+
+ public LinkageTriple() {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * TODO Output linkage triples in string format.
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return keyA + "," + keyB + ":" + weight;
+ }
+
+ public static void insertTriples(ESDriver es, List<LinkageTriple> triples, String index, String type) throws IOException {
+ LinkageTriple.insertTriples(es, triples, index, type, false, false);
+ }
+
+ public static void insertTriples(ESDriver es, List<LinkageTriple> triples, String index, String type, Boolean bTriple, boolean bSymmetry) throws IOException {
+ es.deleteType(index, type);
+ if (bTriple) {
+ LinkageTriple.addMapping(es, index, type);
+ }
+
+ if (triples == null) {
+ return;
+ }
+
+ es.createBulkProcessor();
+ int size = triples.size();
+ for (int i = 0; i < size; i++) {
+
+ XContentBuilder jsonBuilder = jsonBuilder().startObject();
+ if (bTriple) {
+
+ jsonBuilder.field("concept_A", triples.get(i).keyA);
+ jsonBuilder.field("concept_B", triples.get(i).keyB);
+
+ } else {
+ jsonBuilder.field("keywords", triples.get(i).keyA + "," + triples.get(i).keyB);
+ }
+
+ jsonBuilder.field("weight", Double.parseDouble(df.format(triples.get(i).weight)));
+ jsonBuilder.endObject();
+
+ IndexRequest ir = new IndexRequest(index, type).source(jsonBuilder);
+ es.getBulkProcessor().add(ir);
+
+ if (bTriple && bSymmetry) {
+ XContentBuilder symmetryJsonBuilder = jsonBuilder().startObject();
+ symmetryJsonBuilder.field("concept_A", triples.get(i).keyB);
+ symmetryJsonBuilder.field("concept_B", triples.get(i).keyA);
+
+ symmetryJsonBuilder.field("weight", Double.parseDouble(df.format(triples.get(i).weight)));
+
+ symmetryJsonBuilder.endObject();
+
+ IndexRequest symmetryir = new IndexRequest(index, type).source(symmetryJsonBuilder);
+ es.getBulkProcessor().add(symmetryir);
+ }
+ }
+ es.destroyBulkProcessor();
+ }
+
+ public static void addMapping(ESDriver es, String index, String type) {
+ XContentBuilder Mapping;
+ try {
+ Mapping = jsonBuilder().startObject().startObject(type).startObject("properties").startObject("concept_A").field("type", "string").field("index", "not_analyzed").endObject()
+ .startObject("concept_B").field("type", "string").field("index", "not_analyzed").endObject()
+
+ .endObject().endObject().endObject();
+
+ es.getClient().admin().indices().preparePutMapping(index).setType(type).setSource(Mapping).execute().actionGet();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void standardTriples(ESDriver es, String index, String type) throws IOException {
+ es.createBulkProcessor();
+
+ SearchResponse sr = es.getClient().prepareSearch(index).setTypes(type).setQuery(QueryBuilders.matchAllQuery()).setSize(0)
+ .addAggregation(AggregationBuilders.terms("concepts").field("concept_A").size(0)).execute().actionGet();
+ Terms concepts = sr.getAggregations().get("concepts");
+
+ for (Terms.Bucket entry : concepts.getBuckets()) {
+ String concept = (String) entry.getKey();
+ double maxSim = LinkageTriple.getMaxSimilarity(es, index, type, concept);
+ if (maxSim == 1.0) {
+ continue;
+ }
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(index).setTypes(type).setScroll(new TimeValue(60000)).setQuery(QueryBuilders.termQuery("concept_A", concept))
+ .addSort("weight", SortOrder.DESC).setSize(100).execute().actionGet();
+
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> metadata = hit.getSource();
+ double sim = (double) metadata.get("weight");
+ double newSim = sim / maxSim;
+ UpdateRequest ur = es.generateUpdateRequest(index, type, hit.getId(), "weight", Double.parseDouble(df.format(newSim)));
+ es.getBulkProcessor().add(ur);
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+ }
+
+ es.destroyBulkProcessor();
+ }
+
+ private static double getMaxSimilarity(ESDriver es, String index, String type, String concept) {
+
+ double maxSim = 1.0;
+ SearchRequestBuilder builder = es.getClient().prepareSearch(index).setTypes(type).setQuery(QueryBuilders.termQuery("concept_A", concept)).addSort("weight", SortOrder.DESC).setSize(1);
+
+ SearchResponse usrhis = builder.execute().actionGet();
+ SearchHit[] hits = usrhis.getHits().getHits();
+ if (hits.length == 1) {
+ SearchHit hit = hits[0];
+ Map<String, Object> result = hit.getSource();
+ maxSim = (double) result.get("weight");
+ }
+
+ if (maxSim == 0.0) {
+ maxSim = 1.0;
+ }
+
+ return maxSim;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/MatrixUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/MatrixUtil.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/MatrixUtil.java
new file mode 100644
index 0000000..942f1e0
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/MatrixUtil.java
@@ -0,0 +1,488 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.utils;
+
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.api.java.Optional;
+import org.apache.spark.api.java.function.*;
+import org.apache.spark.mllib.feature.IDF;
+import org.apache.spark.mllib.feature.IDFModel;
+import org.apache.spark.mllib.linalg.*;
+import org.apache.spark.mllib.linalg.distributed.IndexedRow;
+import org.apache.spark.mllib.linalg.distributed.IndexedRowMatrix;
+import org.apache.spark.mllib.linalg.distributed.RowMatrix;
+import scala.Tuple2;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Stream;
+
+/**
+ * Matrix utility tool
+ */
+public class MatrixUtil {
+
+ private MatrixUtil() {
+ }
+
+ /**
+ * buildSVDMatrix: Generate SVD matrix from TF-IDF matrix. Please make sure
+ * the TF-IDF matrix has been already built from the original documents.
+ *
+ * @param tfidfMatrix,
+ * each row is a term and each column is a document name and each
+ * cell is the TF-IDF value of the term in the corresponding
+ * document.
+ * @param dimension
+ * Column number of the SVD matrix
+ * @return RowMatrix, each row is a term and each column is a dimension in the
+ * feature space, each cell is value of the term in the corresponding
+ * dimension.
+ */
+ public static RowMatrix buildSVDMatrix(RowMatrix tfidfMatrix, int dimension) {
+ int matrixCol = (int) tfidfMatrix.numCols();
+ if (matrixCol < dimension) {
+ dimension = matrixCol;
+ }
+
+ SingularValueDecomposition<RowMatrix, Matrix> svd = tfidfMatrix.computeSVD(dimension, true, 1.0E-9d);
+ RowMatrix u = svd.U();
+ Vector s = svd.s();
+ return u.multiply(Matrices.diag(s));
+ }
+
+ /**
+ * buildSVDMatrix: Generate SVD matrix from Vector RDD.
+ *
+ * @param vecRDD
+ * vectors of terms in feature space
+ * @param dimension
+ * Column number of the SVD matrix
+ * @return RowMatrix, each row is a term and each column is a dimension in the
+ * feature space, each cell is value of the term in the corresponding
+ * dimension.
+ */
+ public static RowMatrix buildSVDMatrix(JavaRDD<Vector> vecRDD, int dimension) {
+ RowMatrix tfidfMatrix = new RowMatrix(vecRDD.rdd());
+ SingularValueDecomposition<RowMatrix, Matrix> svd = tfidfMatrix.computeSVD(dimension, true, 1.0E-9d);
+ RowMatrix u = svd.U();
+ Vector s = svd.s();
+ return u.multiply(Matrices.diag(s));
+ }
+
+ /**
+ * Create TF-IDF matrix from word-doc matrix.
+ *
+ * @param wordDocMatrix,
+ * each row is a term, each column is a document name and each cell
+ * is number of the term in the corresponding document.
+ * @return RowMatrix, each row is a term and each column is a document name
+ * and each cell is the TF-IDF value of the term in the corresponding
+ * document.
+ */
+ public static RowMatrix createTFIDFMatrix(RowMatrix wordDocMatrix) {
+ JavaRDD<Vector> newcountRDD = wordDocMatrix.rows().toJavaRDD();
+ IDFModel idfModel = new IDF().fit(newcountRDD);
+ JavaRDD<Vector> idf = idfModel.transform(newcountRDD);
+ return new RowMatrix(idf.rdd());
+ }
+
+ /**
+ * Create matrix from doc-terms JavaPairRDD.
+ *
+ * @param uniqueDocRDD
+ * doc-terms JavaPairRDD, in which each key is a doc name, and value
+ * is term list extracted from that doc
+ * @return LabeledRowMatrix {@link LabeledRowMatrix}
+ */
+ public static LabeledRowMatrix createWordDocMatrix(JavaPairRDD<String, List<String>> uniqueDocRDD) {
+ // Index documents with unique IDs
+ JavaPairRDD<List<String>, Long> corpus = uniqueDocRDD.values().zipWithIndex();
+ // cal word-doc numbers
+ JavaPairRDD<Tuple2<String, Long>, Double> worddocNumRDD = corpus.flatMapToPair(new PairFlatMapFunction<Tuple2<List<String>, Long>, Tuple2<String, Long>, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Iterator<Tuple2<Tuple2<String, Long>, Double>> call(Tuple2<List<String>, Long> docwords) throws Exception {
+ List<Tuple2<Tuple2<String, Long>, Double>> pairs = new ArrayList<>();
+ List<String> words = docwords._1;
+ int n = words.size();
+ for (int i = 0; i < n; i++) {
+ Tuple2<String, Long> worddoc = new Tuple2<>(words.get(i), docwords._2);
+ pairs.add(new Tuple2<Tuple2<String, Long>, Double>(worddoc, 1.0));
+ }
+ return pairs.iterator();
+ }
+ }).reduceByKey(new Function2<Double, Double, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Double call(Double first, Double second) throws Exception {
+ return first + second;
+ }
+ });
+ // cal word doc-numbers
+ JavaPairRDD<String, Tuple2<List<Long>, List<Double>>> wordDocnumRDD = worddocNumRDD
+ .mapToPair(new PairFunction<Tuple2<Tuple2<String, Long>, Double>, String, Tuple2<List<Long>, List<Double>>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Tuple2<List<Long>, List<Double>>> call(Tuple2<Tuple2<String, Long>, Double> worddocNum) throws Exception {
+ List<Long> docs = new ArrayList<>();
+ docs.add(worddocNum._1._2);
+ List<Double> nums = new ArrayList<>();
+ nums.add(worddocNum._2);
+ Tuple2<List<Long>, List<Double>> docmums = new Tuple2<>(docs, nums);
+ return new Tuple2<>(worddocNum._1._1, docmums);
+ }
+ });
+ // trans to vector
+ final int corporsize = (int) uniqueDocRDD.keys().count();
+ JavaPairRDD<String, Vector> wordVectorRDD = wordDocnumRDD.reduceByKey(new Function2<Tuple2<List<Long>, List<Double>>, Tuple2<List<Long>, List<Double>>, Tuple2<List<Long>, List<Double>>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<List<Long>, List<Double>> call(Tuple2<List<Long>, List<Double>> arg0, Tuple2<List<Long>, List<Double>> arg1) throws Exception {
+ arg0._1.addAll(arg1._1);
+ arg0._2.addAll(arg1._2);
+ return new Tuple2<>(arg0._1, arg0._2);
+ }
+ }).mapToPair(new PairFunction<Tuple2<String, Tuple2<List<Long>, List<Double>>>, String, Vector>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Vector> call(Tuple2<String, Tuple2<List<Long>, List<Double>>> arg0) throws Exception {
+ int docsize = arg0._2._1.size();
+ int[] intArray = new int[docsize];
+ double[] doubleArray = new double[docsize];
+ for (int i = 0; i < docsize; i++) {
+ intArray[i] = arg0._2._1.get(i).intValue();
+ doubleArray[i] = arg0._2._2.get(i).intValue();
+ }
+ Vector sv = Vectors.sparse(corporsize, intArray, doubleArray);
+ return new Tuple2<>(arg0._1, sv);
+ }
+ });
+
+ RowMatrix wordDocMatrix = new RowMatrix(wordVectorRDD.values().rdd());
+
+ LabeledRowMatrix labeledRowMatrix = new LabeledRowMatrix();
+ labeledRowMatrix.rowMatrix = wordDocMatrix;
+ labeledRowMatrix.rowkeys = wordVectorRDD.keys().collect();
+ labeledRowMatrix.colkeys = uniqueDocRDD.keys().collect();
+ return labeledRowMatrix;
+ }
+
+ public static LabeledRowMatrix createDocWordMatrix(JavaPairRDD<String, List<String>> uniqueDocRDD, JavaSparkContext sc) {
+ // Index word with unique IDs
+ JavaPairRDD<String, Long> wordIDRDD = uniqueDocRDD.values().flatMap(new FlatMapFunction<List<String>, String>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Iterator<String> call(List<String> arg0) throws Exception {
+ return arg0.iterator();
+ }
+ }).distinct().zipWithIndex();
+
+ //
+ JavaPairRDD<Tuple2<String, String>, Double> docwordNumRDD = uniqueDocRDD.flatMapToPair(new PairFlatMapFunction<Tuple2<String, List<String>>, Tuple2<String, String>, Double>() {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Iterator<Tuple2<Tuple2<String, String>, Double>> call(Tuple2<String, List<String>> docwords) throws Exception {
+ List<Tuple2<Tuple2<String, String>, Double>> pairs = new ArrayList<>();
+ List<String> words = docwords._2;
+ int n = words.size();
+ for (int i = 0; i < n; i++) {
+ Tuple2<String, String> worddoc = new Tuple2<>(docwords._1, words.get(i));
+ pairs.add(new Tuple2<Tuple2<String, String>, Double>(worddoc, 1.0));
+ }
+ return pairs.iterator();
+ }
+ }).reduceByKey(new Function2<Double, Double, Double>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Double call(Double first, Double second) throws Exception {
+ return first + second;
+ }
+ });
+
+ //
+ JavaPairRDD<String, Tuple2<String, Double>> wordDocnumRDD = docwordNumRDD.mapToPair(new PairFunction<Tuple2<Tuple2<String, String>, Double>, String, Tuple2<String, Double>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Tuple2<String, Double>> call(Tuple2<Tuple2<String, String>, Double> arg0) throws Exception {
+
+ Tuple2<String, Double> wordmums = new Tuple2<>(arg0._1._1, arg0._2);
+ return new Tuple2<>(arg0._1._2, wordmums);
+ }
+ });
+
+ //
+
+ JavaPairRDD<String, Tuple2<Tuple2<String, Double>, Optional<Long>>> testRDD = wordDocnumRDD.leftOuterJoin(wordIDRDD);
+
+ int wordsize = (int) wordIDRDD.count();
+ JavaPairRDD<String, Vector> docVectorRDD = testRDD.mapToPair(new PairFunction<Tuple2<String, Tuple2<Tuple2<String, Double>, Optional<Long>>>, String, Tuple2<List<Long>, List<Double>>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Tuple2<List<Long>, List<Double>>> call(Tuple2<String, Tuple2<Tuple2<String, Double>, Optional<Long>>> arg0) throws Exception {
+ Optional<Long> oid = arg0._2._2;
+ Long wordId = (long) 0;
+ if (oid.isPresent()) {
+ wordId = oid.get();
+ }
+
+ List<Long> word = new ArrayList<>();
+ word.add(wordId);
+
+ List<Double> count = new ArrayList<>();
+ count.add(arg0._2._1._2);
+
+ Tuple2<List<Long>, List<Double>> wordcount = new Tuple2<>(word, count);
+
+ return new Tuple2<>(arg0._2._1._1, wordcount);
+ }
+
+ }).reduceByKey(new Function2<Tuple2<List<Long>, List<Double>>, Tuple2<List<Long>, List<Double>>, Tuple2<List<Long>, List<Double>>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<List<Long>, List<Double>> call(Tuple2<List<Long>, List<Double>> arg0, Tuple2<List<Long>, List<Double>> arg1) throws Exception {
+ arg0._1.addAll(arg1._1);
+ arg0._2.addAll(arg1._2);
+ return new Tuple2<>(arg0._1, arg0._2);
+ }
+ }).mapToPair(new PairFunction<Tuple2<String, Tuple2<List<Long>, List<Double>>>, String, Vector>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Vector> call(Tuple2<String, Tuple2<List<Long>, List<Double>>> arg0) throws Exception {
+ int docsize = arg0._2._1.size();
+ int[] intArray = new int[docsize];
+ double[] doubleArray = new double[docsize];
+ for (int i = 0; i < docsize; i++) {
+ intArray[i] = arg0._2._1.get(i).intValue();
+ doubleArray[i] = arg0._2._2.get(i).intValue();
+ }
+ Vector sv = Vectors.sparse(wordsize, intArray, doubleArray);
+ return new Tuple2<>(arg0._1, sv);
+ }
+ });
+
+ RowMatrix docwordMatrix = new RowMatrix(docVectorRDD.values().rdd());
+
+ LabeledRowMatrix labeledRowMatrix = new LabeledRowMatrix();
+ labeledRowMatrix.rowMatrix = docwordMatrix;
+ labeledRowMatrix.rowkeys = docVectorRDD.keys().collect();
+ labeledRowMatrix.colkeys = wordIDRDD.keys().collect();
+
+ return labeledRowMatrix;
+ }
+
+ /**
+ * loadVectorFromCSV: Load term vector from csv file.
+ *
+ * @param spark
+ * spark instance
+ * @param csvFileName
+ * csv matrix file
+ * @param skipNum
+ * the numbers of rows which should be skipped Ignore the top skip
+ * number rows of the csv file
+ * @return JavaPairRDD, each key is a term, and value is the vector of the
+ * term in feature space.
+ */
+ public static JavaPairRDD<String, Vector> loadVectorFromCSV(SparkDriver spark, String csvFileName, int skipNum) {
+ // skip the first line (header), important!
+ JavaRDD<String> importRDD = spark.sc.textFile(csvFileName);
+ JavaPairRDD<String, Long> importIdRDD = importRDD.zipWithIndex().filter(new Function<Tuple2<String, Long>, Boolean>() {
+ /** */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Boolean call(Tuple2<String, Long> v1) throws Exception {
+ if (v1._2 > (skipNum - 1)) {
+ return true;
+ }
+ return false;
+ }
+ });
+
+ if (importIdRDD.count() == 0) {
+ return null;
+ }
+
+ return importIdRDD.mapToPair(new PairFunction<Tuple2<String, Long>, String, Vector>() {
+ /** */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<String, Vector> call(Tuple2<String, Long> t) throws Exception {
+ String[] fields = t._1.split(",");
+ String word = fields[0];
+ int fieldsize = fields.length;
+ int nStart = 1;
+ int nEnd = fieldsize - 1;
+ if (fieldsize < 2) {
+ nStart = 0;
+ nEnd = 0;
+ }
+ String[] numfields = Arrays.copyOfRange(fields, nStart, nEnd);
+
+ double[] nums = Stream.of(numfields).mapToDouble(Double::parseDouble).toArray();
+ Vector vec = Vectors.dense(nums);
+ return new Tuple2<>(word, vec);
+ }
+ });
+ }
+
+ /**
+ * Convert vectorRDD to indexed row matrix.
+ *
+ * @param vecs
+ * Vector RDD
+ * @return IndexedRowMatrix
+ */
+ public static IndexedRowMatrix buildIndexRowMatrix(JavaRDD<Vector> vecs) {
+ JavaRDD<IndexedRow> indexrows = vecs.zipWithIndex().map(new Function<Tuple2<Vector, Long>, IndexedRow>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public IndexedRow call(Tuple2<Vector, Long> docId) {
+ return new IndexedRow(docId._2, docId._1);
+ }
+ });
+ return new IndexedRowMatrix(indexrows.rdd());
+ }
+
+ /**
+ * Transpose matrix
+ *
+ * @param indexedMatrix
+ * spark indexed matrix
+ * @return rowmatrix, each row is corresponding to the column in the original
+ * matrix and vice versa
+ */
+ public static RowMatrix transposeMatrix(IndexedRowMatrix indexedMatrix) {
+ return indexedMatrix.toCoordinateMatrix().transpose().toRowMatrix();
+ }
+
+ /**
+ * Output matrix to a CSV file.
+ *
+ * @param matrix
+ * spark row matrix
+ * @param rowKeys
+ * matrix row names
+ * @param colKeys
+ * matrix coloum names
+ * @param fileName
+ * csv file name
+ */
+ public static void exportToCSV(RowMatrix matrix, List<String> rowKeys, List<String> colKeys, String fileName) {
+
+ if (matrix.rows().isEmpty()) {
+ return;
+ }
+
+ int rownum = (int) matrix.numRows();
+ int colnum = (int) matrix.numCols();
+ List<Vector> rows = matrix.rows().toJavaRDD().collect();
+
+ File file = new File(fileName);
+ if (file.exists()) {
+ file.delete();
+ }
+ try {
+ file.createNewFile();
+ FileWriter fw = new FileWriter(file.getAbsoluteFile());
+ BufferedWriter bw = new BufferedWriter(fw);
+ String coltitle = " Num" + ",";
+ for (int j = 0; j < colnum; j++) {
+ coltitle += "\"" + colKeys.get(j) + "\",";
+ }
+ coltitle = coltitle.substring(0, coltitle.length() - 1);
+ bw.write(coltitle + "\n");
+
+ for (int i = 0; i < rownum; i++) {
+ double[] rowvlaue = rows.get(i).toArray();
+ String row = rowKeys.get(i) + ",";
+ for (int j = 0; j < colnum; j++) {
+ row += rowvlaue[j] + ",";
+ }
+ row = row.substring(0, row.length() - 1);
+ bw.write(row + "\n");
+ }
+
+ bw.close();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/RDDUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/RDDUtil.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/RDDUtil.java
new file mode 100644
index 0000000..3fc45f4
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/RDDUtil.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.utils;
+
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.function.FlatMapFunction;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * ClassName: RDDUtil Function: Mudrod Spark RDD common methods
+ */
+public class RDDUtil {
+
+ public RDDUtil() {
+ }
+
+ /**
+ * getAllWordsInDoc: Extracted all unique terms from all docs.
+ *
+ * @param docwordRDD Pair RDD, each key is a doc, and value is term list extracted from
+ * that doc.
+ * @return unique term list
+ */
+ public static JavaRDD<String> getAllWordsInDoc(JavaPairRDD<String, List<String>> docwordRDD) {
+ JavaRDD<String> wordRDD = docwordRDD.values().flatMap(new FlatMapFunction<List<String>, String>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Iterator<String> call(List<String> list) {
+ return list.iterator();
+ }
+ }).distinct();
+
+ return wordRDD;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/SVDUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/SVDUtil.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/SVDUtil.java
new file mode 100644
index 0000000..1982996
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/SVDUtil.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.utils;
+
+import gov.nasa.jpl.mudrod.discoveryengine.MudrodAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.mllib.linalg.Vector;
+import org.apache.spark.mllib.linalg.distributed.CoordinateMatrix;
+import org.apache.spark.mllib.linalg.distributed.RowMatrix;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Singular value decomposition
+ */
+public class SVDUtil extends MudrodAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ // wordRDD: terms extracted from all documents
+ JavaRDD<String> wordRDD;
+ // svdMatrix: svd matrix
+ private RowMatrix svdMatrix;
+ // simMatrix: similarity matrix
+ private CoordinateMatrix simMatrix;
+
+ /**
+ * Creates a new instance of SVDUtil.
+ *
+ * @param config the Mudrod configuration
+ * @param es the Elasticsearch drive
+ * @param spark the spark driver
+ */
+ public SVDUtil(Properties config, ESDriver es, SparkDriver spark) {
+ super(config, es, spark);
+ }
+
+ /**
+ * Build SVD matrix from docment-terms pairs.
+ *
+ * @param docwordRDD JavaPairRDD, key is short name of data set and values are terms in
+ * the corresponding data set
+ * @param svdDimension: Dimension of matrix after singular value decomposition
+ * @return row matrix
+ */
+ public RowMatrix buildSVDMatrix(JavaPairRDD<String, List<String>> docwordRDD, int svdDimension) {
+
+ RowMatrix svdMatrix = null;
+ LabeledRowMatrix wordDocMatrix = MatrixUtil.createWordDocMatrix(docwordRDD);
+ RowMatrix ifIdfMatrix = MatrixUtil.createTFIDFMatrix(wordDocMatrix.rowMatrix);
+ svdMatrix = MatrixUtil.buildSVDMatrix(ifIdfMatrix, svdDimension);
+ this.svdMatrix = svdMatrix;
+ this.wordRDD = RDDUtil.getAllWordsInDoc(docwordRDD);
+ return svdMatrix;
+ }
+
+ /**
+ * Build svd matrix from CSV file.
+ *
+ * @param tfidfCSVfile tf-idf matrix csv file
+ * @param svdDimension: Dimension of matrix after singular value decomposition
+ * @return row matrix
+ */
+ public RowMatrix buildSVDMatrix(String tfidfCSVfile, int svdDimension) {
+ RowMatrix svdMatrix = null;
+ JavaPairRDD<String, Vector> tfidfRDD = MatrixUtil.loadVectorFromCSV(spark, tfidfCSVfile, 2);
+ JavaRDD<Vector> vectorRDD = tfidfRDD.values();
+
+ svdMatrix = MatrixUtil.buildSVDMatrix(vectorRDD, svdDimension);
+ this.svdMatrix = svdMatrix;
+
+ this.wordRDD = tfidfRDD.keys();
+
+ return svdMatrix;
+ }
+
+ /**
+ * Calculate similarity
+ */
+ public void calSimilarity() {
+ CoordinateMatrix simMatrix = SimilarityUtil.calculateSimilarityFromMatrix(svdMatrix);
+ this.simMatrix = simMatrix;
+ }
+
+ /**
+ * Insert linkage triples to elasticsearch
+ *
+ * @param index index name
+ * @param type linkage triple name
+ */
+ public void insertLinkageToES(String index, String type) {
+ List<LinkageTriple> triples = SimilarityUtil.matrixToTriples(wordRDD, simMatrix);
+ try {
+ LinkageTriple.insertTriples(es, triples, index, type);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/SimilarityUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/SimilarityUtil.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/SimilarityUtil.java
new file mode 100644
index 0000000..8ae9770
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/SimilarityUtil.java
@@ -0,0 +1,277 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.utils;
+
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.Optional;
+import org.apache.spark.api.java.function.Function;
+import org.apache.spark.api.java.function.PairFunction;
+import org.apache.spark.mllib.linalg.Vector;
+import org.apache.spark.mllib.linalg.distributed.CoordinateMatrix;
+import org.apache.spark.mllib.linalg.distributed.IndexedRowMatrix;
+import org.apache.spark.mllib.linalg.distributed.MatrixEntry;
+import org.apache.spark.mllib.linalg.distributed.RowMatrix;
+import scala.Tuple2;
+
+import java.util.List;
+
+/**
+ * Similarity and distrance calculation utilities
+ */
+public class SimilarityUtil {
+
+ public static final int SIM_COSINE = 3;
+ public static final int SIM_HELLINGER = 2;
+ public static final int SIM_PEARSON = 1;
+ /**
+ * CalSimilarityFromMatrix: Calculate term similarity from matrix.
+ *
+ * @param svdMatrix. Each row is corresponding to a term, and each column is
+ * corresponding to a dimension of feature
+ * @return CoordinateMatrix, each row is corresponding to a term, and each
+ * column is also a term, the cell value is the similarity between the
+ * two terms
+ */
+ public static CoordinateMatrix calculateSimilarityFromMatrix(RowMatrix svdMatrix) {
+ JavaRDD<Vector> vecs = svdMatrix.rows().toJavaRDD();
+ return SimilarityUtil.calculateSimilarityFromVector(vecs);
+ }
+
+ /**
+ * CalSimilarityFromVector:Calculate term similarity from vector.
+ *
+ * @param vecs Each vector is corresponding to a term in the feature space.
+ * @return CoordinateMatrix, each row is corresponding to a term, and each
+ * column is also a term, the cell value is the similarity between the
+ * two terms
+ */
+ public static CoordinateMatrix calculateSimilarityFromVector(JavaRDD<Vector> vecs) {
+ IndexedRowMatrix indexedMatrix = MatrixUtil.buildIndexRowMatrix(vecs);
+ RowMatrix transposeMatrix = MatrixUtil.transposeMatrix(indexedMatrix);
+ return transposeMatrix.columnSimilarities();
+ }
+
+ /**
+ * Calculate term similarity from vector.
+ *
+ * @param importRDD the {@link org.apache.spark.api.java.JavaPairRDD}
+ * data structure containing the vectors.
+ * @param simType the similarity calculation to execute e.g.
+ * <ul>
+ * <li>{@link gov.nasa.jpl.mudrod.utils.SimilarityUtil#SIM_COSINE} - 3,</li>
+ * <li>{@link gov.nasa.jpl.mudrod.utils.SimilarityUtil#SIM_HELLINGER} - 2,</li>
+ * <li>{@link gov.nasa.jpl.mudrod.utils.SimilarityUtil#SIM_PEARSON} - 1</li>
+ * </ul>
+ * @return a new {@link org.apache.spark.api.java.JavaPairRDD}
+ */
+ public static JavaRDD<LinkageTriple> calculateSimilarityFromVector(JavaPairRDD<String, Vector> importRDD, int simType) {
+ JavaRDD<Tuple2<String, Vector>> importRDD1 = importRDD.map(f -> new Tuple2<String, Vector>(f._1, f._2));
+ JavaPairRDD<Tuple2<String, Vector>, Tuple2<String, Vector>> cartesianRDD = importRDD1.cartesian(importRDD1);
+
+ return cartesianRDD.map(new Function<Tuple2<Tuple2<String, Vector>, Tuple2<String, Vector>>, LinkageTriple>() {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public LinkageTriple call(Tuple2<Tuple2<String, Vector>, Tuple2<String, Vector>> arg) {
+ String keyA = arg._1._1;
+ String keyB = arg._2._1;
+
+ if (keyA.equals(keyB)) {
+ return null;
+ }
+
+ Vector vecA = arg._1._2;
+ Vector vecB = arg._2._2;
+ Double weight = 0.0;
+
+ if (simType == SimilarityUtil.SIM_PEARSON) {
+ weight = SimilarityUtil.pearsonDistance(vecA, vecB);
+ } else if (simType == SimilarityUtil.SIM_HELLINGER) {
+ weight = SimilarityUtil.hellingerDistance(vecA, vecB);
+ }
+
+ LinkageTriple triple = new LinkageTriple();
+ triple.keyA = keyA;
+ triple.keyB = keyB;
+ triple.weight = weight;
+ return triple;
+ }
+ }).filter(new Function<LinkageTriple, Boolean>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Boolean call(LinkageTriple arg0) throws Exception {
+ if (arg0 == null) {
+ return false;
+ }
+ return true;
+ }
+ });
+ }
+
+ /**
+ * MatrixtoTriples:Convert term similarity matrix to linkage triple list.
+ *
+ * @param keys each key is a term
+ * @param simMatirx term similarity matrix, in which each row and column is a term and
+ * the cell value is the similarity between the two terms
+ * @return linkage triple list
+ */
+ public static List<LinkageTriple> matrixToTriples(JavaRDD<String> keys, CoordinateMatrix simMatirx) {
+ if (simMatirx.numCols() != keys.count()) {
+ return null;
+ }
+
+ // index words
+ JavaPairRDD<Long, String> keyIdRDD = JavaPairRDD.fromJavaRDD(keys.zipWithIndex().map(new Function<Tuple2<String, Long>, Tuple2<Long, String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<Long, String> call(Tuple2<String, Long> docId) {
+ return docId.swap();
+ }
+ }));
+
+ JavaPairRDD<Long, LinkageTriple> entriesRowRDD = simMatirx.entries().toJavaRDD().mapToPair(new PairFunction<MatrixEntry, Long, LinkageTriple>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<Long, LinkageTriple> call(MatrixEntry t) throws Exception {
+ LinkageTriple triple = new LinkageTriple();
+ triple.keyAId = t.i();
+ triple.keyBId = t.j();
+ triple.weight = t.value();
+ return new Tuple2<>(triple.keyAId, triple);
+ }
+ });
+
+ JavaPairRDD<Long, LinkageTriple> entriesColRDD = entriesRowRDD.leftOuterJoin(keyIdRDD).values().mapToPair(new PairFunction<Tuple2<LinkageTriple, Optional<String>>, Long, LinkageTriple>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Tuple2<Long, LinkageTriple> call(Tuple2<LinkageTriple, Optional<String>> t) throws Exception {
+ LinkageTriple triple = t._1;
+ Optional<String> stra = t._2;
+ if (stra.isPresent()) {
+ triple.keyA = stra.get();
+ }
+ return new Tuple2<>(triple.keyBId, triple);
+ }
+ });
+
+ JavaRDD<LinkageTriple> tripleRDD = entriesColRDD.leftOuterJoin(keyIdRDD).values().map(new Function<Tuple2<LinkageTriple, Optional<String>>, LinkageTriple>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public LinkageTriple call(Tuple2<LinkageTriple, Optional<String>> t) throws Exception {
+ LinkageTriple triple = t._1;
+ Optional<String> strb = t._2;
+ if (strb.isPresent()) {
+ triple.keyB = strb.get();
+ }
+ return triple;
+ }
+ });
+ return tripleRDD.collect();
+ }
+
+ /**
+ * Calculate similarity (Hellinger Distance) between vectors
+ *
+ * @param vecA initial vector from which to calculate a similarity
+ * @param vecB second vector involved in similarity calculation
+ * @return similarity between two vectors
+ */
+ public static double hellingerDistance(Vector vecA, Vector vecB) {
+ double[] arrA = vecA.toArray();
+ double[] arrB = vecB.toArray();
+
+ double sim = 0.0;
+
+ int arrsize = arrA.length;
+ for (int i = 0; i < arrsize; i++) {
+ double a = arrA[i];
+ double b = arrB[i];
+ double sqrtDiff = Math.sqrt(a) - Math.sqrt(b);
+ sim += sqrtDiff * sqrtDiff;
+ }
+
+ sim = sim / Math.sqrt(2);
+
+ return sim;
+ }
+
+ /**
+ * Calculate similarity (Pearson Distance) between vectors
+ *
+ * @param vecA initial vector from which to calculate a similarity
+ * @param vecB second vector involved in similarity calculation
+ * @return similarity between two vectors
+ */
+ public static double pearsonDistance(Vector vecA, Vector vecB) {
+ double[] arrA = vecA.toArray();
+ double[] arrB = vecB.toArray();
+
+ int viewA = 0;
+ int viewB = 0;
+ int viewAB = 0;
+
+ int arrsize = arrA.length;
+ for (int i = 0; i < arrsize; i++) {
+ if (arrA[i] > 0) {
+ viewA++;
+ }
+
+ if (arrB[i] > 0) {
+ viewB++;
+ }
+
+ if (arrB[i] > 0 && arrA[i] > 0) {
+ viewAB++;
+ }
+ }
+ return viewAB / (Math.sqrt(viewA) * Math.sqrt(viewB));
+ }
+
+ /**
+ * calculate similarity between vectors
+ *
+ * @param vecA initial vector from which to calculate a similarity
+ * @param vecB second vector involved in similarity calculation
+ * @return similarity between two vectors
+ */
+ public static double cosineDistance(Vector vecA, Vector vecB) {
+ return 1;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/utils/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/utils/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/utils/package-info.java
new file mode 100644
index 0000000..3fcd95e
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/utils/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes utilities classes for calculating similarity and
+ * parsing HTTP request
+ */
+package gov.nasa.jpl.mudrod.utils;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/package-info.java
new file mode 100644
index 0000000..f4a8b86
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes web log pre-processing, processing, and data structure
+ * classes.
+ */
+package gov.nasa.jpl.mudrod.weblog;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/KGreedyPartitionSolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/KGreedyPartitionSolver.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/KGreedyPartitionSolver.java
new file mode 100644
index 0000000..4397873
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/KGreedyPartitionSolver.java
@@ -0,0 +1,142 @@
+package gov.nasa.jpl.mudrod.weblog.partition;
+
+import java.util.*;
+
+public class KGreedyPartitionSolver implements ThePartitionProblemSolver {
+
+ public boolean bsorted = false;
+
+ public KGreedyPartitionSolver() {
+ // default constructor
+ }
+
+ public KGreedyPartitionSolver(boolean bsorted) {
+ this.bsorted = true;
+ }
+
+ @Override
+ public Map<String, Integer> solve(Map<String, Double> labelNums, int k) {
+ List<Double> lista = null;
+ List<String> months = null;
+
+ if (!this.bsorted) {
+ LinkedHashMap sortedMap = this.sortMapByValue(labelNums);
+ lista = new ArrayList(sortedMap.values());
+ months = new ArrayList(sortedMap.keySet());
+ } else {
+ lista = new ArrayList(labelNums.values());
+ months = new ArrayList(labelNums.keySet());
+ }
+
+ List<List<Double>> parts = new ArrayList<>();
+ List<List<String>> splitMonths = new ArrayList<>();
+
+ for (int i = 0; i < k; i++) {
+ List<Double> part = new ArrayList();
+ parts.add(part);
+
+ List<String> monthList = new ArrayList();
+ splitMonths.add(monthList);
+ }
+
+ int j = 0;
+ for (Double lista1 : lista) {
+
+ Double minimalSum = -1.0;
+ int position = 0;
+ for (int i = 0; i < parts.size(); i++) {
+ List<Double> part = parts.get(i);
+ if (minimalSum == -1) {
+ minimalSum = Suma(part);
+ position = i;
+ } else if (Suma(part) < minimalSum) {
+ minimalSum = Suma(part);
+ position = i;
+ }
+ }
+
+ List<Double> part = parts.get(position);
+ part.add(lista1);
+ parts.set(position, part);
+
+ List<String> month = splitMonths.get(position);
+ month.add(months.get(j));
+ splitMonths.set(position, month);
+ j++;
+ }
+
+ /* for(int i=0; i<splitMonths.size(); i++){
+ System.out.println("group:" + i);
+ printStrList(splitMonths.get(i));
+ }
+
+ for(int i=0; i<parts.size(); i++){
+ print(parts.get(i));
+ }*/
+
+ Map<String, Integer> LabelGroups = new HashMap<String, Integer>();
+ for (int i = 0; i < splitMonths.size(); i++) {
+ List<String> list = splitMonths.get(i);
+ for (int m = 0; m < list.size(); m++) {
+ LabelGroups.put(list.get(m), i);
+ }
+ }
+
+ return LabelGroups;
+ }
+
+ public LinkedHashMap<String, Double> sortMapByValue(Map passedMap) {
+ List mapKeys = new ArrayList(passedMap.keySet());
+ List mapValues = new ArrayList(passedMap.values());
+ Collections.sort(mapValues, Collections.reverseOrder());
+ Collections.sort(mapKeys, Collections.reverseOrder());
+
+ LinkedHashMap sortedMap = new LinkedHashMap();
+
+ Iterator valueIt = mapValues.iterator();
+ while (valueIt.hasNext()) {
+ Object val = valueIt.next();
+ Iterator keyIt = mapKeys.iterator();
+
+ while (keyIt.hasNext()) {
+ Object key = keyIt.next();
+ String comp1 = passedMap.get(key).toString();
+ String comp2 = val.toString();
+
+ if (comp1.equals(comp2)) {
+ passedMap.remove(key);
+ mapKeys.remove(key);
+ sortedMap.put((String) key, (Double) val);
+ break;
+ }
+
+ }
+
+ }
+ return sortedMap;
+ }
+
+ private Double Suma(List<Double> part) {
+ Double ret = 0.0;
+ for (int i = 0; i < part.size(); i++) {
+ ret += part.get(i);
+ }
+ return ret;
+ }
+
+ private void print(List<Double> list) {
+ /*for (int i = 0; i < list.size(); i++) {
+ System.out.print(list.get(i)+",");
+ }*/
+ System.out.print("sum is:" + Suma(list));
+ System.out.println();
+ }
+
+ private void printStrList(List<String> list) {
+ for (int i = 0; i < list.size(); i++) {
+ System.out.print(list.get(i) + ",");
+ }
+ System.out.println();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/ThePartitionProblemSolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/ThePartitionProblemSolver.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/ThePartitionProblemSolver.java
new file mode 100644
index 0000000..11aaed3
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/ThePartitionProblemSolver.java
@@ -0,0 +1,8 @@
+package gov.nasa.jpl.mudrod.weblog.partition;
+
+import java.util.Map;
+
+public interface ThePartitionProblemSolver {
+
+ public Map<String, Integer> solve(Map<String, Double> labelNums, int k);
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/logPartitioner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/logPartitioner.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/logPartitioner.java
new file mode 100644
index 0000000..4c299dd
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/partition/logPartitioner.java
@@ -0,0 +1,33 @@
+package gov.nasa.jpl.mudrod.weblog.partition;
+
+import org.apache.spark.Partitioner;
+
+import java.util.Map;
+
+public class logPartitioner extends Partitioner {
+
+ int num;
+ Map<String, Integer> UserGroups;
+
+ public logPartitioner(int num) {
+ this.num = num;
+ }
+
+ public logPartitioner(Map<String, Integer> UserGroups, int num) {
+ this.UserGroups = UserGroups;
+ this.num = num;
+ }
+
+ @Override
+ public int getPartition(Object arg0) {
+ // TODO Auto-generated method stub
+ String user = (String) arg0;
+ return UserGroups.get(user);
+ }
+
+ @Override
+ public int numPartitions() {
+ // TODO Auto-generated method stub
+ return num;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ClickStreamGenerator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ClickStreamGenerator.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ClickStreamGenerator.java
new file mode 100644
index 0000000..34323df
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ClickStreamGenerator.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.utils.LabeledRowMatrix;
+import gov.nasa.jpl.mudrod.utils.MatrixUtil;
+import gov.nasa.jpl.mudrod.weblog.structure.ClickStream;
+import gov.nasa.jpl.mudrod.weblog.structure.SessionExtractor;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Supports ability to extract click stream data based on session processing results
+ */
+public class ClickStreamGenerator extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(ClickStreamGenerator.class);
+
+ public ClickStreamGenerator(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting ClickStreamGenerator...");
+ startTime = System.currentTimeMillis();
+
+ String clickstremMatrixFile = props.getProperty("clickstreamMatrix");
+ try {
+ SessionExtractor extractor = new SessionExtractor();
+ JavaRDD<ClickStream> clickstreamRDD = extractor.extractClickStreamFromES(this.props, this.es, this.spark);
+ int weight = Integer.parseInt(props.getProperty("downloadWeight"));
+ JavaPairRDD<String, List<String>> metaddataQueryRDD = extractor.bulidDataQueryRDD(clickstreamRDD, weight);
+ LabeledRowMatrix wordDocMatrix = MatrixUtil.createWordDocMatrix(metaddataQueryRDD);
+
+ MatrixUtil.exportToCSV(wordDocMatrix.rowMatrix, wordDocMatrix.rowkeys, wordDocMatrix.colkeys, clickstremMatrixFile);
+ } catch (Exception e) {
+ LOG.error("Encountered error within ClickStreamGenerator: {}", e);
+ }
+
+ endTime = System.currentTimeMillis();
+ LOG.info("ClickStreamGenerator complete. Time elapsed {} seconds.", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/CrawlerDetection.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/CrawlerDetection.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/CrawlerDetection.java
new file mode 100644
index 0000000..80bf33b
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/CrawlerDetection.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.function.FlatMapFunction;
+import org.apache.spark.api.java.function.Function2;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.aggregations.AggregationBuilder;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
+import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
+import org.elasticsearch.search.aggregations.bucket.histogram.Histogram.Order;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.joda.time.DateTime;
+import org.joda.time.Seconds;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * An {@link DiscoveryStepAbstract}
+ * implementation which detects a known list of Web crawlers which may may be
+ * present within, and pollute various logs acting as input to Mudrod.
+ */
+public class CrawlerDetection extends LogAbstract {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(CrawlerDetection.class);
+
+ public static final String CRAWLER = "crawler";
+ public static final String GOOGLE_BOT = "googlebot";
+ public static final String BING_BOT = "bingbot";
+ public static final String YAHOO_BOT = "slurp";
+ public static final String YACY_BOT = "yacybot";
+ public static final String ROGER_BOT = "rogerbot";
+ public static final String YANDEX_BOT = "yandexbot";
+
+ public static final String NO_AGENT_BOT = "-";
+ public static final String PERL_BOT = "libwww-perl/";
+ public static final String APACHE_HHTP = "apache-httpclient/";
+ public static final String JAVA_CLIENT = "java/";
+ public static final String CURL = "curl/";
+
+ /**
+ * Paramterized constructor to instantiate a configured instance of
+ * {@link CrawlerDetection}
+ *
+ * @param props populated {@link java.util.Properties} object
+ * @param es {@link ESDriver} object to use in
+ * crawler detection preprocessing.
+ * @param spark {@link SparkDriver} object to use in
+ * crawler detection preprocessing.
+ */
+ public CrawlerDetection(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ public CrawlerDetection() {
+ super(null, null, null);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting Crawler detection {}.", httpType);
+ startTime = System.currentTimeMillis();
+ try {
+ checkByRate();
+ } catch (InterruptedException | IOException e) {
+ LOG.error("Encountered an error whilst detecting Web crawlers.", e);
+ }
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("Crawler detection complete. Time elapsed {} seconds", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ /**
+ * Check known crawler through crawler agent name list
+ *
+ * @param agent name of a log line
+ * @return 1 if the log is initiated by crawler, 0 otherwise
+ */
+ public boolean checkKnownCrawler(String agent) {
+ agent = agent.toLowerCase();
+ if (agent.contains(CRAWLER) || agent.contains(GOOGLE_BOT) || agent.contains(BING_BOT) || agent.contains(APACHE_HHTP) || agent.contains(PERL_BOT) || agent.contains(YAHOO_BOT) || agent
+ .contains(YANDEX_BOT) || agent.contains(NO_AGENT_BOT) || agent.contains(PERL_BOT) || agent.contains(APACHE_HHTP) || agent.contains(JAVA_CLIENT) || agent.contains(CURL)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void checkByRate() throws InterruptedException, IOException {
+ String processingType = props.getProperty(MudrodConstants.PROCESS_TYPE);
+ if (processingType.equals("sequential")) {
+ checkByRateInSequential();
+ } else if (processingType.equals("parallel")) {
+ checkByRateInParallel();
+ }
+ }
+
+ /**
+ * Check crawler by request sending rate, which is read from configruation
+ * file
+ *
+ * @throws InterruptedException InterruptedException
+ * @throws IOException IOException
+ */
+ public void checkByRateInSequential() throws InterruptedException, IOException {
+ es.createBulkProcessor();
+
+ int rate = Integer.parseInt(props.getProperty("sendingrate"));
+
+ Terms users = this.getUserTerms(this.httpType);
+ LOG.info("Original User count: {}", Integer.toString(users.getBuckets().size()));
+
+ int userCount = 0;
+ for (Terms.Bucket entry : users.getBuckets()) {
+ String user = entry.getKey().toString();
+ int count = checkByRate(es, user);
+ userCount += count;
+ }
+ es.destroyBulkProcessor();
+ LOG.info("User count: {}", Integer.toString(userCount));
+ }
+
+ void checkByRateInParallel() throws InterruptedException, IOException {
+
+ JavaRDD<String> userRDD = getUserRDD(this.httpType);
+ LOG.info("Original User count: {}", userRDD.count());
+
+ int userCount = 0;
+ userCount = userRDD.mapPartitions((FlatMapFunction<Iterator<String>, Integer>) iterator -> {
+ ESDriver tmpES = new ESDriver(props);
+ tmpES.createBulkProcessor();
+ List<Integer> realUserNums = new ArrayList<>();
+ while (iterator.hasNext()) {
+ String s = iterator.next();
+ Integer realUser = checkByRate(tmpES, s);
+ realUserNums.add(realUser);
+ }
+ tmpES.destroyBulkProcessor();
+ tmpES.close();
+ return realUserNums.iterator();
+ }).reduce((Function2<Integer, Integer, Integer>) (a, b) -> a + b);
+
+ LOG.info("User count: {}", Integer.toString(userCount));
+ }
+
+ private int checkByRate(ESDriver es, String user) {
+
+ int rate = Integer.parseInt(props.getProperty("sendingrate"));
+ Pattern pattern = Pattern.compile("get (.*?) http/*");
+ Matcher matcher;
+
+ BoolQueryBuilder filterSearch = new BoolQueryBuilder();
+ filterSearch.must(QueryBuilders.termQuery("IP", user));
+
+ AggregationBuilder aggregation = AggregationBuilders.dateHistogram("by_minute").field("Time").dateHistogramInterval(DateHistogramInterval.MINUTE).order(Order.COUNT_DESC);
+ SearchResponse checkRobot = es.getClient().prepareSearch(logIndex).setTypes(httpType, ftpType).setQuery(filterSearch).setSize(0).addAggregation(aggregation).execute().actionGet();
+
+ Histogram agg = checkRobot.getAggregations().get("by_minute");
+
+ List<? extends Histogram.Bucket> botList = agg.getBuckets();
+ long maxCount = botList.get(0).getDocCount();
+ if (maxCount >= rate) {
+ return 0;
+ } else {
+ DateTime dt1 = null;
+ int toLast = 0;
+ SearchResponse scrollResp = es.getClient().prepareSearch(logIndex).setTypes(httpType, ftpType).setScroll(new TimeValue(60000)).setQuery(filterSearch).setSize(100).execute().actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String logtype = (String) result.get("LogType");
+ if (logtype.equals("PO.DAAC")) {
+ String request = (String) result.get("Request");
+ matcher = pattern.matcher(request.trim().toLowerCase());
+ boolean find = false;
+ while (matcher.find()) {
+ request = matcher.group(1);
+ result.put("RequestUrl", "http://podaac.jpl.nasa.gov" + request);
+ find = true;
+ }
+ if (!find) {
+ result.put("RequestUrl", request);
+ }
+ } else {
+ result.put("RequestUrl", result.get("Request"));
+ }
+
+ DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+ DateTime dt2 = fmt.parseDateTime((String) result.get("Time"));
+
+ if (dt1 == null) {
+ toLast = 0;
+ } else {
+ toLast = Math.abs(Seconds.secondsBetween(dt1, dt2).getSeconds());
+ }
+ result.put("ToLast", toLast);
+ IndexRequest ir = new IndexRequest(logIndex, cleanupType).source(result);
+
+ es.getBulkProcessor().add(ir);
+ dt1 = dt2;
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ }
+
+ return 1;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/HistoryGenerator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/HistoryGenerator.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/HistoryGenerator.java
new file mode 100644
index 0000000..d5dc102
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/HistoryGenerator.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Supports ability to generate search history (queries) for each individual
+ * user (IP)
+ */
+public class HistoryGenerator extends LogAbstract {
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(HistoryGenerator.class);
+
+ public HistoryGenerator(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting HistoryGenerator...");
+ startTime = System.currentTimeMillis();
+
+ generateBinaryMatrix();
+
+ endTime = System.currentTimeMillis();
+ LOG.info("HistoryGenerator complete. Time elapsed {} seconds", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ /**
+ * Method to generate a binary user*query matrix (stored in temporary .csv
+ * file)
+ */
+ public void generateBinaryMatrix() {
+ try {
+
+ System.out.println(props.getProperty("userHistoryMatrix"));
+ File file = new File(props.getProperty("userHistoryMatrix"));
+ if (file.exists()) {
+ file.delete();
+ }
+
+ file.createNewFile();
+
+ FileWriter fw = new FileWriter(file.getAbsoluteFile());
+ BufferedWriter bw = new BufferedWriter(fw);
+ bw.write("Num" + ",");
+
+ // step 1: write first row of csv
+ List<String> logIndexList = es.getIndexListWithPrefix(props.getProperty(MudrodConstants.LOG_INDEX));
+
+ String[] logIndices = logIndexList.toArray(new String[0]);
+ String[] statictypeArray = new String[] { this.sessionStats };
+ int docCount = es.getDocCount(logIndices, statictypeArray);
+
+ SearchResponse sr = es.getClient().prepareSearch(logIndices).setTypes(statictypeArray).setQuery(QueryBuilders.matchAllQuery()).setSize(0)
+ .addAggregation(AggregationBuilders.terms("IPs").field("IP").size(docCount)).execute().actionGet();
+ Terms ips = sr.getAggregations().get("IPs");
+ List<String> ipList = new ArrayList<>();
+ for (Terms.Bucket entry : ips.getBuckets()) {
+ if (entry.getDocCount() > Integer.parseInt(props.getProperty(MudrodConstants.MINI_USER_HISTORY))) { // filter
+ // out
+ // less
+ // active users/ips
+ ipList.add(entry.getKey().toString());
+ }
+ }
+ bw.write(String.join(",", ipList) + "\n");
+
+ // step 2: step the rest rows of csv
+ SearchRequestBuilder sr2Builder = es.getClient().prepareSearch(logIndices).setTypes(statictypeArray).setQuery(QueryBuilders.matchAllQuery()).setSize(0)
+ .addAggregation(AggregationBuilders.terms("KeywordAgg").field("keywords").size(docCount).subAggregation(AggregationBuilders.terms("IPAgg").field("IP").size(docCount)));
+
+ SearchResponse sr2 = sr2Builder.execute().actionGet();
+ Terms keywords = sr2.getAggregations().get("KeywordAgg");
+
+ for (Terms.Bucket keyword : keywords.getBuckets()) {
+
+ Map<String, Integer> ipMap = new HashMap<>();
+ Terms ipAgg = keyword.getAggregations().get("IPAgg");
+
+ int distinctUser = ipAgg.getBuckets().size();
+ if (distinctUser > Integer.parseInt(props.getProperty(MudrodConstants.MINI_USER_HISTORY))) {
+ bw.write(keyword.getKey() + ",");
+ for (Terms.Bucket IP : ipAgg.getBuckets()) {
+
+ ipMap.put(IP.getKey().toString(), 1);
+ }
+ for (int i = 0; i < ipList.size(); i++) {
+ if (ipMap.containsKey(ipList.get(i))) {
+ bw.write(ipMap.get(ipList.get(i)) + ",");
+ } else {
+ bw.write("0,");
+ }
+ }
+ bw.write("\n");
+ }
+ }
+
+ bw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
[20/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 0000000..c63d005
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,324 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>gov.nasa.jpl.mudrod</groupId>
+ <artifactId>mudrod-parent</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <relativePath>../</relativePath>
+ </parent>
+
+ <artifactId>mudrod-core</artifactId>
+
+ <name>Mudrod :: Core</name>
+ <description>Core Mudrod library implementation.</description>
+
+ <properties>
+ <!-- This property is the name of the directory containing the SVM/SGD Model. It is used during build to create a zip file from this directory -->
+ <svmSgdModel.value>javaSVMWithSGDModel</svmSgdModel.value>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jdom</groupId>
+ <artifactId>jdom</artifactId>
+ </dependency>
+
+ <!-- Elasticsearch dependencies -->
+ <dependency>
+ <groupId>org.elasticsearch</groupId>
+ <artifactId>elasticsearch</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.elasticsearch.client</groupId>
+ <artifactId>transport</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.elasticsearch.plugin</groupId>
+ <artifactId>transport-netty4-client</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.elasticsearch</groupId>
+ <artifactId>elasticsearch-spark-20_2.11</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.carrotsearch</groupId>
+ <artifactId>hppc</artifactId>
+ </dependency>
+ <!-- End of Elasticsearch dependencies -->
+
+ <!-- Spark dependencies -->
+ <dependency>
+ <groupId>org.apache.spark</groupId>
+ <artifactId>spark-core_2.11</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.spark</groupId>
+ <artifactId>spark-sql_2.11</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.spark</groupId>
+ <artifactId>spark-mllib_2.11</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.github.fommil.netlib</groupId>
+ <artifactId>all</artifactId>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ </dependency>
+
+ <dependency>
+ <!-- Needed to run the Spark UI during log ingestion -->
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ <scope>compile</scope>
+ </dependency>
+ <!-- End of Spark dependencies -->
+
+ <dependency>
+ <groupId>org.codehaus.jettison</groupId>
+ <artifactId>jettison</artifactId>
+ <version>1.3.8</version>
+ </dependency>
+
+ <!-- Logging dependencies -->
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ </dependency>
+ <!-- End of Logging dependencies -->
+
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>net.sf.opencsv</groupId>
+ <artifactId>opencsv</artifactId>
+ <version>2.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/main/resources</directory>
+ <filtering>true</filtering>
+ <excludes>
+ <exclude>${svmSgdModel.value}/**</exclude>
+ </excludes>
+ </resource>
+
+ <resource>
+ <directory>${project.build.directory}</directory>
+ <includes>
+ <include>${svmSgdModel.value}.zip</include>
+ </includes>
+ </resource>
+
+ <resource>
+ <directory>${basedir}/../</directory>
+ <targetPath>META-INF</targetPath>
+ <includes>
+ <include>LICENSE.txt</include>
+ <include>NOTICE.txt</include>
+ </includes>
+ </resource>
+ </resources>
+
+ <plugins>
+ <!-- generates the bin launchers -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>appassembler-maven-plugin</artifactId>
+ <version>1.10</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>assemble</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <repositoryLayout>flat</repositoryLayout>
+ <repositoryName>lib</repositoryName>
+ <programs>
+ <program>
+ <mainClass>gov.nasa.jpl.mudrod.main.MudrodEngine
+ </mainClass>
+ <name>mudrod-engine</name>
+ </program>
+ </programs>
+ </configuration>
+ </plugin>
+
+ <!-- Generates the distribution package -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>zipSVMWithSGDModel</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <appendAssemblyId>false</appendAssemblyId>
+ <tarLongFileMode>posix</tarLongFileMode>
+ <finalName>${svmSgdModel.value}</finalName>
+ <outputDirectory>${project.build.directory}
+ </outputDirectory>
+ <descriptors>
+ <descriptor>
+ ${basedir}/src/main/assembly/zipSVMWithSGDModel.xml
+ </descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>generateDistribution</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <appendAssemblyId>false</appendAssemblyId>
+ <tarLongFileMode>posix</tarLongFileMode>
+ <descriptors>
+ <descriptor>
+ ${basedir}/src/main/assembly/bin.xml
+ </descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.0.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>3.0.0</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <transformers>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <manifestEntries>
+ <Main-Class>
+ gov.nasa.jpl.mudrod.main.MudrodEngine
+ </Main-Class>
+ <Build-Number>${implementation.build}
+ </Build-Number>
+ </manifestEntries>
+ </transformer>
+ </transformers>
+ <filters>
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <exclude>META-INF/*.SF</exclude>
+ <exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ <finalName>
+ ${project.artifactId}-uber-${project.version}
+ </finalName>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <resources>
+ <resource>
+ <directory>${basedir}/../</directory>
+ <targetPath>
+ ${project.build.directory}/apidocs/META-INF
+ </targetPath>
+ <includes>
+ <include>LICENSE.txt</include>
+ <include>NOTICE.txt</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/assembly/bin.xml
----------------------------------------------------------------------
diff --git a/core/src/main/assembly/bin.xml b/core/src/main/assembly/bin.xml
new file mode 100644
index 0000000..7977d65
--- /dev/null
+++ b/core/src/main/assembly/bin.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>bin</id>
+ <formats>
+ <format>tar.gz</format>
+ <format>zip</format>
+ </formats>
+ <fileSets>
+ <fileSet>
+ <directory>target/appassembler/bin</directory>
+ <outputDirectory>bin</outputDirectory>
+ <excludes>
+ <exclude>*.bat</exclude>
+ </excludes>
+ <lineEnding>unix</lineEnding>
+ <directoryMode>0755</directoryMode>
+ <fileMode>0644</fileMode>
+ </fileSet>
+ <fileSet>
+ <directory>target/appassembler/bin</directory>
+ <outputDirectory>bin</outputDirectory>
+ <includes>
+ <include>*.bat</include>
+ </includes>
+ <lineEnding>dos</lineEnding>
+ <directoryMode>0755</directoryMode>
+ <fileMode>0644</fileMode>
+ </fileSet>
+ <fileSet>
+ <directory>target/appassembler/lib</directory>
+ <outputDirectory>lib</outputDirectory>
+ </fileSet>
+ </fileSets>
+</assembly>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/assembly/zipSVMWithSGDModel.xml
----------------------------------------------------------------------
diff --git a/core/src/main/assembly/zipSVMWithSGDModel.xml b/core/src/main/assembly/zipSVMWithSGDModel.xml
new file mode 100644
index 0000000..aec117f
--- /dev/null
+++ b/core/src/main/assembly/zipSVMWithSGDModel.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>zipSVMWithSGDModel</id>
+ <baseDirectory>${svmSgdModel.value}</baseDirectory>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <fileSets>
+ <fileSet>
+ <directory>${basedir}/src/main/resources/${svmSgdModel.value}</directory>
+ <outputDirectory>.</outputDirectory>
+ </fileSet>
+ </fileSets>
+</assembly>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryEngineAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryEngineAbstract.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryEngineAbstract.java
new file mode 100644
index 0000000..2de9cf6
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryEngineAbstract.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.discoveryengine;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+public abstract class DiscoveryEngineAbstract extends MudrodAbstract implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public DiscoveryEngineAbstract(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Abstract method of preprocess
+ */
+ public abstract void preprocess();
+
+ /**
+ * Abstract method of process
+ */
+ public abstract void process();
+
+ /**
+ * Abstract method of output
+ */
+ public abstract void output();
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryStepAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryStepAbstract.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryStepAbstract.java
new file mode 100644
index 0000000..94e8094
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/DiscoveryStepAbstract.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.discoveryengine;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+
+import java.util.Properties;
+
+/*
+ * Generic class of discovery engine step
+ */
+public abstract class DiscoveryStepAbstract extends MudrodAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ public DiscoveryStepAbstract(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Abstract class of step execution without parameter
+ *
+ * @return An instance of Object
+ */
+ public abstract Object execute();
+
+ /**
+ * Abstract class of step execution with parameter
+ *
+ * @param o an instance of object
+ * @return An instance of object
+ */
+ public abstract Object execute(Object o);
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MetadataDiscoveryEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MetadataDiscoveryEngine.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MetadataDiscoveryEngine.java
new file mode 100644
index 0000000..e994825
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MetadataDiscoveryEngine.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.discoveryengine;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.metadata.pre.ApiHarvester;
+import gov.nasa.jpl.mudrod.metadata.pre.MatrixGenerator;
+import gov.nasa.jpl.mudrod.metadata.process.MetadataAnalyzer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+/**
+ * Supports to preprocess and process metadata
+ */
+public class MetadataDiscoveryEngine extends DiscoveryEngineAbstract implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(MetadataDiscoveryEngine.class);
+
+ public MetadataDiscoveryEngine(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Method of preprocessing metadata
+ */
+ public void preprocess() {
+ LOG.info("Starting metadata preprocessing...");
+ startTime = System.currentTimeMillis();
+
+ DiscoveryStepAbstract harvester = new ApiHarvester(this.props, this.es, this.spark);
+ harvester.execute();
+
+ endTime = System.currentTimeMillis();
+ LOG.info("Finished metadata preprocessing. Time elapsed: {}s", (endTime - startTime) / 1000);
+ }
+
+ /**
+ * Method of processing metadata
+ */
+ public void process() {
+ LOG.info("Starting metadata processing...");
+ startTime = System.currentTimeMillis();
+
+ DiscoveryStepAbstract matrix = new MatrixGenerator(this.props, this.es, this.spark);
+ matrix.execute();
+
+ DiscoveryStepAbstract svd = new MetadataAnalyzer(this.props, this.es, this.spark);
+ svd.execute();
+
+ endTime = System.currentTimeMillis();
+ LOG.info("Finished metadata processing. Time elapsed: {}s", (endTime - startTime) / 1000);
+ }
+
+ public void output() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MudrodAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MudrodAbstract.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MudrodAbstract.java
new file mode 100644
index 0000000..b3f1831
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/MudrodAbstract.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.discoveryengine;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import org.apache.commons.io.IOUtils;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.CheckForNull;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.Properties;
+
+/**
+ * This is the most generic class of Mudrod
+ */
+public abstract class MudrodAbstract implements Serializable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MudrodAbstract.class);
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ protected Properties props = new Properties();
+ protected ESDriver es = null;
+ protected SparkDriver spark = null;
+ protected long startTime;
+ protected long endTime;
+
+ protected static final String ES_SETTINGS = "elastic_settings.json";
+ protected static final String ES_MAPPINGS = "elastic_mappings.json";
+
+ public MudrodAbstract(Properties props, ESDriver es, SparkDriver spark) {
+ this.props = props;
+ this.es = es;
+ this.spark = spark;
+
+ if (this.props != null) {
+ this.initMudrod();
+ }
+ }
+
+ /**
+ * Method of setting up essential configuration for MUDROD to start
+ */
+ @CheckForNull
+ protected void initMudrod() {
+ InputStream settingsStream = getClass().getClassLoader().getResourceAsStream(ES_SETTINGS);
+ InputStream mappingsStream = getClass().getClassLoader().getResourceAsStream(ES_MAPPINGS);
+ JSONObject settingsJSON = null;
+ JSONObject mappingJSON = null;
+
+ try {
+ settingsJSON = new JSONObject(IOUtils.toString(settingsStream));
+ } catch (JSONException | IOException e1) {
+ LOG.error("Error reading Elasticsearch settings!", e1);
+ }
+
+ try {
+ mappingJSON = new JSONObject(IOUtils.toString(mappingsStream));
+ } catch (JSONException | IOException e1) {
+ LOG.error("Error reading Elasticsearch mappings!", e1);
+ }
+
+ try {
+ if (settingsJSON != null && mappingJSON != null) {
+ this.es.putMapping(props.getProperty(MudrodConstants.ES_INDEX_NAME), settingsJSON.toString(), mappingJSON.toString());
+ }
+ } catch (IOException e) {
+ LOG.error("Error entering Elasticsearch Mappings!", e);
+ }
+ }
+
+ /**
+ * Get driver of Elasticsearch
+ *
+ * @return driver of Elasticsearch
+ */
+ public ESDriver getES() {
+ return this.es;
+ }
+
+ /**
+ * Get configuration of MUDROD (read from configuration file)
+ *
+ * @return configuration of MUDROD
+ */
+ public Properties getConfig() {
+ return this.props;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/OntologyDiscoveryEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/OntologyDiscoveryEngine.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/OntologyDiscoveryEngine.java
new file mode 100644
index 0000000..fe8066f
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/OntologyDiscoveryEngine.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.discoveryengine;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.ontology.pre.AggregateTriples;
+import gov.nasa.jpl.mudrod.ontology.process.OntologyLinkCal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+/**
+ * Supports to preprocess and process ontology
+ */
+public class OntologyDiscoveryEngine extends DiscoveryEngineAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(OntologyDiscoveryEngine.class);
+
+ public OntologyDiscoveryEngine(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Method of preprocessing ontology
+ */
+ public void preprocess() {
+ LOG.info("*****************Ontology preprocessing starts******************");
+ startTime = System.currentTimeMillis();
+
+ DiscoveryStepAbstract at = new AggregateTriples(this.props, this.es, this.spark);
+ at.execute();
+
+ endTime = System.currentTimeMillis();
+ LOG.info("*****************Ontology preprocessing ends******************Took {}s", (endTime - startTime) / 1000);
+ }
+
+ /**
+ * Method of processing ontology
+ */
+ public void process() {
+ LOG.info("*****************Ontology processing starts******************");
+ startTime = System.currentTimeMillis();
+
+ DiscoveryStepAbstract ol = new OntologyLinkCal(this.props, this.es, this.spark);
+ ol.execute();
+
+ endTime = System.currentTimeMillis();
+ LOG.info("*****************Ontology processing ends******************Took {}s", (endTime - startTime) / 1000);
+ }
+
+ public void output() {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/RecommendEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/RecommendEngine.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/RecommendEngine.java
new file mode 100644
index 0000000..9805b79
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/RecommendEngine.java
@@ -0,0 +1,77 @@
+package gov.nasa.jpl.mudrod.discoveryengine;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.recommendation.pre.ImportMetadata;
+import gov.nasa.jpl.mudrod.recommendation.pre.MetadataTFIDFGenerator;
+import gov.nasa.jpl.mudrod.recommendation.pre.NormalizeVariables;
+import gov.nasa.jpl.mudrod.recommendation.pre.SessionCooccurence;
+import gov.nasa.jpl.mudrod.recommendation.process.AbstractBasedSimilarity;
+import gov.nasa.jpl.mudrod.recommendation.process.VariableBasedSimilarity;
+import gov.nasa.jpl.mudrod.recommendation.process.sessionBasedCF;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+public class RecommendEngine extends DiscoveryEngineAbstract {
+
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(RecommendEngine.class);
+
+ public RecommendEngine(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ LOG.info("Started Mudrod Recommend Engine.");
+ }
+
+ @Override
+ public void preprocess() {
+ LOG.info("*****************Recommendation preprocessing starts******************");
+
+ startTime = System.currentTimeMillis();
+
+ DiscoveryStepAbstract harvester = new ImportMetadata(this.props, this.es, this.spark);
+ harvester.execute();
+
+ DiscoveryStepAbstract tfidf = new MetadataTFIDFGenerator(this.props, this.es, this.spark);
+ tfidf.execute();
+
+ DiscoveryStepAbstract sessionMatrixGen = new SessionCooccurence(this.props, this.es, this.spark);
+ sessionMatrixGen.execute();
+
+ DiscoveryStepAbstract transformer = new NormalizeVariables(this.props, this.es, this.spark);
+ transformer.execute();
+
+ endTime = System.currentTimeMillis();
+
+ LOG.info("*****************Recommendation preprocessing ends******************Took {}s {}", (endTime - startTime) / 1000);
+ }
+
+ @Override
+ public void process() {
+ // TODO Auto-generated method stub
+ LOG.info("*****************Recommendation processing starts******************");
+
+ startTime = System.currentTimeMillis();
+
+ DiscoveryStepAbstract tfCF = new AbstractBasedSimilarity(this.props, this.es, this.spark);
+ tfCF.execute();
+
+ DiscoveryStepAbstract cbCF = new VariableBasedSimilarity(this.props, this.es, this.spark);
+ cbCF.execute();
+
+ DiscoveryStepAbstract sbCF = new sessionBasedCF(this.props, this.es, this.spark);
+ sbCF.execute();
+
+ endTime = System.currentTimeMillis();
+
+ LOG.info("*****************Recommendation processing ends******************Took {}s {}", (endTime - startTime) / 1000);
+ }
+
+ @Override
+ public void output() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/WeblogDiscoveryEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/WeblogDiscoveryEngine.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/WeblogDiscoveryEngine.java
new file mode 100644
index 0000000..4657222
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/WeblogDiscoveryEngine.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.discoveryengine;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.weblog.pre.*;
+import gov.nasa.jpl.mudrod.weblog.process.ClickStreamAnalyzer;
+import gov.nasa.jpl.mudrod.weblog.process.UserHistoryAnalyzer;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Supports to preprocess and process web log
+ */
+public class WeblogDiscoveryEngine extends DiscoveryEngineAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(WeblogDiscoveryEngine.class);
+ public String timeSuffix = null;
+
+ public WeblogDiscoveryEngine(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ LOG.info("Started Mudrod Weblog Discovery Engine.");
+ }
+
+ /**
+ * Get log file list from a directory
+ *
+ * @param logDir path to directory containing logs either local or in HDFS.
+ * @return a list of log files
+ */
+ public List<String> getFileList(String logDir) {
+
+ ArrayList<String> inputList = new ArrayList<>();
+ if (!logDir.startsWith("hdfs://")) {
+ File directory = new File(logDir);
+ File[] fList = directory.listFiles();
+ for (File file : fList) {
+ if (file.isFile() && file.getName().matches(".*\\d+.*") && file.getName().contains(props.getProperty(MudrodConstants.HTTP_PREFIX))) {
+ inputList.add(file.getName().replace(props.getProperty(MudrodConstants.HTTP_PREFIX), ""));
+ }
+ }
+ } else {
+ Configuration conf = new Configuration();
+ try (FileSystem fs = FileSystem.get(new URI(logDir), conf)) {
+ FileStatus[] fileStatus;
+ fileStatus = fs.listStatus(new Path(logDir));
+ for (FileStatus status : fileStatus) {
+ String path1 = status.getPath().toString();
+ if (path1.matches(".*\\d+.*") && path1.contains(props.getProperty(MudrodConstants.HTTP_PREFIX))) {
+
+ String time = path1.substring(path1.lastIndexOf('.') + 1);
+ inputList.add(time);
+ }
+ }
+ } catch (IllegalArgumentException | IOException | URISyntaxException e) {
+ LOG.error("An error occured whilst obtaining the log file list.", e);
+ }
+ }
+
+ return inputList;
+ }
+
+ /**
+ * Method of preprocessing web logs, generating vocab similarity based on web
+ * logs
+ */
+ @Override
+ public void preprocess() {
+ LOG.info("Starting Web log preprocessing.");
+
+ ArrayList<String> inputList = (ArrayList<String>) getFileList(props.getProperty(MudrodConstants.DATA_DIR));
+
+ for (int i = 0; i < inputList.size(); i++) {
+ timeSuffix = inputList.get(i);
+ props.put(MudrodConstants.TIME_SUFFIX, timeSuffix);
+ startTime = System.currentTimeMillis();
+ LOG.info("Processing logs dated {}", inputList.get(i));
+
+ DiscoveryStepAbstract im = new ImportLogFile(this.props, this.es, this.spark);
+ im.execute();
+
+ DiscoveryStepAbstract cd = new CrawlerDetection(this.props, this.es, this.spark);
+ cd.execute();
+
+ DiscoveryStepAbstract sg = new SessionGenerator(this.props, this.es, this.spark);
+ sg.execute();
+
+ DiscoveryStepAbstract ss = new SessionStatistic(this.props, this.es, this.spark);
+ ss.execute();
+
+ DiscoveryStepAbstract rr = new RemoveRawLog(this.props, this.es, this.spark);
+ rr.execute();
+
+ endTime = System.currentTimeMillis();
+
+ LOG.info("Web log preprocessing for logs dated {} complete. Time elapsed {} seconds.", inputList.get(i), (endTime - startTime) / 1000);
+ }
+
+ DiscoveryStepAbstract hg = new HistoryGenerator(this.props, this.es, this.spark);
+ hg.execute();
+
+ DiscoveryStepAbstract cg = new ClickStreamGenerator(this.props, this.es, this.spark);
+ cg.execute();
+
+ LOG.info("Web log preprocessing (user history and clickstream) complete.");
+ }
+
+ /**
+ * Method of web log ingest
+ */
+ public void logIngest() {
+ LOG.info("Starting Web log ingest.");
+ ArrayList<String> inputList = (ArrayList<String>) getFileList(props.getProperty(MudrodConstants.DATA_DIR));
+ for (int i = 0; i < inputList.size(); i++) {
+ timeSuffix = inputList.get(i);
+ props.put("TimeSuffix", timeSuffix);
+ DiscoveryStepAbstract im = new ImportLogFile(this.props, this.es, this.spark);
+ im.execute();
+ }
+
+ LOG.info("Web log ingest complete.");
+
+ }
+
+ /**
+ * Method of reconstructing user sessions from raw web logs
+ */
+ public void sessionRestruct() {
+ LOG.info("Starting Session reconstruction.");
+ ArrayList<String> inputList = (ArrayList<String>) getFileList(props.getProperty(MudrodConstants.DATA_DIR));
+ for (int i = 0; i < inputList.size(); i++) {
+ timeSuffix = inputList.get(i); // change timeSuffix dynamically
+ props.put(MudrodConstants.TIME_SUFFIX, timeSuffix);
+ DiscoveryStepAbstract cd = new CrawlerDetection(this.props, this.es, this.spark);
+ cd.execute();
+
+ DiscoveryStepAbstract sg = new SessionGenerator(this.props, this.es, this.spark);
+ sg.execute();
+
+ DiscoveryStepAbstract ss = new SessionStatistic(this.props, this.es, this.spark);
+ ss.execute();
+
+ DiscoveryStepAbstract rr = new RemoveRawLog(this.props, this.es, this.spark);
+ rr.execute();
+
+ endTime = System.currentTimeMillis();
+ }
+ LOG.info("Session reconstruction complete.");
+ }
+
+ @Override
+ public void process() {
+ LOG.info("Starting Web log processing.");
+ startTime = System.currentTimeMillis();
+
+ DiscoveryStepAbstract svd = new ClickStreamAnalyzer(this.props, this.es, this.spark);
+ svd.execute();
+
+ DiscoveryStepAbstract ua = new UserHistoryAnalyzer(this.props, this.es, this.spark);
+ ua.execute();
+
+ endTime = System.currentTimeMillis();
+ LOG.info("Web log processing complete. Time elaspsed {} seconds.", (endTime - startTime) / 1000);
+ }
+
+ @Override
+ public void output() {
+ // not implemented yet!
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/package-info.java
new file mode 100644
index 0000000..21e528e
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/discoveryengine/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes abstract classes of MUDROD, discovery step, and engine.
+ * Workflow classes such as weblogDiscoveryEngine, OntologyDiscoveryEngine, and
+ * MetadataDiscoveryEngine are also included here.
+ */
+package gov.nasa.jpl.mudrod.discoveryengine;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/driver/ESDriver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/driver/ESDriver.java b/core/src/main/java/gov/nasa/jpl/mudrod/driver/ESDriver.java
new file mode 100644
index 0000000..d1af04a
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/driver/ESDriver.java
@@ -0,0 +1,572 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.driver;
+
+import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
+import com.google.gson.GsonBuilder;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import gov.nasa.jpl.mudrod.utils.ESTransportClient;
+import org.apache.commons.lang.StringUtils;
+import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
+import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse.AnalyzeToken;
+import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
+import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
+import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
+import org.elasticsearch.action.bulk.BackoffPolicy;
+import org.elasticsearch.action.bulk.BulkProcessor;
+import org.elasticsearch.action.bulk.BulkRequest;
+import org.elasticsearch.action.bulk.BulkResponse;
+import org.elasticsearch.action.delete.DeleteRequest;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.search.SearchType;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.client.transport.TransportClient;
+import org.elasticsearch.cluster.metadata.MappingMetaData;
+import org.elasticsearch.common.collect.ImmutableOpenMap;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.transport.InetSocketTransportAddress;
+import org.elasticsearch.common.unit.ByteSizeUnit;
+import org.elasticsearch.common.unit.ByteSizeValue;
+import org.elasticsearch.common.unit.Fuzziness;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.MatchAllQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.node.Node;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.suggest.Suggest;
+import org.elasticsearch.search.suggest.SuggestBuilder;
+import org.elasticsearch.search.suggest.SuggestBuilders;
+import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * Driver implementation for all Elasticsearch functionality.
+ */
+public class ESDriver implements Serializable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ESDriver.class);
+ private static final long serialVersionUID = 1L;
+ private transient Client client = null;
+ private transient Node node = null;
+ private transient BulkProcessor bulkProcessor = null;
+
+ /**
+ * Default constructor for this class. To load client configuration call
+ * substantiated constructor.
+ */
+ public ESDriver() {
+ // Default constructor, to load configuration call ESDriver(props)
+ }
+
+ /**
+ * Substantiated constructor which accepts a {@link java.util.Properties}
+ *
+ * @param props a populated properties object.
+ */
+ public ESDriver(Properties props) {
+ try {
+ setClient(makeClient(props));
+ } catch (IOException e) {
+ LOG.error("Error whilst constructing Elastcisearch client.", e);
+ }
+ }
+
+ public void createBulkProcessor() {
+ LOG.debug("Creating BulkProcessor with maxBulkDocs={}, maxBulkLength={}", 1000, 2500500);
+ setBulkProcessor(BulkProcessor.builder(getClient(), new BulkProcessor.Listener() {
+ @Override
+ public void beforeBulk(long executionId, BulkRequest request) {
+ LOG.debug("ESDriver#createBulkProcessor @Override #beforeBulk is not implemented yet!");
+ }
+
+ @Override
+ public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
+ LOG.debug("ESDriver#createBulkProcessor @Override #afterBulk is not implemented yet!");
+ }
+
+ @Override
+ public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
+ LOG.error("Bulk request has failed!");
+ throw new RuntimeException("Caught exception in bulk: " + request.getDescription() + ", failure: " + failure, failure);
+ }
+ }).setBulkActions(1000).setBulkSize(new ByteSizeValue(2500500, ByteSizeUnit.GB)).setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 10)).setConcurrentRequests(1)
+ .build());
+ }
+
+ public void destroyBulkProcessor() {
+ try {
+ getBulkProcessor().awaitClose(20, TimeUnit.MINUTES);
+ setBulkProcessor(null);
+ refreshIndex();
+ } catch (InterruptedException e) {
+ LOG.error("Error destroying the Bulk Processor.", e);
+ }
+ }
+
+ public void putMapping(String indexName, String settingsJson, String mappingJson) throws IOException {
+
+ boolean exists = getClient().admin().indices().prepareExists(indexName).execute().actionGet().isExists();
+ if (exists) {
+ return;
+ }
+
+ getClient().admin().indices().prepareCreate(indexName).setSettings(Settings.builder().loadFromSource(settingsJson)).execute().actionGet();
+ getClient().admin().indices().preparePutMapping(indexName).setType("_default_").setSource(mappingJson).execute().actionGet();
+ }
+
+ public String customAnalyzing(String indexName, String str) throws InterruptedException, ExecutionException {
+ return this.customAnalyzing(indexName, "cody", str);
+ }
+
+ public String customAnalyzing(String indexName, String analyzer, String str) throws InterruptedException, ExecutionException {
+ String[] strList = str.toLowerCase().split(",");
+ for (int i = 0; i < strList.length; i++) {
+ String tmp = "";
+ AnalyzeResponse r = client.admin().indices().prepareAnalyze(strList[i]).setIndex(indexName).setAnalyzer(analyzer).execute().get();
+ for (AnalyzeToken token : r.getTokens()) {
+ tmp += token.getTerm() + " ";
+ }
+ strList[i] = tmp.trim();
+ }
+ return String.join(",", strList);
+ }
+
+ public List<String> customAnalyzing(String indexName, List<String> list) throws InterruptedException, ExecutionException {
+ if (list == null) {
+ return list;
+ }
+ int size = list.size();
+ List<String> customlist = new ArrayList<>();
+ for (int i = 0; i < size; i++) {
+ customlist.add(this.customAnalyzing(indexName, list.get(i)));
+ }
+
+ return customlist;
+ }
+
+ public void deleteAllByQuery(String index, String type, QueryBuilder query) {
+ createBulkProcessor();
+ SearchResponse scrollResp = getClient().prepareSearch(index).setSearchType(SearchType.QUERY_AND_FETCH).setTypes(type).setScroll(new TimeValue(60000)).setQuery(query).setSize(10000).execute()
+ .actionGet();
+
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ DeleteRequest deleteRequest = new DeleteRequest(index, type, hit.getId());
+ getBulkProcessor().add(deleteRequest);
+ }
+
+ scrollResp = getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+
+ }
+ destroyBulkProcessor();
+ }
+
+ public void deleteType(String index, String type) {
+ this.deleteAllByQuery(index, type, QueryBuilders.matchAllQuery());
+ }
+
+ public List<String> getTypeListWithPrefix(Object object, Object object2) {
+ ArrayList<String> typeList = new ArrayList<>();
+ GetMappingsResponse res;
+ try {
+ res = getClient().admin().indices().getMappings(new GetMappingsRequest().indices(object.toString())).get();
+ ImmutableOpenMap<String, MappingMetaData> mapping = res.mappings().get(object.toString());
+ for (ObjectObjectCursor<String, MappingMetaData> c : mapping) {
+ if (c.key.startsWith(object2.toString())) {
+ typeList.add(c.key);
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Error whilst obtaining type list from Elasticsearch mappings.", e);
+ }
+ return typeList;
+ }
+
+ public List<String> getIndexListWithPrefix(Object object) {
+
+ LOG.info("Retrieving index list with prefix: {}", object.toString());
+ String[] indices = client.admin().indices().getIndex(new GetIndexRequest()).actionGet().getIndices();
+
+ ArrayList<String> indexList = new ArrayList<>();
+ int length = indices.length;
+ for (int i = 0; i < length; i++) {
+ String indexName = indices[i];
+ if (indexName.startsWith(object.toString())) {
+ indexList.add(indexName);
+ }
+ }
+
+ return indexList;
+ }
+
+ public String searchByQuery(String index, String type, String query) throws IOException, InterruptedException, ExecutionException {
+ return searchByQuery(index, type, query, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ public String searchByQuery(String index, String type, String query, Boolean bDetail) throws IOException, InterruptedException, ExecutionException {
+ boolean exists = getClient().admin().indices().prepareExists(index).execute().actionGet().isExists();
+ if (!exists) {
+ return null;
+ }
+
+ QueryBuilder qb = QueryBuilders.queryStringQuery(query);
+ SearchResponse response = getClient().prepareSearch(index).setTypes(type).setQuery(qb).setSize(500).execute().actionGet();
+
+ // Map of K,V pairs where key is the field name from search result and value is the that should be returned for that field. Not always the same.
+ Map<String, String> fieldsToReturn = new HashMap<>();
+
+ fieldsToReturn.put("Dataset-ShortName", "Short Name");
+ fieldsToReturn.put("Dataset-LongName", "Long Name");
+ fieldsToReturn.put("DatasetParameter-Topic", "Topic");
+ fieldsToReturn.put("Dataset-Description", "Dataset-Description");
+ fieldsToReturn.put("DatasetCitation-ReleaseDateLong", "Release Date");
+
+ if (bDetail) {
+ fieldsToReturn.put("DatasetPolicy-DataFormat", "DataFormat");
+ fieldsToReturn.put("Dataset-Doi", "Dataset-Doi");
+ fieldsToReturn.put("Dataset-ProcessingLevel", "Processing Level");
+ fieldsToReturn.put("DatasetCitation-Version", "Version");
+ fieldsToReturn.put("DatasetSource-Sensor-ShortName", "DatasetSource-Sensor-ShortName");
+ fieldsToReturn.put("DatasetProject-Project-ShortName", "DatasetProject-Project-ShortName");
+ fieldsToReturn.put("DatasetParameter-Category", "DatasetParameter-Category");
+ fieldsToReturn.put("DatasetLocationPolicy-BasePath", "DatasetLocationPolicy-BasePath");
+ fieldsToReturn.put("DatasetParameter-Variable-Full", "DatasetParameter-Variable-Full");
+ fieldsToReturn.put("DatasetParameter-Term-Full", "DatasetParameter-Term-Full");
+ fieldsToReturn.put("DatasetParameter-VariableDetail", "DatasetParameter-VariableDetail");
+
+ fieldsToReturn.put("DatasetRegion-Region", "Region");
+ fieldsToReturn.put("DatasetCoverage-NorthLat", "NorthLat");
+ fieldsToReturn.put("DatasetCoverage-SouthLat", "SouthLat");
+ fieldsToReturn.put("DatasetCoverage-WestLon", "WestLon");
+ fieldsToReturn.put("DatasetCoverage-EastLon", "EastLon");
+ fieldsToReturn.put("DatasetCoverage-StartTimeLong-Long", "DatasetCoverage-StartTimeLong-Long");
+ fieldsToReturn.put("Dataset-DatasetCoverage-StopTimeLong", "Dataset-DatasetCoverage-StopTimeLong");
+
+ fieldsToReturn.put("Dataset-TemporalResolution", "Dataset-TemporalResolution");
+ fieldsToReturn.put("Dataset-TemporalRepeat", "Dataset-TemporalRepeat");
+ fieldsToReturn.put("Dataset-LatitudeResolution", "Dataset-LatitudeResolution");
+ fieldsToReturn.put("Dataset-LongitudeResolution", "Dataset-LongitudeResolution");
+ fieldsToReturn.put("Dataset-AcrossTrackResolution", "Dataset-AcrossTrackResolution");
+ fieldsToReturn.put("Dataset-AlongTrackResolution", "Dataset-AlongTrackResolution");
+ }
+
+ List<Map<String, Object>> searchResults = new ArrayList<>();
+
+ for (SearchHit hit : response.getHits().getHits()) {
+ Map<String, Object> source = hit.getSource();
+
+ Map<String, Object> searchResult = source.entrySet().stream().filter(entry -> fieldsToReturn.keySet().contains(entry.getKey()))
+ .collect(Collectors.toMap(entry -> fieldsToReturn.get(entry.getKey()), Entry::getValue));
+
+ // searchResult is now a map where the key = value from fieldsToReturn and the value = value from search result
+
+ // Some results require special handling/formatting:
+ // Release Date formatting
+ LocalDate releaseDate = Instant.ofEpochMilli(Long.parseLong(((ArrayList<String>) searchResult.get("Release Date")).get(0))).atZone(ZoneId.of("Z")).toLocalDate();
+ searchResult.put("Release Date", releaseDate.format(DateTimeFormatter.ISO_DATE));
+
+ if (bDetail) {
+
+ // DataFormat value, translate RAW to BINARY
+ if ("RAW".equals(searchResult.get("DataFormat"))) {
+ searchResult.put("DataFormat", "BINARY");
+ }
+
+ // DatasetLocationPolicy-BasePath Should only contain ftp, http, or https URLs
+ List<String> urls = ((List<String>) searchResult.get("DatasetLocationPolicy-BasePath")).stream().filter(url -> url.startsWith("ftp") || url.startsWith("http")).collect(Collectors.toList());
+ searchResult.put("DatasetLocationPolicy-BasePath", urls);
+
+ // Time Span Formatting
+ LocalDate startDate = Instant.ofEpochMilli((Long) searchResult.get("DatasetCoverage-StartTimeLong-Long")).atZone(ZoneId.of("Z")).toLocalDate();
+ LocalDate endDate = "".equals(searchResult.get("Dataset-DatasetCoverage-StopTimeLong")) ?
+ null :
+ Instant.ofEpochMilli(Long.parseLong(searchResult.get("Dataset-DatasetCoverage-StopTimeLong").toString())).atZone(ZoneId.of("Z")).toLocalDate();
+ searchResult.put("Time Span", startDate.format(DateTimeFormatter.ISO_DATE) + " to " + (endDate == null ? "Present" : endDate.format(DateTimeFormatter.ISO_DATE)));
+
+ // Temporal resolution can come from one of two fields
+ searchResult.put("TemporalResolution", "".equals(searchResult.get("Dataset-TemporalResolution")) ? searchResult.get("Dataset-TemporalRepeat") : searchResult.get("Dataset-TemporalResolution"));
+
+ // Special formatting for spatial resolution
+ String latResolution = (String) searchResult.get("Dataset-LatitudeResolution");
+ String lonResolution = (String) searchResult.get("Dataset-LongitudeResolution");
+ if (!latResolution.isEmpty() && !lonResolution.isEmpty()) {
+ searchResult.put("SpatialResolution", latResolution + " degrees (latitude) x " + lonResolution + " degrees (longitude)");
+ } else {
+ String acrossResolution = (String) searchResult.get("Dataset-AcrossTrackResolution");
+ String alonResolution = (String) searchResult.get("Dataset-AlongTrackResolution");
+ double dAcrossResolution = Double.parseDouble(acrossResolution) / 1000;
+ double dAlonResolution = Double.parseDouble(alonResolution) / 1000;
+ searchResult.put("SpatialResolution", dAlonResolution + " km (Along) x " + dAcrossResolution + " km (Across)");
+ }
+
+ // Measurement is a list of hierarchies that goes Topic -> Term -> Variable -> Variable Detail. Need to construct these hierarchies.
+ List<List<String>> measurements = buildMeasurementHierarchies((List<String>) searchResult.get("Topic"), (List<String>) searchResult.get("DatasetParameter-Term-Full"),
+ (List<String>) searchResult.get("DatasetParameter-Variable-Full"), (List<String>) searchResult.get("DatasetParameter-VariableDetail"));
+
+ searchResult.put("Measurements", measurements);
+
+ }
+
+ searchResults.add(searchResult);
+ }
+
+ Map<String, List<?>> pdResults = new HashMap<>();
+ pdResults.put("PDResults", searchResults);
+
+ return new GsonBuilder().create().toJson(pdResults);
+ }
+
+ /**
+ * Builds a List of Measurement Hierarchies given the individual source lists.
+ * The hierarchy is built from the element in the same position from each input list in the order: Topic -> Term -> Variable -> VariableDetail
+ * "None" and blank strings are ignored. If, at any level, an element does not exist for that position or it is "None" or blank, that hierarchy is considered complete.
+ *
+ * For example, if the input is:
+ * <pre>
+ * topics = ["Oceans", "Oceans"]
+ * terms = ["Sea Surface Topography", "Ocean Waves"]
+ * variables = ["Sea Surface Height", "Significant Wave Height"]
+ * variableDetails = ["None", "None"]
+ * </pre>
+ *
+ * The output would be:
+ * <pre>
+ * [
+ * ["Oceans", "Sea Surface Topography", "Sea Surface Height"],
+ * ["Oceans", "Ocean Waves", "Significant Wave Height"]
+ * ]
+ * </pre>
+ * Oceans > Sea Surface Topography > Sea Surface Height
+ * Oceans > Ocean Waves > Significant Wave Height
+ *
+ * @param topics List of topics, the first element of a measurement
+ * @param terms List of terms, the second element of a measurement
+ * @param variables List of variables, the third element of a measurement
+ * @param variableDetails List of variable details, the fourth element of a measurement
+ *
+ * @return A List where each element is a single hierarchy (as a List) built from the provided input lists.
+ */
+ private List<List<String>> buildMeasurementHierarchies(List<String> topics, List<String> terms, List<String> variables, List<String> variableDetails) {
+
+ List<List<String>> measurements = new ArrayList<>();
+
+ for (int x = 0; x < topics.size(); x++) {
+ measurements.add(new ArrayList<>());
+ measurements.get(x).add(topics.get(x));
+ // Only add the next 'level' if we can
+ if (x < terms.size() && !"None".equalsIgnoreCase(terms.get(x)) && StringUtils.isNotBlank(terms.get(x))) {
+ measurements.get(x).add(terms.get(x));
+ if (x < variables.size() && !"None".equalsIgnoreCase(variables.get(x)) && StringUtils.isNotBlank(variables.get(x))) {
+ measurements.get(x).add(variables.get(x));
+ if (x < variableDetails.size() && !"None".equalsIgnoreCase(variableDetails.get(x)) && StringUtils.isNotBlank(variableDetails.get(x))) {
+ measurements.get(x).add(variableDetails.get(x));
+ }
+ }
+ }
+ }
+
+ return measurements;
+
+ }
+
+ public List<String> autoComplete(String index, String term) {
+ boolean exists = this.getClient().admin().indices().prepareExists(index).execute().actionGet().isExists();
+ if (!exists) {
+ return new ArrayList<>();
+ }
+
+ Set<String> suggestHS = new HashSet<String>();
+ List<String> suggestList = new ArrayList<>();
+
+ // please make sure that the completion field is configured in the ES mapping
+ CompletionSuggestionBuilder suggestionsBuilder = SuggestBuilders.completionSuggestion("Dataset-Metadata").prefix(term, Fuzziness.fromEdits(2)).size(100);
+ SearchRequestBuilder suggestRequestBuilder = getClient().prepareSearch(index).suggest(new SuggestBuilder().addSuggestion("completeMe", suggestionsBuilder));
+ SearchResponse sr = suggestRequestBuilder.setFetchSource(false).execute().actionGet();
+
+ Iterator<? extends Suggest.Suggestion.Entry.Option> iterator = sr.getSuggest().getSuggestion("completeMe").iterator().next().getOptions().iterator();
+
+ while (iterator.hasNext()) {
+ Suggest.Suggestion.Entry.Option next = iterator.next();
+ String suggest = next.getText().string().toLowerCase();
+ suggestList.add(suggest);
+ }
+
+ suggestHS.addAll(suggestList);
+ suggestList.clear();
+ suggestList.addAll(suggestHS);
+ return suggestList;
+ }
+
+ public void close() {
+ client.close();
+ }
+
+ public void refreshIndex() {
+ client.admin().indices().prepareRefresh().execute().actionGet();
+ }
+
+ /**
+ * Generates a TransportClient or NodeClient
+ *
+ * @param props a populated {@link java.util.Properties} object
+ * @return a constructed {@link org.elasticsearch.client.Client}
+ * @throws IOException if there is an error building the
+ * {@link org.elasticsearch.client.Client}
+ */
+ protected Client makeClient(Properties props) throws IOException {
+ String clusterName = props.getProperty(MudrodConstants.ES_CLUSTER);
+ String hostsString = props.getProperty(MudrodConstants.ES_UNICAST_HOSTS);
+ String[] hosts = hostsString.split(",");
+ String portStr = props.getProperty(MudrodConstants.ES_TRANSPORT_TCP_PORT);
+ int port = Integer.parseInt(portStr);
+
+ Settings.Builder settingsBuilder = Settings.builder();
+
+ // Set the cluster name and build the settings
+ if (!clusterName.isEmpty())
+ settingsBuilder.put("cluster.name", clusterName);
+
+ settingsBuilder.put("http.type", "netty3");
+ settingsBuilder.put("transport.type", "netty3");
+
+ Settings settings = settingsBuilder.build();
+
+ Client client = null;
+
+ // Prefer TransportClient
+ if (hosts != null && port > 1) {
+ TransportClient transportClient = new ESTransportClient(settings);
+ for (String host : hosts)
+ transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port));
+ client = transportClient;
+ } else if (clusterName != null) {
+ node = new Node(settings);
+ client = node.client();
+ }
+
+ return client;
+ }
+
+ /**
+ * Main method used to invoke the ESDriver implementation.
+ *
+ * @param args no arguments are required to invoke the Driver.
+ */
+ public static void main(String[] args) {
+ MudrodEngine mudrodEngine = new MudrodEngine();
+ ESDriver es = new ESDriver(mudrodEngine.loadConfig());
+ es.getTypeListWithPrefix("podaacsession", "sessionstats");
+ }
+
+ /**
+ * @return the client
+ */
+ public Client getClient() {
+ return client;
+ }
+
+ /**
+ * @param client the client to set
+ */
+ public void setClient(Client client) {
+ this.client = client;
+ }
+
+ /**
+ * @return the bulkProcessor
+ */
+ public BulkProcessor getBulkProcessor() {
+ return bulkProcessor;
+ }
+
+ /**
+ * @param bulkProcessor the bulkProcessor to set
+ */
+ public void setBulkProcessor(BulkProcessor bulkProcessor) {
+ this.bulkProcessor = bulkProcessor;
+ }
+
+ public UpdateRequest generateUpdateRequest(String index, String type, String id, String field1, Object value1) {
+
+ UpdateRequest ur = null;
+ try {
+ ur = new UpdateRequest(index, type, id).doc(jsonBuilder().startObject().field(field1, value1).endObject());
+ } catch (IOException e) {
+ LOG.error("Error whilst attempting to generate a new Update Request.", e);
+ }
+
+ return ur;
+ }
+
+ public UpdateRequest generateUpdateRequest(String index, String type, String id, Map<String, Object> filedValueMap) {
+
+ UpdateRequest ur = null;
+ try {
+ XContentBuilder builder = jsonBuilder().startObject();
+ for (Entry<String, Object> entry : filedValueMap.entrySet()) {
+ String key = entry.getKey();
+ builder.field(key, filedValueMap.get(key));
+ }
+ builder.endObject();
+ ur = new UpdateRequest(index, type, id).doc(builder);
+ } catch (IOException e) {
+ LOG.error("Error whilst attempting to generate a new Update Request.", e);
+ }
+
+ return ur;
+ }
+
+ public int getDocCount(String index, String... type) {
+ MatchAllQueryBuilder search = QueryBuilders.matchAllQuery();
+ String[] indexArr = new String[] { index };
+ return this.getDocCount(indexArr, type, search);
+ }
+
+ public int getDocCount(String[] index, String[] type) {
+ MatchAllQueryBuilder search = QueryBuilders.matchAllQuery();
+ return this.getDocCount(index, type, search);
+ }
+
+ public int getDocCount(String[] index, String[] type, QueryBuilder filterSearch) {
+ SearchRequestBuilder countSrBuilder = getClient().prepareSearch(index).setTypes(type).setQuery(filterSearch).setSize(0);
+ SearchResponse countSr = countSrBuilder.execute().actionGet();
+ int docCount = (int) countSr.getHits().getTotalHits();
+ return docCount;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/driver/SparkDriver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/driver/SparkDriver.java b/core/src/main/java/gov/nasa/jpl/mudrod/driver/SparkDriver.java
new file mode 100644
index 0000000..e49c029
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/driver/SparkDriver.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.driver;
+
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import org.apache.spark.SparkConf;
+import org.apache.spark.api.java.JavaSparkContext;
+import org.apache.spark.serializer.KryoSerializer;
+import org.apache.spark.sql.SQLContext;
+
+import java.io.File;
+import java.io.Serializable;
+import java.net.URISyntaxException;
+import java.util.Properties;
+//import org.apache.spark.sql.SparkSession;
+
+public class SparkDriver implements Serializable {
+
+ //TODO the commented out code below is the API uprgade
+ //for Spark 2.0.0. It requires a large upgrade and simplification
+ //across the mudrod codebase so should be done in an individual ticket.
+ // /**
+ // *
+ // */
+ // private static final long serialVersionUID = 1L;
+ // private SparkSession builder;
+ //
+ // public SparkDriver() {
+ // builder = SparkSession.builder()
+ // .master("local[2]")
+ // .config("spark.hadoop.validateOutputSpecs", "false")
+ // .config("spark.files.overwrite", "true")
+ // .getOrCreate();
+ // }
+ //
+ // public SparkSession getBuilder() {
+ // return builder;
+ // }
+ //
+ // public void setBuilder(SparkSession builder) {
+ // this.builder = builder;
+ // }
+ //
+ // public void close() {
+ // builder.stop();
+ // }
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ public transient JavaSparkContext sc;
+ public transient SQLContext sqlContext;
+
+ public SparkDriver() {
+ // empty default constructor
+ }
+
+ public SparkDriver(Properties props) {
+ SparkConf conf = new SparkConf().setAppName(props.getProperty(MudrodConstants.SPARK_APP_NAME, "MudrodSparkApp")).setIfMissing("spark.master", props.getProperty(MudrodConstants.SPARK_MASTER))
+ .set("spark.hadoop.validateOutputSpecs", "false").set("spark.files.overwrite", "true");
+
+ String esHost = props.getProperty(MudrodConstants.ES_UNICAST_HOSTS);
+ String esPort = props.getProperty(MudrodConstants.ES_HTTP_PORT);
+
+ if (!"".equals(esHost)) {
+ conf.set("es.nodes", esHost);
+ }
+
+ if (!"".equals(esPort)) {
+ conf.set("es.port", esPort);
+ }
+
+ conf.set("spark.serializer", KryoSerializer.class.getName());
+ conf.set("es.batch.size.entries", "1500");
+
+ sc = new JavaSparkContext(conf);
+ sqlContext = new SQLContext(sc);
+ }
+
+ public void close() {
+ sc.sc().stop();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/driver/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/driver/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/driver/package-info.java
new file mode 100644
index 0000000..d9cde36
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/driver/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes commonly used Elasticsearch and Spark related
+ * functions
+ */
+package gov.nasa.jpl.mudrod.driver;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/integration/LinkageIntegration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/integration/LinkageIntegration.java b/core/src/main/java/gov/nasa/jpl/mudrod/integration/LinkageIntegration.java
new file mode 100644
index 0000000..14b667d
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/integration/LinkageIntegration.java
@@ -0,0 +1,324 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.integration;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.sort.SortOrder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.DecimalFormat;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+
+/**
+ * Supports ability to integrate vocab similarity results from metadata, ontology, and web logs.
+ */
+public class LinkageIntegration extends DiscoveryStepAbstract {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LinkageIntegration.class);
+ private static final long serialVersionUID = 1L;
+ transient List<LinkedTerm> termList = new ArrayList<>();
+ DecimalFormat df = new DecimalFormat("#.00");
+ private static final String INDEX_NAME = "indexName";
+ private static final String WEIGHT = "weight";
+
+ public LinkageIntegration(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * The data structure to store semantic triple.
+ */
+ class LinkedTerm {
+ String term = null;
+ double weight = 0;
+ String model = null;
+
+ public LinkedTerm(String str, double w, String m) {
+ term = str;
+ weight = w;
+ model = m;
+ }
+ }
+
+ /**
+ * Method of executing integration step
+ */
+ @Override
+ public Object execute() {
+ getIngeratedList("ocean wind", 11);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ /**
+ * Method of getting integrated results
+ *
+ * @param input query string
+ * @return a hash map where the string is a related term, and double is the
+ * similarity to the input query
+ */
+ public Map<String, Double> appyMajorRule(String input) {
+ termList = new ArrayList<>();
+ Map<String, Double> termsMap = new HashMap<>();
+ Map<String, List<LinkedTerm>> map = new HashMap<>();
+ try {
+ map = aggregateRelatedTermsFromAllmodel(es.customAnalyzing(props.getProperty(INDEX_NAME), input));
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Error applying majority rule", e);
+ }
+
+ for (Entry<String, List<LinkedTerm>> entry : map.entrySet()) {
+ List<LinkedTerm> list = entry.getValue();
+ double sumModelWeight = 0;
+ double tmp = 0;
+ for (LinkedTerm element : list) {
+ sumModelWeight += getModelweight(element.model);
+
+ if (element.weight > tmp) {
+ tmp = element.weight;
+ }
+ }
+
+ double finalWeight = tmp + ((sumModelWeight - 2) * 0.05);
+ if (finalWeight < 0) {
+ finalWeight = 0;
+ }
+
+ if (finalWeight > 1) {
+ finalWeight = 1;
+ }
+ termsMap.put(entry.getKey(), Double.parseDouble(df.format(finalWeight)));
+ }
+
+ return sortMapByValue(termsMap);
+ }
+
+ /**
+ * Method of getting integrated results
+ *
+ * @param input query string
+ * @param num the number of most related terms
+ * @return a string of related terms along with corresponding similarities
+ */
+ public String getIngeratedList(String input, int num) {
+ String output = "";
+ Map<String, Double> sortedMap = appyMajorRule(input);
+ int count = 0;
+ for (Entry<String, Double> entry : sortedMap.entrySet()) {
+ if (count < num) {
+ output += entry.getKey() + " = " + entry.getValue() + ", ";
+ }
+ count++;
+ }
+ LOG.info("\n************************Integrated results***************************");
+ LOG.info(output);
+ return output;
+ }
+
+ /**
+ * Method of getting integrated results
+ *
+ * @param input query string
+ * @return a JSON object of related terms along with corresponding similarities
+ */
+ public JsonObject getIngeratedListInJson(String input) {
+ Map<String, Double> sortedMap = appyMajorRule(input);
+ int count = 0;
+ Map<String, Double> trimmedMap = new LinkedHashMap<>();
+ for (Entry<String, Double> entry : sortedMap.entrySet()) {
+ if (!entry.getKey().contains("china")) {
+ if (count < 10) {
+ trimmedMap.put(entry.getKey(), entry.getValue());
+ }
+ count++;
+ }
+ }
+
+ return mapToJson(trimmedMap);
+ }
+
+ /**
+ * Method of aggregating terms from web logs, metadata, and ontology
+ *
+ * @param input query string
+ * @return a hash map where the string is a related term, and the list is
+ * the similarities from different sources
+ */
+ public Map<String, List<LinkedTerm>> aggregateRelatedTermsFromAllmodel(String input) {
+ aggregateRelatedTerms(input, props.getProperty("userHistoryLinkageType"));
+ aggregateRelatedTerms(input, props.getProperty("clickStreamLinkageType"));
+ aggregateRelatedTerms(input, props.getProperty("metadataLinkageType"));
+ aggregateRelatedTermsSWEET(input, props.getProperty("ontologyLinkageType"));
+
+ return termList.stream().collect(Collectors.groupingBy(w -> w.term));
+ }
+
+ public int getModelweight(String model) {
+ if (model.equals(props.getProperty("userHistoryLinkageType"))) {
+ return Integer.parseInt(props.getProperty("userHistory_w"));
+ }
+
+ if (model.equals(props.getProperty("clickStreamLinkageType"))) {
+ return Integer.parseInt(props.getProperty("clickStream_w"));
+ }
+
+ if (model.equals(props.getProperty("metadataLinkageType"))) {
+ return Integer.parseInt(props.getProperty("metadata_w"));
+ }
+
+ if (model.equals(props.getProperty("ontologyLinkageType"))) {
+ return Integer.parseInt(props.getProperty("ontology_w"));
+ }
+
+ return 999999;
+ }
+
+ /**
+ * Method of extracting the related term from a comma string
+ *
+ * @param str input string
+ * @param input query string
+ * @return related term contained in the input string
+ */
+ public String extractRelated(String str, String input) {
+ String[] strList = str.split(",");
+ if (input.equals(strList[0])) {
+ return strList[1];
+ } else {
+ return strList[0];
+ }
+ }
+
+ public void aggregateRelatedTerms(String input, String model) {
+ //get the first 10 related terms
+ SearchResponse usrhis = es.getClient().prepareSearch(props.getProperty(INDEX_NAME)).setTypes(model).setQuery(QueryBuilders.termQuery("keywords", input)).addSort(WEIGHT, SortOrder.DESC).setSize(11)
+ .execute().actionGet();
+
+ LOG.info("\n************************ {} results***************************", model);
+ for (SearchHit hit : usrhis.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String keywords = (String) result.get("keywords");
+ String relatedKey = extractRelated(keywords, input);
+
+ if (!relatedKey.equals(input)) {
+ LinkedTerm lTerm = new LinkedTerm(relatedKey, (double) result.get(WEIGHT), model);
+ LOG.info("( {} {} )", relatedKey, (double) result.get(WEIGHT));
+ termList.add(lTerm);
+ }
+
+ }
+ }
+
+ /**
+ * Method of querying related terms from ontology
+ *
+ * @param input input query
+ * @param model source name
+ */
+ public void aggregateRelatedTermsSWEET(String input, String model) {
+ SearchResponse usrhis = es.getClient().prepareSearch(props.getProperty(INDEX_NAME)).setTypes(model).setQuery(QueryBuilders.termQuery("concept_A", input)).addSort(WEIGHT, SortOrder.DESC)
+ .setSize(11).execute().actionGet();
+ LOG.info("\n************************ {} results***************************", model);
+ for (SearchHit hit : usrhis.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ String conceptB = (String) result.get("concept_B");
+ if (!conceptB.equals(input)) {
+ LinkedTerm lTerm = new LinkedTerm(conceptB, (double) result.get(WEIGHT), model);
+ LOG.info("( {} {} )", conceptB, (double) result.get(WEIGHT));
+ termList.add(lTerm);
+ }
+ }
+ }
+
+ /**
+ * Method of sorting a map by value
+ *
+ * @param passedMap input map
+ * @return sorted map
+ */
+ public Map<String, Double> sortMapByValue(Map<String, Double> passedMap) {
+ List<String> mapKeys = new ArrayList<>(passedMap.keySet());
+ List<Double> mapValues = new ArrayList<>(passedMap.values());
+ Collections.sort(mapValues, Collections.reverseOrder());
+ Collections.sort(mapKeys, Collections.reverseOrder());
+
+ LinkedHashMap<String, Double> sortedMap = new LinkedHashMap<>();
+
+ Iterator<Double> valueIt = mapValues.iterator();
+ while (valueIt.hasNext()) {
+ Object val = valueIt.next();
+ Iterator<String> keyIt = mapKeys.iterator();
+
+ while (keyIt.hasNext()) {
+ Object key = keyIt.next();
+ String comp1 = passedMap.get(key).toString();
+ String comp2 = val.toString();
+
+ if (comp1.equals(comp2)) {
+ passedMap.remove(key);
+ mapKeys.remove(key);
+ sortedMap.put((String) key, (Double) val);
+ break;
+ }
+
+ }
+
+ }
+ return sortedMap;
+ }
+
+ /**
+ * Method of converting hashmap to JSON
+ *
+ * @param word input query
+ * @param wordweights a map from related terms to weights
+ * @return converted JSON object
+ */
+ private JsonObject mapToJson(Map<String, Double> wordweights) {
+ Gson gson = new Gson();
+ JsonObject json = new JsonObject();
+ List<JsonObject> nodes = new ArrayList<>();
+
+ for (Entry<String, Double> entry : wordweights.entrySet()) {
+ JsonObject node = new JsonObject();
+ String key = entry.getKey();
+ Double value = entry.getValue();
+ node.addProperty("word", key);
+ node.addProperty("weight", value);
+ nodes.add(node);
+ }
+
+ JsonElement nodesElement = gson.toJsonTree(nodes);
+ json.add("ontology", nodesElement);
+
+ return json;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/integration/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/integration/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/integration/package-info.java
new file mode 100644
index 0000000..7f2ba66
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/integration/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes integration method of web log, ontology, and metdata
+ * mining results.
+ */
+package gov.nasa.jpl.mudrod.integration;
\ No newline at end of file
[07/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff b/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..9e61285
Binary files /dev/null and b/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff2
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff2 b/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 0000000..64539b5
Binary files /dev/null and b/web/META-INF/resources/fonts/glyphicons-halflings-regular.woff2 differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/images/OceanWave.jpg
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/images/OceanWave.jpg b/web/META-INF/resources/images/OceanWave.jpg
new file mode 100644
index 0000000..15ee197
Binary files /dev/null and b/web/META-INF/resources/images/OceanWave.jpg differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/images/searching.png
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/images/searching.png b/web/META-INF/resources/images/searching.png
new file mode 100644
index 0000000..8f2595b
Binary files /dev/null and b/web/META-INF/resources/images/searching.png differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/images/spinner.gif
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/images/spinner.gif b/web/META-INF/resources/images/spinner.gif
new file mode 100644
index 0000000..0cac9fd
Binary files /dev/null and b/web/META-INF/resources/images/spinner.gif differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/images/sprite.png
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/images/sprite.png b/web/META-INF/resources/images/sprite.png
new file mode 100644
index 0000000..d151860
Binary files /dev/null and b/web/META-INF/resources/images/sprite.png differ
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/index.html
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/index.html b/web/META-INF/resources/index.html
new file mode 100755
index 0000000..cbcc30a
--- /dev/null
+++ b/web/META-INF/resources/index.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+ -->
+<html lang="en" ng-app="mudrodApp">
+<head>
+ <title>JPL | MUDROD</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+ <link href="css/index.css" rel="stylesheet">
+ <link href="css/main-header.css" rel="stylesheet">
+ <link href="css/footer.css" rel="stylesheet">
+ <link href="images/logo.png" rel="icon">
+
+ <script src="js/libs/jquery-1.10.2.min.js"></script>
+ <script src="js/libs/angular.min.js"></script>
+ <script src="js/libs/angular-route.min.js"></script>
+ <script src="js/libs/angular-resource.min.js"></script>
+ <script src="js/libs/angular-cookies.min.js"></script>
+ <script src="js/libs/underscore-min.js"></script>
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
+
+ <script src="js/app.js"></script>
+ <script src="js/controllers.js"></script>
+ <script src="js/services.js"></script>
+
+
+</head>
+<body>
+
+<!-- main header -->
+<div ng-include src="'partials/main-header.html'"></div>
+
+<div ng-view></div>
+<footer class="mudrod-footer">
+ <p>
+ <a href="https://mudrod.github.io/"
+ target="_blank">Mining and Utilizing Dataset Relevancy from Oceanographic Datasets (MUDROD)</a>
+ is funded by NASA AIST Program(NNX15AM85G), developed by <a
+ href="http://stcenter.net/stc/">NSF Spatiotemporal
+ Innovation Center</a> in collaboration with <a
+ href="http://www.jpl.nasa.gov/">NASA JPL</a>
+ </p>
+</footer>
+<div ng-include src="'partials/footer.html'"></div>
+
+</body>
+</html>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/app.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/app.js b/web/META-INF/resources/js/app.js
new file mode 100755
index 0000000..5901b80
--- /dev/null
+++ b/web/META-INF/resources/js/app.js
@@ -0,0 +1,49 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+/* App Module */
+
+var mudrod = angular.module('mudrodApp', [
+ 'ngRoute',
+ 'mudrodControllers',
+ 'mudrodServices'
+]);
+
+mudrod.filter('urlencode', function() {
+ return function(input) {
+ if(input) {
+ return window.encodeURIComponent(input);
+ }
+ return "";
+ }
+});
+
+
+mudrod.config(['$routeProvider',
+ function ($routeProvider) {
+ $routeProvider.when('/', {
+ templateUrl: 'partials/search.html'
+ }).when('/metadataView/', {
+ templateUrl: 'partials/metadataResults.html',
+ controller: 'metadataViewCtrl',
+ reloadOnSearch: false
+ }).when('/datasetView/', {
+ templateUrl: 'partials/datasetResults.html',
+ controller: 'datasetViewCtrl'
+ }).otherwise({
+ redirectTo: '/',
+ templateUrl: 'partials/search.html'});
+ }]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/controllers.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/controllers.js b/web/META-INF/resources/js/controllers.js
new file mode 100755
index 0000000..8ff196f
--- /dev/null
+++ b/web/META-INF/resources/js/controllers.js
@@ -0,0 +1,210 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+/* Controllers */
+var mudrodControllers = angular.module('mudrodControllers', []);
+
+mudrodControllers.controller('searchCtrl', ['$scope', '$rootScope', '$location', '$route', 'Autocomplete', 'SearchOptions',
+ function ($scope, $rootScope, $location, $route, Autocomplete, SearchOptions) {
+
+ $scope.hidethis = true;
+ $scope.options = {
+ opt: 'Or'
+ };
+
+ $scope.complete = function (string) {
+ Autocomplete.get({term: string},
+ function success(response) {
+ $scope.filterSearch = response;
+ $scope.hidethis = false;
+ },
+ function error(errorResponse) {
+ console.log("Error:" + JSON.stringify(errorResponse));
+ }
+ );
+ };
+
+ $scope.fillTextbox = function (string) {
+ $scope.options.query = string;
+ $scope.hidethis = true;
+ document.getElementById("search-btn").focus();
+ };
+
+ $scope.search = function (options) {
+ $scope.hidethis = true;
+ $rootScope.searchOptions = angular.copy(options);
+ $location.path("/metadataView/").search({'query': options.query, 'opt': options.opt});
+ $route.reload();
+ };
+
+ $scope.$watch(function () {
+ return SearchOptions.getSearchOptions();
+ }, function (newValue, oldValue) {
+ if (newValue !== null) {
+ $scope.options.query = newValue.query;
+ $scope.options.opt = newValue.opt;
+ }
+ }, true);
+ }]);
+
+mudrodControllers.controller('vocabularyCtrl', ['$scope', '$rootScope', 'VocabList',
+ function vocabularyCtrl($scope, $rootScope, VocabList) {
+
+ var word = $rootScope.searchOptions.query;
+ VocabList.get({query: word},
+ function success(response) {
+ $scope.ontologyList = response.graph.ontology;
+
+ },
+ function error(errorResponse) {
+ console.log("Error:" + JSON.stringify(errorResponse));
+ }
+ );
+ }]);
+
+mudrodControllers.controller('metadataViewCtrl', ['$rootScope', '$scope', '$location', '$routeParams', 'MetaData', 'PagerService', 'SearchOptions',
+ function metadataViewCtrl($rootScope, $scope, $location, $routeParams, MetaData, PagerService, SearchOptions) {
+
+ $scope.searchComplete = false;
+
+ var vm = this;
+ vm.PDItems = [];
+ vm.pager = {};
+ vm.setPage = setPage;
+ vm.rankData = rankData;
+ vm.totalMatches = 0;
+ vm.rankopt = $routeParams.rankopt ? $routeParams.rankopt : 'Rank-SVM';
+
+ var word = String();
+ var opt = String();
+ var rankopt = vm.rankopt;
+
+ if (!$routeParams.query) {
+ if(!$rootScope.searchOptions){
+ $location.path('/').search({});
+ }
+ word = $rootScope.searchOptions.query;
+ opt = $rootScope.searchOptions.opt;
+ SearchOptions.setSearchOptions({'query': word, 'opt': opt});
+ } else {
+ word = $routeParams.query;
+ if($routeParams.opt){
+ opt = $routeParams.opt;
+ }else if ($rootScope.searchOptions && $rootScope.searchOptions.opt){
+ opt = $rootScope.searchOptions.opt;
+ upsertQueryParam('opt', opt);
+ }else{
+ opt = 'Or';
+ upsertQueryParam('opt', opt);
+ }
+
+ word = word.replace(/,/g , " ");
+ word = word.replace(/\//g , " ");
+
+ SearchOptions.setSearchOptions({'query': word, 'opt': opt});
+ }
+ $rootScope.searchOptions = SearchOptions.getSearchOptions();
+ searchMetadata();
+
+ function initController() {
+ vm.setPage(1);
+ }
+
+ function setPage(page) {
+ if (page < 1 || page > vm.pager.totalPages) {
+ return;
+ }
+
+ // get pager object from service
+ vm.pager = PagerService.GetPager(vm.PDItems.length, page);
+
+ // get current page of items
+ vm.items = vm.PDItems.slice(vm.pager.startIndex, vm.pager.endIndex + 1);
+ }
+
+ function rankData(opt) {
+ rankopt = opt;
+ upsertQueryParam('rankopt', opt);
+ searchMetadata();
+ }
+
+ function upsertQueryParam(paramName, paramValue){
+ var qParams = $location.search();
+ qParams[paramName] = paramValue;
+ $location.search(qParams);
+ }
+
+ function searchMetadata() {
+ MetaData.get({query: word, operator: opt, rankoption: rankopt},
+ function success(response) {
+ vm.PDItems = response.PDResults;
+ vm.totalMatches = vm.PDItems.length;
+ vm.query = word;
+ vm.opt = opt;
+ initController();
+ $scope.searchComplete = true;
+ },
+ function error(errorResponse) {
+ $scope.searchComplete = true;
+ vm.searchError = {"status": errorResponse.status, "message": errorResponse.data};
+ }
+ );
+ }
+ }]);
+
+mudrodControllers.controller('datasetViewCtrl', ['$rootScope', '$scope', '$routeParams', 'DatasetDetail', 'SearchOptions',
+ function datasetViewCtrl($rootScope, $scope, $routeParams, DatasetDetail, SearchOptions) {
+ var shortname = $routeParams.shortname;
+
+ var query = String();
+ var opt = String();
+ if ($rootScope.searchOptions) {
+ query = $rootScope.searchOptions.query;
+ opt = $rootScope.searchOptions.opt;
+ SearchOptions.setSearchOptions({'query': query, 'opt': opt});
+ } else if ($routeParams.query && $routeParams.opt) {
+ query = $routeParams.query;
+ opt = $routeParams.opt;
+ SearchOptions.setSearchOptions({'query': query, 'opt': opt});
+ $rootScope.searchOptions = SearchOptions.getSearchOptions();
+ }
+
+ DatasetDetail.get({shortname: shortname},
+ function success(response) {
+ $scope.dataset = response.PDResults[0];
+ },
+ function error(errorResponse) {
+ console.log("Error:" + JSON.stringify(errorResponse));
+ }
+ );
+ }]);
+
+mudrodControllers.controller('hRecommendationCtrl', ['$scope', '$routeParams', 'HRecommendation',
+ function hRecommendationCtrl($scope, $routeParams, HRecommendation) {
+ var shortname = $routeParams.shortname;
+ HRecommendation.get({shortname: shortname},
+ function success(response) {
+ $scope.recommendationList = response.HybridRecommendationData.linked;
+
+ },
+ function error(errorResponse) {
+ console.log("Error:" + JSON.stringify(errorResponse));
+ }
+ );
+ }]);
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/web/META-INF/resources/js/libs/angular-cookies.min.js
----------------------------------------------------------------------
diff --git a/web/META-INF/resources/js/libs/angular-cookies.min.js b/web/META-INF/resources/js/libs/angular-cookies.min.js
new file mode 100755
index 0000000..09020c7
--- /dev/null
+++ b/web/META-INF/resources/js/libs/angular-cookies.min.js
@@ -0,0 +1,8 @@
+/*
+ AngularJS v1.3.7
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(e,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&e.$apply())})();k=!0;e.$watch(function(){var a,d,e;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)d=c[a],f.isString(d)||(d=""+d,c[a]=d),d!==g[a]&&(b.cookies(a,d),e=!0);if(e)for(a in d=b.cookies(),c)c[a]!==d[a]&&(m(d[a])?delete c[a]:c[a]=d[a])});return c}]).factory("$cookieStore",
+["$cookies",function(e){return{get:function(b){return(b=e[b])?f.fromJson(b):b},put:function(b,c){e[b]=f.toJson(c)},remove:function(b){delete e[b]}}}])})(window,window.angular);
+//# sourceMappingURL=angular-cookies.min.js.map
[15/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ImportLogFile.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ImportLogFile.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ImportLogFile.java
new file mode 100644
index 0000000..c55082a
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/ImportLogFile.java
@@ -0,0 +1,343 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.weblog.structure.ApacheAccessLog;
+import gov.nasa.jpl.mudrod.weblog.structure.FtpLog;
+import org.apache.spark.api.java.JavaRDD;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.spark.rdd.api.java.JavaEsSpark;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * Supports ability to parse and process FTP and HTTP log files
+ */
+public class ImportLogFile extends LogAbstract {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ImportLogFile.class);
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ String logEntryPattern = "^([\\d.]+) (\\S+) (\\S+) \\[([\\w:/]+\\s[+\\-]\\d{4})\\] " + "\"(.+?)\" (\\d{3}) (\\d+|-) \"((?:[^\"]|\")+)\" \"([^\"]+)\"";
+
+ public static final int NUM_FIELDS = 9;
+ Pattern p = Pattern.compile(logEntryPattern);
+ transient Matcher matcher;
+
+ /**
+ * Constructor supporting a number of parameters documented below.
+ *
+ * @param props a {@link java.util.Map} containing K,V of type String, String
+ * respectively.
+ * @param es the {@link ESDriver} used to persist log
+ * files.
+ * @param spark the {@link SparkDriver} used to process
+ * input log files.
+ */
+ public ImportLogFile(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting Log Import {}", props.getProperty(MudrodConstants.TIME_SUFFIX));
+ startTime = System.currentTimeMillis();
+ readFile();
+ endTime = System.currentTimeMillis();
+ LOG.info("Log Import complete. Time elapsed {} seconds", (endTime - startTime) / 1000);
+ es.refreshIndex();
+ return null;
+ }
+
+ /**
+ * Utility function to aid String to Number formatting such that three letter
+ * months such as 'Jan' are converted to the Gregorian integer equivalent.
+ *
+ * @param time the input {@link java.lang.String} to convert to int.
+ * @return the converted Month as an int.
+ */
+ public String switchtoNum(String time) {
+ String newTime = time;
+ if (newTime.contains("Jan")) {
+ newTime = newTime.replace("Jan", "1");
+ } else if (newTime.contains("Feb")) {
+ newTime = newTime.replace("Feb", "2");
+ } else if (newTime.contains("Mar")) {
+ newTime = newTime.replace("Mar", "3");
+ } else if (newTime.contains("Apr")) {
+ newTime = newTime.replace("Apr", "4");
+ } else if (newTime.contains("May")) {
+ newTime = newTime.replace("May", "5");
+ } else if (newTime.contains("Jun")) {
+ newTime = newTime.replace("Jun", "6");
+ } else if (newTime.contains("Jul")) {
+ newTime = newTime.replace("Jul", "7");
+ } else if (newTime.contains("Aug")) {
+ newTime = newTime.replace("Aug", "8");
+ } else if (newTime.contains("Sep")) {
+ newTime = newTime.replace("Sep", "9");
+ } else if (newTime.contains("Oct")) {
+ newTime = newTime.replace("Oct", "10");
+ } else if (newTime.contains("Nov")) {
+ newTime = newTime.replace("Nov", "11");
+ } else if (newTime.contains("Dec")) {
+ newTime = newTime.replace("Dec", "12");
+ }
+ return newTime;
+ }
+
+ public void readFile() {
+
+ String httplogpath = null;
+ String ftplogpath = null;
+
+ File directory = new File(props.getProperty(MudrodConstants.DATA_DIR));
+ File[] fList = directory.listFiles();
+ for (File file : fList) {
+ if (file.isFile() && file.getName().contains(props.getProperty(MudrodConstants.TIME_SUFFIX)))
+ {
+ if (file.getName().contains(props.getProperty(MudrodConstants.HTTP_PREFIX)))
+ {
+ httplogpath = file.getAbsolutePath();
+ }
+
+ if (file.getName().contains(props.getProperty(MudrodConstants.FTP_PREFIX)))
+ {
+ ftplogpath = file.getAbsolutePath();
+ }
+ }
+ }
+
+ if(httplogpath == null || ftplogpath == null)
+ {
+ LOG.error("WWW file or FTP logs cannot be found, please check your data directory.");
+ return;
+ }
+
+ String processingType = props.getProperty(MudrodConstants.PROCESS_TYPE, "parallel");
+ if (processingType.equals("sequential")) {
+ readFileInSequential(httplogpath, ftplogpath);
+ } else if (processingType.equals("parallel")) {
+ readFileInParallel(httplogpath, ftplogpath);
+ }
+ }
+
+ /**
+ * Read the FTP or HTTP log path with the intention of processing lines from
+ * log files.
+ *
+ * @param httplogpath path to the parent directory containing http logs
+ * @param ftplogpath path to the parent directory containing ftp logs
+ */
+ public void readFileInSequential(String httplogpath, String ftplogpath) {
+ es.createBulkProcessor();
+ try {
+ readLogFile(httplogpath, "http", logIndex, httpType);
+ readLogFile(ftplogpath, "FTP", logIndex, ftpType);
+
+ } catch (IOException e) {
+ LOG.error("Error whilst reading log file.", e);
+ }
+ es.destroyBulkProcessor();
+ }
+
+ /**
+ * Read the FTP or HTTP log path with the intention of processing lines from
+ * log files.
+ *
+ * @param httplogpath path to the parent directory containing http logs
+ * @param ftplogpath path to the parent directory containing ftp logs
+ */
+ public void readFileInParallel(String httplogpath, String ftplogpath) {
+
+ importHttpfile(httplogpath);
+ importFtpfile(ftplogpath);
+ }
+
+ public void importHttpfile(String httplogpath) {
+ // import http logs
+ JavaRDD<String> accessLogs = spark.sc.textFile(httplogpath, this.partition).map(s -> ApacheAccessLog.parseFromLogLine(s)).filter(ApacheAccessLog::checknull);
+
+ JavaEsSpark.saveJsonToEs(accessLogs, logIndex + "/" + this.httpType);
+ }
+
+ public void importFtpfile(String ftplogpath) {
+ // import ftp logs
+ JavaRDD<String> ftpLogs = spark.sc.textFile(ftplogpath, this.partition).map(s -> FtpLog.parseFromLogLine(s)).filter(FtpLog::checknull);
+
+ JavaEsSpark.saveJsonToEs(ftpLogs, logIndex + "/" + this.ftpType);
+ }
+
+ /**
+ * Process a log path on local file system which contains the relevant
+ * parameters as below.
+ *
+ * @param fileName the {@link java.lang.String} path to the log directory on file
+ * system
+ * @param protocol whether to process 'http' or 'FTP'
+ * @param index the index name to write logs to
+ * @param type one of the available protocols from which Mudrod logs are obtained.
+ * @throws IOException if there is an error reading anything from the fileName provided.
+ */
+ public void readLogFile(String fileName, String protocol, String index, String type) throws IOException {
+ BufferedReader br = new BufferedReader(new FileReader(fileName));
+ int count = 0;
+ try {
+ String line = br.readLine();
+ while (line != null) {
+ if ("FTP".equals(protocol)) {
+ parseSingleLineFTP(line, index, type);
+ } else {
+ parseSingleLineHTTP(line, index, type);
+ }
+ line = br.readLine();
+ count++;
+ }
+ } catch (FileNotFoundException e) {
+ LOG.error("File not found.", e);
+ } catch (IOException e) {
+ LOG.error("Error reading input directory.", e);
+ } finally {
+ br.close();
+ LOG.info("Num of {} entries:\t{}", protocol, count);
+ }
+ }
+
+ /**
+ * Parse a single FTP log entry
+ *
+ * @param log a single log line
+ * @param index the index name we wish to persist the log line to
+ * @param type one of the available protocols from which Mudrod logs are obtained.
+ */
+ public void parseSingleLineFTP(String log, String index, String type) {
+ String ip = log.split(" +")[6];
+
+ String time = log.split(" +")[1] + ":" + log.split(" +")[2] + ":" + log.split(" +")[3] + ":" + log.split(" +")[4];
+
+ time = switchtoNum(time);
+ SimpleDateFormat formatter = new SimpleDateFormat("MM:dd:HH:mm:ss:yyyy");
+ Date date = null;
+ try {
+ date = formatter.parse(time);
+ } catch (ParseException e) {
+ LOG.error("Error whilst parsing the date.", e);
+ }
+ String bytes = log.split(" +")[7];
+
+ String request = log.split(" +")[8].toLowerCase();
+
+ if (!request.contains("/misc/") && !request.contains("readme")) {
+ IndexRequest ir;
+ try {
+ ir = new IndexRequest(index, type)
+ .source(jsonBuilder().startObject().field("LogType", "ftp").field("IP", ip).field("Time", date).field("Request", request).field("Bytes", Long.parseLong(bytes)).endObject());
+ es.getBulkProcessor().add(ir);
+ } catch (NumberFormatException e) {
+ LOG.error("Error whilst processing numbers", e);
+ } catch (IOException e) {
+ LOG.error("IOError whilst adding to the bulk processor.", e);
+ }
+ }
+
+ }
+
+ /**
+ * Parse a single HTTP log entry
+ *
+ * @param log a single log line
+ * @param index the index name we wish to persist the log line to
+ * @param type one of the available protocols from which Mudrod logs are obtained.
+ */
+ public void parseSingleLineHTTP(String log, String index, String type) {
+ matcher = p.matcher(log);
+ if (!matcher.matches() || NUM_FIELDS != matcher.groupCount()) {
+ return;
+ }
+ String time = matcher.group(4);
+ time = switchtoNum(time);
+ SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy:HH:mm:ss");
+ Date date = null;
+ try {
+ date = formatter.parse(time);
+ } catch (ParseException e) {
+ LOG.error("Error whilst attempting to parse date.", e);
+ }
+
+ String bytes = matcher.group(7);
+ if ("-".equals(bytes)) {
+ bytes = "0";
+ }
+
+ String request = matcher.group(5).toLowerCase();
+ String agent = matcher.group(9);
+ CrawlerDetection crawlerDe = new CrawlerDetection(this.props, this.es, this.spark);
+ if (!crawlerDe.checkKnownCrawler(agent)) {
+ boolean tag = false;
+ String[] mimeTypes = { ".js", ".css", ".jpg", ".png", ".ico", "image_captcha", "autocomplete", ".gif", "/alldata/", "/api/", "get / http/1.1", ".jpeg", "/ws/" };
+ for (int i = 0; i < mimeTypes.length; i++) {
+ if (request.contains(mimeTypes[i])) {
+ tag = true;
+ break;
+ }
+ }
+
+ if (!tag) {
+ IndexRequest ir = null;
+ executeBulkRequest(ir, index, type, matcher, date, bytes);
+ }
+ }
+ }
+
+ private void executeBulkRequest(IndexRequest ir, String index, String type, Matcher matcher, Date date, String bytes) {
+ IndexRequest newIr = ir;
+ try {
+ newIr = new IndexRequest(index, type).source(
+ jsonBuilder().startObject().field("LogType", "PO.DAAC").field("IP", matcher.group(1)).field("Time", date).field("Request", matcher.group(5)).field("Response", matcher.group(6))
+ .field("Bytes", Integer.parseInt(bytes)).field("Referer", matcher.group(8)).field("Browser", matcher.group(9)).endObject());
+
+ es.getBulkProcessor().add(newIr);
+ } catch (NumberFormatException e) {
+ LOG.error("Error whilst processing numbers", e);
+ } catch (IOException e) {
+ LOG.error("IOError whilst adding to the bulk processor.", e);
+ }
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/LogAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/LogAbstract.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/LogAbstract.java
new file mode 100644
index 0000000..5b8ed9b
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/LogAbstract.java
@@ -0,0 +1,228 @@
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.weblog.partition.KGreedyPartitionSolver;
+import gov.nasa.jpl.mudrod.weblog.partition.ThePartitionProblemSolver;
+import gov.nasa.jpl.mudrod.weblog.partition.logPartitioner;
+import org.apache.commons.io.IOUtils;
+import org.apache.spark.Partition;
+import org.apache.spark.api.java.JavaPairRDD;
+import org.apache.spark.api.java.JavaRDD;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.aggregations.AggregationBuilder;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
+import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
+import org.elasticsearch.search.aggregations.bucket.histogram.Histogram.Order;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.Tuple2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+public class LogAbstract extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(LogAbstract.class);
+
+ public String logIndex = null;
+ public String httpType = null;
+ public String ftpType = null;
+ public String cleanupType = null;
+ public String sessionStats = null;
+ public int partition = 96;
+
+ public LogAbstract(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ if (props != null) {
+ initLogIndex();
+ }
+ }
+
+ protected void initLogIndex() {
+ logIndex = props.getProperty(MudrodConstants.LOG_INDEX) + props.getProperty(MudrodConstants.TIME_SUFFIX);
+ httpType = props.getProperty(MudrodConstants.HTTP_TYPE_PREFIX);
+ ftpType = props.getProperty(MudrodConstants.FTP_TYPE_PREFIX);
+ cleanupType = props.getProperty(MudrodConstants.CLEANUP_TYPE_PREFIX);
+ sessionStats = props.getProperty(MudrodConstants.SESSION_STATS_PREFIX);
+
+ InputStream settingsStream = getClass().getClassLoader().getResourceAsStream(ES_SETTINGS);
+ InputStream mappingsStream = getClass().getClassLoader().getResourceAsStream(ES_MAPPINGS);
+ JSONObject settingsJSON = null;
+ JSONObject mappingJSON = null;
+
+ try {
+ settingsJSON = new JSONObject(IOUtils.toString(settingsStream));
+ } catch (JSONException | IOException e1) {
+ LOG.error("Error reading Elasticsearch settings!", e1);
+ }
+
+ try {
+ mappingJSON = new JSONObject(IOUtils.toString(mappingsStream));
+ } catch (JSONException | IOException e1) {
+ LOG.error("Error reading Elasticsearch mappings!", e1);
+ }
+
+ try {
+ if (settingsJSON != null && mappingJSON != null) {
+ this.es.putMapping(logIndex, settingsJSON.toString(), mappingJSON.toString());
+ }
+ } catch (IOException e) {
+ LOG.error("Error entering Elasticsearch Mappings!", e);
+ }
+ }
+
+ @Override
+ public Object execute() {
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+ public JavaRDD<String> getUserRDD(String... type) {
+ Map<String, Double> userDocs = getUserDocs(type);
+ return parallizeUsers(userDocs);
+ }
+
+ public List<String> getUsers(String type) {
+
+ Terms users = this.getUserTerms(type);
+ List<String> userList = new ArrayList<>();
+ for (Terms.Bucket entry : users.getBuckets()) {
+ String ip = (String) entry.getKey();
+ userList.add(ip);
+ }
+
+ return userList;
+ }
+
+ public Terms getUserTerms(String... type) {
+
+ int docCount = es.getDocCount(logIndex, type);
+
+ SearchResponse sr = es.getClient().prepareSearch(logIndex).setTypes(type).setQuery(QueryBuilders.matchAllQuery()).setSize(0)
+ .addAggregation(AggregationBuilders.terms("Users").field("IP").size(docCount)).execute().actionGet();
+ return sr.getAggregations().get("Users");
+ }
+
+ public Map<String, Double> getUserDocs(String... type) {
+
+ Terms users = this.getUserTerms(type);
+ Map<String, Double> userList = new HashMap<>();
+ for (Terms.Bucket entry : users.getBuckets()) {
+ String ip = (String) entry.getKey();
+ Long count = entry.getDocCount();
+ userList.put(ip, Double.valueOf(count));
+ }
+
+ return userList;
+ }
+
+ public Map<String, Long> getUserDailyDocs() {
+
+ int docCount = es.getDocCount(logIndex, httpType);
+
+ AggregationBuilder dailyAgg = AggregationBuilders.dateHistogram("by_day").field("Time").dateHistogramInterval(DateHistogramInterval.DAY).order(Order.COUNT_DESC);
+
+ SearchResponse sr = es.getClient().prepareSearch(logIndex).setTypes(httpType).setQuery(QueryBuilders.matchAllQuery()).setSize(0)
+ .addAggregation(AggregationBuilders.terms("Users").field("IP").size(docCount).subAggregation(dailyAgg)).execute().actionGet();
+ Terms users = sr.getAggregations().get("Users");
+ Map<String, Long> userList = new HashMap<>();
+ for (Terms.Bucket user : users.getBuckets()) {
+ String ip = (String) user.getKey();
+
+ System.out.println(ip);
+
+ Histogram agg = user.getAggregations().get("by_day");
+ List<? extends Histogram.Bucket> dateList = agg.getBuckets();
+ int size = dateList.size();
+ for (int i = 0; i < size; i++) {
+ Long count = dateList.get(i).getDocCount();
+ String date = dateList.get(i).getKey().toString();
+
+ System.out.println(date);
+ System.out.println(count);
+ }
+ }
+
+ return userList;
+ }
+
+ protected void checkUserPartition(JavaRDD<String> userRDD) {
+ System.out.println("hhhhh");
+ List<Partition> partitios = userRDD.partitions();
+ System.out.println(partitios.size());
+ int[] partitionIds = new int[partitios.size()];
+ for (int i = 0; i < partitios.size(); i++) {
+ int index = partitios.get(i).index();
+ partitionIds[i] = index;
+ }
+
+ List<String>[] userIPs = userRDD.collectPartitions(partitionIds);
+ for (int i = 0; i < userIPs.length; i++) {
+ List<String> iuser = userIPs[i];
+ System.out.println(i + " partition");
+ System.out.println(iuser.toString());
+ }
+ }
+
+ public JavaRDD<String> parallizeUsers(Map<String, Double> userDocs) {
+
+ // prepare list for parallize
+ List<Tuple2<String, Double>> list = new ArrayList<>();
+ for (String user : userDocs.keySet()) {
+ list.add(new Tuple2<String, Double>(user, userDocs.get(user)));
+ }
+
+ // group users
+ ThePartitionProblemSolver solution = new KGreedyPartitionSolver();
+ Map<String, Integer> userGroups = solution.solve(userDocs, this.partition);
+
+ JavaPairRDD<String, Double> pairRdd = spark.sc.parallelizePairs(list);
+ JavaPairRDD<String, Double> userPairRDD = pairRdd.partitionBy(new logPartitioner(userGroups, this.partition));
+
+ // repartitioned user RDD
+ return userPairRDD.keys();
+ }
+
+ public Terms getSessionTerms() {
+
+ int docCount = es.getDocCount(this.logIndex, this.cleanupType);
+
+ SearchResponse sr = es.getClient().prepareSearch(this.logIndex).setTypes(this.cleanupType).setQuery(QueryBuilders.matchAllQuery())
+ .addAggregation(AggregationBuilders.terms("Sessions").field("SessionID").size(docCount)).execute().actionGet();
+
+ Terms Sessions = sr.getAggregations().get("Sessions");
+ return Sessions;
+ }
+
+ public List<String> getSessions() {
+
+ Terms sessions = this.getSessionTerms();
+ List<String> sessionList = new ArrayList<>();
+ for (Terms.Bucket entry : sessions.getBuckets()) {
+ if (entry.getDocCount() >= 3 && !entry.getKey().equals("invalid")) {
+ String session = (String) entry.getKey();
+ sessionList.add(session);
+ }
+ }
+
+ return sessionList;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RankingTrainDataGenerator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RankingTrainDataGenerator.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RankingTrainDataGenerator.java
new file mode 100644
index 0000000..12d7386
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RankingTrainDataGenerator.java
@@ -0,0 +1,54 @@
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.weblog.structure.RankingTrainData;
+import gov.nasa.jpl.mudrod.weblog.structure.SessionExtractor;
+import org.apache.spark.api.java.JavaRDD;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+public class RankingTrainDataGenerator extends DiscoveryStepAbstract {
+
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(RankingTrainDataGenerator.class);
+
+ public RankingTrainDataGenerator(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public Object execute() {
+ // TODO Auto-generated method stub
+ LOG.info("Starting generate ranking train data.");
+ startTime = System.currentTimeMillis();
+
+ String rankingTrainFile = "E:\\Mudrod_input_data\\Testing_Data_4_1monthLog+Meta+Onto\\traing.txt";
+ try {
+ SessionExtractor extractor = new SessionExtractor();
+ JavaRDD<RankingTrainData> rankingTrainDataRDD = extractor.extractRankingTrainData(this.props, this.es, this.spark);
+
+ JavaRDD<String> rankingTrainData_JsonRDD = rankingTrainDataRDD.map(f -> f.toJson());
+
+ rankingTrainData_JsonRDD.coalesce(1, true).saveAsTextFile(rankingTrainFile);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ endTime = System.currentTimeMillis();
+ LOG.info("Ranking train data generation complete. Time elapsed {} seconds.", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RemoveRawLog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RemoveRawLog.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RemoveRawLog.java
new file mode 100644
index 0000000..01b57c0
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/RemoveRawLog.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+/**
+ * Supports ability to remove raw logs after processing is finished
+ */
+public class RemoveRawLog extends LogAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(RemoveRawLog.class);
+
+ public RemoveRawLog(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting raw log removal.");
+ startTime = System.currentTimeMillis();
+ es.deleteAllByQuery(logIndex, httpType, QueryBuilders.matchAllQuery());
+ es.deleteAllByQuery(logIndex, ftpType, QueryBuilders.matchAllQuery());
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("Raw log removal complete. Time elapsed {} seconds.", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionGenerator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionGenerator.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionGenerator.java
new file mode 100644
index 0000000..b95e30b
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionGenerator.java
@@ -0,0 +1,452 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.weblog.structure.Session;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.function.FlatMapFunction;
+import org.apache.spark.api.java.function.Function2;
+import org.apache.spark.api.java.function.VoidFunction;
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.elasticsearch.search.aggregations.metrics.stats.Stats;
+import org.elasticsearch.search.aggregations.metrics.stats.StatsAggregationBuilder;
+import org.elasticsearch.search.sort.SortOrder;
+import org.joda.time.DateTime;
+import org.joda.time.Seconds;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.*;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * Supports ability to generate user session by time threshold and referrer
+ */
+public class SessionGenerator extends LogAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(SessionGenerator.class);
+
+ public SessionGenerator(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting Session Generation.");
+ startTime = System.currentTimeMillis();
+ generateSession();
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("Session generating complete. Time elapsed {} seconds.", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ public void generateSession() {
+ try {
+ es.createBulkProcessor();
+ genSessionByReferer(Integer.parseInt(props.getProperty("timegap")));
+ es.destroyBulkProcessor();
+
+ es.createBulkProcessor();
+ combineShortSessions(Integer.parseInt(props.getProperty("timegap")));
+ es.destroyBulkProcessor();
+ } catch (ElasticsearchException e) {
+ LOG.error("Error whilst executing bulk processor.", e);
+ } catch (IOException e) {
+ LOG.error("Error whilst reading configuration.", e);
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void genSessionByReferer(int timeThres) throws InterruptedException, IOException {
+ String processingType = props.getProperty(MudrodConstants.PROCESS_TYPE);
+ if (processingType.equals("sequential")) {
+ genSessionByRefererInSequential(timeThres);
+ } else if (processingType.equals("parallel")) {
+ genSessionByRefererInParallel(timeThres);
+ }
+ }
+
+ public void combineShortSessions(int timeThres) throws InterruptedException, IOException {
+ String processingType = props.getProperty(MudrodConstants.PROCESS_TYPE);
+ if (processingType.equals("sequential")) {
+ combineShortSessionsInSequential(timeThres);
+ } else if (processingType.equals("parallel")) {
+ combineShortSessionsInParallel(timeThres);
+ }
+ }
+
+ /**
+ * Method to generate session by time threshold and referrer
+ *
+ * @param timeThres value of time threshold (s)
+ * @throws ElasticsearchException ElasticsearchException
+ * @throws IOException IOException
+ */
+ public void genSessionByRefererInSequential(int timeThres) throws ElasticsearchException, IOException {
+
+ Terms users = this.getUserTerms(this.cleanupType);
+
+ int sessionCount = 0;
+ for (Terms.Bucket entry : users.getBuckets()) {
+
+ String user = (String) entry.getKey();
+ Integer sessionNum = genSessionByReferer(es, user, timeThres);
+ sessionCount += sessionNum;
+ }
+
+ LOG.info("Initial session count: {}", Integer.toString(sessionCount));
+ }
+
+ public void combineShortSessionsInSequential(int timeThres) throws ElasticsearchException, IOException {
+
+ Terms users = this.getUserTerms(this.cleanupType);
+ for (Terms.Bucket entry : users.getBuckets()) {
+ String user = entry.getKey().toString();
+ combineShortSessions(es, user, timeThres);
+ }
+ }
+
+ /**
+ * Method to remove invalid logs through IP address
+ *
+ * @param es an instantiated es driver
+ * @param ip invalid IP address
+ * @throws ElasticsearchException ElasticsearchException
+ * @throws IOException IOException
+ */
+ public void deleteInvalid(ESDriver es, String ip) throws IOException {
+
+ BoolQueryBuilder filterAll = new BoolQueryBuilder();
+ filterAll.must(QueryBuilders.termQuery("IP", ip));
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(logIndex).setTypes(this.cleanupType).setScroll(new TimeValue(60000)).setQuery(filterAll).setSize(100).execute().actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ update(es, logIndex, cleanupType, hit.getId(), "SessionID", "invalid");
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Method to update a Elasticsearch record/document by id, field, and value
+ *
+ * @param es
+ * @param index index name is Elasticsearch
+ * @param type type name
+ * @param id ID of the document that needs to be updated
+ * @param field1 field of the document that needs to be updated
+ * @param value1 value of the document that needs to be changed to
+ * @throws ElasticsearchException
+ * @throws IOException
+ */
+ private void update(ESDriver es, String index, String type, String id, String field1, Object value1) throws IOException {
+ UpdateRequest ur = new UpdateRequest(index, type, id).doc(jsonBuilder().startObject().field(field1, value1).endObject());
+ es.getBulkProcessor().add(ur);
+ }
+
+ public void genSessionByRefererInParallel(int timeThres) throws InterruptedException, IOException {
+
+ JavaRDD<String> userRDD = getUserRDD(this.cleanupType);
+
+ int sessionCount = 0;
+ sessionCount = userRDD.mapPartitions(new FlatMapFunction<Iterator<String>, Integer>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Iterator<Integer> call(Iterator<String> arg0) throws Exception {
+ ESDriver tmpES = new ESDriver(props);
+ tmpES.createBulkProcessor();
+ List<Integer> sessionNums = new ArrayList<>();
+ while (arg0.hasNext()) {
+ String s = arg0.next();
+ Integer sessionNum = genSessionByReferer(tmpES, s, timeThres);
+ sessionNums.add(sessionNum);
+ }
+ tmpES.destroyBulkProcessor();
+ tmpES.close();
+ return sessionNums.iterator();
+ }
+ }).reduce(new Function2<Integer, Integer, Integer>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Integer call(Integer a, Integer b) {
+ return a + b;
+ }
+ });
+
+ LOG.info("Initial Session count: {}", Integer.toString(sessionCount));
+ }
+
+ public int genSessionByReferer(ESDriver es, String user, int timeThres) throws ElasticsearchException, IOException {
+
+ String startTime = null;
+ int sessionCountIn = 0;
+
+ BoolQueryBuilder filterSearch = new BoolQueryBuilder();
+ filterSearch.must(QueryBuilders.termQuery("IP", user));
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(logIndex).setTypes(this.cleanupType).setScroll(new TimeValue(60000)).setQuery(filterSearch).addSort("Time", SortOrder.ASC).setSize(100)
+ .execute().actionGet();
+
+ Map<String, Map<String, DateTime>> sessionReqs = new HashMap<>();
+ String request = "";
+ String referer = "";
+ String logType = "";
+ String id = "";
+ String ip = user;
+ String indexUrl = "http://podaac.jpl.nasa.gov/";
+ DateTime time = null;
+ DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+
+ while (scrollResp.getHits().getHits().length != 0) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+ request = (String) result.get("RequestUrl");
+ referer = (String) result.get("Referer");
+ logType = (String) result.get("LogType");
+ time = fmt.parseDateTime((String) result.get("Time"));
+ id = hit.getId();
+
+ if ("PO.DAAC".equals(logType)) {
+ if ("-".equals(referer) || referer.equals(indexUrl) || !referer.contains(indexUrl)) {
+ sessionCountIn++;
+ sessionReqs.put(ip + "@" + sessionCountIn, new HashMap<String, DateTime>());
+ sessionReqs.get(ip + "@" + sessionCountIn).put(request, time);
+
+ update(es, logIndex, this.cleanupType, id, "SessionID", ip + "@" + sessionCountIn);
+
+ } else {
+ int count = sessionCountIn;
+ int rollbackNum = 0;
+ while (true) {
+ Map<String, DateTime> requests = sessionReqs.get(ip + "@" + count);
+ if (requests == null) {
+ sessionReqs.put(ip + "@" + count, new HashMap<String, DateTime>());
+ sessionReqs.get(ip + "@" + count).put(request, time);
+ update(es, logIndex, this.cleanupType, id, "SessionID", ip + "@" + count);
+
+ break;
+ }
+ ArrayList<String> keys = new ArrayList<>(requests.keySet());
+ boolean bFindRefer = false;
+
+ for (int i = keys.size() - 1; i >= 0; i--) {
+ rollbackNum++;
+ if (keys.get(i).equalsIgnoreCase(referer)) {
+ bFindRefer = true;
+ // threshold,if time interval > 10*
+ // click num, start a new session
+ if (Math.abs(Seconds.secondsBetween(requests.get(keys.get(i)), time).getSeconds()) < timeThres * rollbackNum) {
+ sessionReqs.get(ip + "@" + count).put(request, time);
+ update(es, logIndex, this.cleanupType, id, "SessionID", ip + "@" + count);
+ } else {
+ sessionCountIn++;
+ sessionReqs.put(ip + "@" + sessionCountIn, new HashMap<String, DateTime>());
+ sessionReqs.get(ip + "@" + sessionCountIn).put(request, time);
+ update(es, logIndex, this.cleanupType, id, "SessionID", ip + "@" + sessionCountIn);
+ }
+
+ break;
+ }
+ }
+
+ if (bFindRefer) {
+ break;
+ }
+
+ count--;
+ if (count < 0) {
+ sessionCountIn++;
+
+ sessionReqs.put(ip + "@" + sessionCountIn, new HashMap<String, DateTime>());
+ sessionReqs.get(ip + "@" + sessionCountIn).put(request, time);
+ update(es, props.getProperty(MudrodConstants.ES_INDEX_NAME), this.cleanupType, id, "SessionID", ip + "@" + sessionCountIn);
+
+ break;
+ }
+ }
+ }
+ } else if ("ftp".equals(logType)) {
+
+ // may affect computation efficiency
+ Map<String, DateTime> requests = sessionReqs.get(ip + "@" + sessionCountIn);
+ if (requests == null) {
+ sessionReqs.put(ip + "@" + sessionCountIn, new HashMap<String, DateTime>());
+ } else {
+ ArrayList<String> keys = new ArrayList<>(requests.keySet());
+ int size = keys.size();
+ if (Math.abs(Seconds.secondsBetween(requests.get(keys.get(size - 1)), time).getSeconds()) > timeThres) {
+ sessionCountIn += 1;
+ sessionReqs.put(ip + "@" + sessionCountIn, new HashMap<String, DateTime>());
+ }
+ }
+ sessionReqs.get(ip + "@" + sessionCountIn).put(request, time);
+ update(es, logIndex, this.cleanupType, id, "SessionID", ip + "@" + sessionCountIn);
+ }
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ }
+
+ return sessionCountIn;
+ }
+
+ public void combineShortSessionsInParallel(int timeThres) throws InterruptedException, IOException {
+
+ JavaRDD<String> userRDD = getUserRDD(this.cleanupType);
+
+ userRDD.foreachPartition(new VoidFunction<Iterator<String>>() {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void call(Iterator<String> arg0) throws Exception {
+ ESDriver tmpES = new ESDriver(props);
+ tmpES.createBulkProcessor();
+ while (arg0.hasNext()) {
+ String s = arg0.next();
+ combineShortSessions(tmpES, s, timeThres);
+ }
+ tmpES.destroyBulkProcessor();
+ tmpES.close();
+ }
+ });
+ }
+
+ public void combineShortSessions(ESDriver es, String user, int timeThres) throws ElasticsearchException, IOException {
+
+ BoolQueryBuilder filterSearch = new BoolQueryBuilder();
+ filterSearch.must(QueryBuilders.termQuery("IP", user));
+
+ String[] indexArr = new String[] { logIndex };
+ String[] typeArr = new String[] { cleanupType };
+ int docCount = es.getDocCount(indexArr, typeArr, filterSearch);
+
+ if (docCount < 3) {
+ deleteInvalid(es, user);
+ return;
+ }
+
+ BoolQueryBuilder filterCheck = new BoolQueryBuilder();
+ filterCheck.must(QueryBuilders.termQuery("IP", user)).must(QueryBuilders.termQuery("Referer", "-"));
+ SearchResponse checkReferer = es.getClient().prepareSearch(logIndex).setTypes(this.cleanupType).setScroll(new TimeValue(60000)).setQuery(filterCheck).setSize(0).execute().actionGet();
+
+ long numInvalid = checkReferer.getHits().getTotalHits();
+ double invalidRate = numInvalid / docCount;
+
+ if (invalidRate >= 0.8) {
+ deleteInvalid(es, user);
+ return;
+ }
+
+ StatsAggregationBuilder statsAgg = AggregationBuilders.stats("Stats").field("Time");
+ SearchResponse srSession = es.getClient().prepareSearch(logIndex).setTypes(this.cleanupType).setScroll(new TimeValue(60000)).setQuery(filterSearch)
+ .addAggregation(AggregationBuilders.terms("Sessions").field("SessionID").size(docCount).subAggregation(statsAgg)).execute().actionGet();
+
+ Terms sessions = srSession.getAggregations().get("Sessions");
+
+ List<Session> sessionList = new ArrayList<>();
+ for (Terms.Bucket session : sessions.getBuckets()) {
+ Stats agg = session.getAggregations().get("Stats");
+ Session sess = new Session(props, es, agg.getMinAsString(), agg.getMaxAsString(), session.getKey().toString());
+ sessionList.add(sess);
+ }
+
+ Collections.sort(sessionList);
+ DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+ String last = null;
+ String lastnewID = null;
+ String lastoldID = null;
+ String current = null;
+ for (Session s : sessionList) {
+ current = s.getEndTime();
+ if (last != null) {
+ if (Seconds.secondsBetween(fmt.parseDateTime(last), fmt.parseDateTime(current)).getSeconds() < timeThres) {
+ if (lastnewID == null) {
+ s.setNewID(lastoldID);
+ } else {
+ s.setNewID(lastnewID);
+ }
+
+ QueryBuilder fs = QueryBuilders.boolQuery().filter(QueryBuilders.termQuery("SessionID", s.getID()));
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(logIndex).setTypes(this.cleanupType).setScroll(new TimeValue(60000)).setQuery(fs).setSize(100).execute().actionGet();
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ if (lastnewID == null) {
+ update(es, logIndex, this.cleanupType, hit.getId(), "SessionID", lastoldID);
+ } else {
+ update(es, logIndex, this.cleanupType, hit.getId(), "SessionID", lastnewID);
+ }
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+ }
+ ;
+ }
+ lastoldID = s.getID();
+ lastnewID = s.getNewID();
+ last = current;
+ }
+
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionStatistic.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionStatistic.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionStatistic.java
new file mode 100644
index 0000000..7e7640f
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/SessionStatistic.java
@@ -0,0 +1,312 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.weblog.structure.RequestUrl;
+import org.apache.spark.api.java.JavaRDD;
+import org.apache.spark.api.java.function.FlatMapFunction;
+import org.apache.spark.api.java.function.Function2;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.elasticsearch.search.aggregations.metrics.stats.Stats;
+import org.elasticsearch.search.aggregations.metrics.stats.StatsAggregationBuilder;
+import org.joda.time.DateTime;
+import org.joda.time.Seconds;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+/**
+ * Supports ability to post-process session, including summarizing statistics
+ * and filtering
+ */
+public class SessionStatistic extends LogAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(SessionStatistic.class);
+
+ public SessionStatistic(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ @Override
+ public Object execute() {
+ LOG.info("Starting Session Summarization.");
+ startTime = System.currentTimeMillis();
+ try {
+ processSession();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("Session Summarization complete. Time elapsed {} seconds.", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ public void processSession() throws InterruptedException, IOException, ExecutionException {
+ String processingType = props.getProperty(MudrodConstants.PROCESS_TYPE);
+ if (processingType.equals("sequential")) {
+ processSessionInSequential();
+ } else if (processingType.equals("parallel")) {
+ processSessionInParallel();
+ }
+ }
+
+ public void processSessionInSequential() throws IOException, InterruptedException, ExecutionException {
+ es.createBulkProcessor();
+ Terms Sessions = this.getSessionTerms();
+ int session_count = 0;
+ for (Terms.Bucket entry : Sessions.getBuckets()) {
+ if (entry.getDocCount() >= 3 && !entry.getKey().equals("invalid")) {
+ String sessionid = entry.getKey().toString();
+ int sessionNum = processSession(es, sessionid);
+ session_count += sessionNum;
+ }
+ }
+ LOG.info("Final Session count: {}", Integer.toString(session_count));
+ es.destroyBulkProcessor();
+ }
+
+ /**
+ * Extract the dataset ID from a long request
+ *
+ * @param request raw log request
+ * @return dataset ID
+ */
+ public String findDataset(String request) {
+ String pattern1 = "/dataset/";
+ String pattern2;
+ if (request.contains("?")) {
+ pattern2 = "?";
+ } else {
+ pattern2 = " ";
+ }
+
+ Pattern p = Pattern.compile(Pattern.quote(pattern1) + "(.*?)" + Pattern.quote(pattern2));
+ Matcher m = p.matcher(request);
+ if (m.find()) {
+ return m.group(1);
+ }
+ return null;
+ }
+
+ public void processSessionInParallel() throws InterruptedException, IOException {
+
+ List<String> sessions = this.getSessions();
+ JavaRDD<String> sessionRDD = spark.sc.parallelize(sessions, partition);
+
+ int sessionCount = 0;
+ sessionCount = sessionRDD.mapPartitions(new FlatMapFunction<Iterator<String>, Integer>() {
+ @Override
+ public Iterator<Integer> call(Iterator<String> arg0) throws Exception {
+ ESDriver tmpES = new ESDriver(props);
+ tmpES.createBulkProcessor();
+ List<Integer> sessionNums = new ArrayList<Integer>();
+ sessionNums.add(0);
+ while (arg0.hasNext()) {
+ String s = arg0.next();
+ Integer sessionNum = processSession(tmpES, s);
+ sessionNums.add(sessionNum);
+ }
+ tmpES.destroyBulkProcessor();
+ tmpES.close();
+ return sessionNums.iterator();
+ }
+ }).reduce(new Function2<Integer, Integer, Integer>() {
+ @Override
+ public Integer call(Integer a, Integer b) {
+ return a + b;
+ }
+ });
+
+ LOG.info("Final Session count: {}", Integer.toString(sessionCount));
+ }
+
+ public int processSession(ESDriver es, String sessionId) throws IOException, InterruptedException, ExecutionException {
+
+ String inputType = cleanupType;
+ String outputType = sessionStats;
+
+ DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+ String min = null;
+ String max = null;
+ DateTime start = null;
+ DateTime end = null;
+ int duration = 0;
+ float request_rate = 0;
+
+ int session_count = 0;
+ Pattern pattern = Pattern.compile("get (.*?) http/*");
+
+ StatsAggregationBuilder statsAgg = AggregationBuilders.stats("Stats").field("Time");
+
+ BoolQueryBuilder filter_search = new BoolQueryBuilder();
+ filter_search.must(QueryBuilders.termQuery("SessionID", sessionId));
+
+ SearchResponse sr = es.getClient().prepareSearch(logIndex).setTypes(inputType).setQuery(filter_search).addAggregation(statsAgg).execute().actionGet();
+
+ Stats agg = sr.getAggregations().get("Stats");
+ min = agg.getMinAsString();
+ max = agg.getMaxAsString();
+ start = fmt.parseDateTime(min);
+ end = fmt.parseDateTime(max);
+
+ duration = Seconds.secondsBetween(start, end).getSeconds();
+
+ int searchDataListRequest_count = 0;
+ int searchDataRequest_count = 0;
+ int searchDataListRequest_byKeywords_count = 0;
+ int ftpRequest_count = 0;
+ int keywords_num = 0;
+
+ String IP = null;
+ String keywords = "";
+ String views = "";
+ String downloads = "";
+
+ SearchResponse scrollResp = es.getClient().prepareSearch(logIndex).setTypes(inputType).setScroll(new TimeValue(60000)).setQuery(filter_search).setSize(100).execute().actionGet();
+
+ while (true) {
+ for (SearchHit hit : scrollResp.getHits().getHits()) {
+ Map<String, Object> result = hit.getSource();
+
+ String request = (String) result.get("Request");
+ String logType = (String) result.get("LogType");
+ IP = (String) result.get("IP");
+ Matcher matcher = pattern.matcher(request.trim().toLowerCase());
+ while (matcher.find()) {
+ request = matcher.group(1);
+ }
+
+ String datasetlist = "/datasetlist?";
+ String dataset = "/dataset/";
+ if (request.contains(datasetlist)) {
+ searchDataListRequest_count++;
+
+ RequestUrl requestURL = new RequestUrl();
+ String infoStr = requestURL.getSearchInfo(request) + ",";
+ String info = es.customAnalyzing(props.getProperty("indexName"), infoStr);
+
+ if (!info.equals(",")) {
+ if (keywords.equals("")) {
+ keywords = keywords + info;
+ } else {
+ String[] items = info.split(",");
+ String[] keywordList = keywords.split(",");
+ for (int m = 0; m < items.length; m++) {
+ if (!Arrays.asList(keywordList).contains(items[m])) {
+ keywords = keywords + items[m] + ",";
+ }
+ }
+ }
+ }
+
+ }
+ if (request.startsWith(dataset)) {
+ searchDataRequest_count++;
+ if (findDataset(request) != null) {
+ String view = findDataset(request);
+
+ if ("".equals(views)) {
+ views = view;
+ } else {
+ if (views.contains(view)) {
+
+ } else {
+ views = views + "," + view;
+ }
+ }
+ }
+ }
+ if ("ftp".equals(logType)) {
+ ftpRequest_count++;
+ String download = "";
+ String requestLowercase = request.toLowerCase();
+ if (requestLowercase.endsWith(".jpg") == false && requestLowercase.endsWith(".pdf") == false && requestLowercase.endsWith(".txt") == false && requestLowercase.endsWith(".gif") == false) {
+ download = request;
+ }
+
+ if ("".equals(downloads)) {
+ downloads = download;
+ } else {
+ if (downloads.contains(download)) {
+
+ } else {
+ downloads = downloads + "," + download;
+ }
+ }
+ }
+
+ }
+
+ scrollResp = es.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
+ // Break condition: No hits are returned
+ if (scrollResp.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+
+ if (!keywords.equals("")) {
+ keywords_num = keywords.split(",").length;
+ }
+
+ if (searchDataListRequest_count != 0 && searchDataListRequest_count <= Integer.parseInt(props.getProperty("searchf")) && searchDataRequest_count != 0 && searchDataRequest_count <= Integer
+ .parseInt(props.getProperty("viewf")) && ftpRequest_count <= Integer.parseInt(props.getProperty("downloadf"))) {
+ String sessionURL = props.getProperty("SessionPort") + props.getProperty("SessionUrl") + "?sessionid=" + sessionId + "&sessionType=" + outputType + "&requestType=" + inputType;
+ session_count = 1;
+
+ IndexRequest ir = new IndexRequest(logIndex, outputType).source(
+ jsonBuilder().startObject().field("SessionID", sessionId).field("SessionURL", sessionURL).field("Duration", duration).field("Number of Keywords", keywords_num).field("Time", min)
+ .field("End_time", max).field("searchDataListRequest_count", searchDataListRequest_count).field("searchDataListRequest_byKeywords_count", searchDataListRequest_byKeywords_count)
+ .field("searchDataRequest_count", searchDataRequest_count).field("keywords", es.customAnalyzing(logIndex, keywords)).field("views", views).field("downloads", downloads)
+ .field("request_rate", request_rate).field("Comments", "").field("Validation", 0).field("Produceby", 0).field("Correlation", 0).field("IP", IP).endObject());
+
+ es.getBulkProcessor().add(ir);
+ }
+
+ return session_count;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/package-info.java
new file mode 100644
index 0000000..5a3a1c3
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/pre/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes Preprocessing for all functionality required by the
+ * {@link gov.nasa.jpl.mudrod.discoveryengine.WeblogDiscoveryEngine}
+ */
+package gov.nasa.jpl.mudrod.weblog.pre;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/ClickStreamAnalyzer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/ClickStreamAnalyzer.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/ClickStreamAnalyzer.java
new file mode 100644
index 0000000..2b8f45f
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/ClickStreamAnalyzer.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.process;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.semantics.SVDAnalyzer;
+import gov.nasa.jpl.mudrod.ssearch.ClickstreamImporter;
+import gov.nasa.jpl.mudrod.utils.LinkageTriple;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Supports ability to calculate term similarity based on click stream
+ */
+public class ClickStreamAnalyzer extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClickStreamAnalyzer.class);
+
+ public ClickStreamAnalyzer(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Method of executing click stream analyzer
+ */
+ @Override
+ public Object execute() {
+ LOG.info("Starting ClickStreamAnalyzer...");
+ startTime = System.currentTimeMillis();
+ try {
+ String clickstream_matrixFile = props.getProperty("clickstreamMatrix");
+ File f = new File(clickstream_matrixFile);
+ if (f.exists()) {
+ SVDAnalyzer svd = new SVDAnalyzer(props, es, spark);
+ svd.getSVDMatrix(props.getProperty("clickstreamMatrix"), Integer.parseInt(props.getProperty("clickstreamSVDDimension")), props.getProperty("clickstreamSVDMatrix_tmp"));
+ List<LinkageTriple> tripleList = svd.calTermSimfromMatrix(props.getProperty("clickstreamSVDMatrix_tmp"));
+ svd.saveToES(tripleList, props.getProperty("indexName"), props.getProperty("clickStreamLinkageType"));
+
+ // Store click stream in ES for the ranking use
+ ClickstreamImporter cs = new ClickstreamImporter(props, es, spark);
+ cs.importfromCSVtoES();
+ }
+ } catch (Exception e) {
+ LOG.error("Encountered an error during execution of ClickStreamAnalyzer.", e);
+ }
+
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("ClickStreamAnalyzer complete. Time elapsed: {}s", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/UserHistoryAnalyzer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/UserHistoryAnalyzer.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/UserHistoryAnalyzer.java
new file mode 100644
index 0000000..248756b
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/UserHistoryAnalyzer.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.process;
+
+import gov.nasa.jpl.mudrod.discoveryengine.DiscoveryStepAbstract;
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.semantics.SemanticAnalyzer;
+import gov.nasa.jpl.mudrod.utils.LinkageTriple;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Supports ability to calculate term similarity based on user history
+ */
+public class UserHistoryAnalyzer extends DiscoveryStepAbstract {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private static final Logger LOG = LoggerFactory.getLogger(UserHistoryAnalyzer.class);
+
+ public UserHistoryAnalyzer(Properties props, ESDriver es, SparkDriver spark) {
+ super(props, es, spark);
+ }
+
+ /**
+ * Method of executing user history analyzer
+ */
+ @Override
+ public Object execute() {
+ LOG.info("Starting UserHistoryAnalyzer...");
+ startTime = System.currentTimeMillis();
+
+ SemanticAnalyzer sa = new SemanticAnalyzer(props, es, spark);
+ List<LinkageTriple> tripleList = sa.calTermSimfromMatrix(props.getProperty("userHistoryMatrix"));
+ sa.saveToES(tripleList, props.getProperty(MudrodConstants.ES_INDEX_NAME), props.getProperty(MudrodConstants.USE_HISTORY_LINKAGE_TYPE));
+
+ endTime = System.currentTimeMillis();
+ es.refreshIndex();
+ LOG.info("UserHistoryAnalyzer complete. Time elapsed: {}s", (endTime - startTime) / 1000);
+ return null;
+ }
+
+ @Override
+ public Object execute(Object o) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/package-info.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/package-info.java
new file mode 100644
index 0000000..e96fd3c
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/process/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes web log processing classes.
+ */
+package gov.nasa.jpl.mudrod.weblog.process;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ApacheAccessLog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ApacheAccessLog.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ApacheAccessLog.java
new file mode 100644
index 0000000..1051384
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ApacheAccessLog.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import com.google.gson.Gson;
+import gov.nasa.jpl.mudrod.weblog.pre.CrawlerDetection;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class represents an Apache access log line. See
+ * http://httpd.apache.org/docs/2.2/logs.html for more details.
+ */
+public class ApacheAccessLog extends WebLog implements Serializable {
+
+ // double Bytes;
+ String Response;
+ String Referer;
+ String Browser;
+
+ @Override
+ public double getBytes() {
+ return this.Bytes;
+ }
+
+ public String getBrowser() {
+ return this.Browser;
+ }
+
+ public String getResponse() {
+ return this.Response;
+ }
+
+ public String getReferer() {
+ return this.Referer;
+ }
+
+ public ApacheAccessLog() {
+
+ }
+
+ public static String parseFromLogLine(String log) throws IOException, ParseException {
+
+ String logEntryPattern = "^([\\d.]+) (\\S+) (\\S+) \\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(.+?)\" (\\d{3}) (\\d+|-) \"((?:[^\"]|\")+)\" \"([^\"]+)\"";
+ final int NUM_FIELDS = 9;
+ Pattern p = Pattern.compile(logEntryPattern);
+ Matcher matcher;
+
+ String lineJson = "{}";
+ matcher = p.matcher(log);
+ if (!matcher.matches() || NUM_FIELDS != matcher.groupCount()) {
+ return lineJson;
+ }
+
+ String time = matcher.group(4);
+ time = SwithtoNum(time);
+ SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy:HH:mm:ss");
+ Date date = formatter.parse(time);
+
+ String bytes = matcher.group(7);
+
+ if (bytes.equals("-")) {
+ bytes = "0";
+ }
+
+ String request = matcher.group(5).toLowerCase();
+ String agent = matcher.group(9);
+ CrawlerDetection crawlerDe = new CrawlerDetection();
+ if (crawlerDe.checkKnownCrawler(agent)) {
+ return lineJson;
+ } else {
+
+ boolean tag = false;
+ String[] mimeTypes = { ".js", ".css", ".jpg", ".png", ".ico", "image_captcha", "autocomplete", ".gif", "/alldata/", "/api/", "get / http/1.1", ".jpeg", "/ws/" };
+ for (int i = 0; i < mimeTypes.length; i++) {
+ if (request.contains(mimeTypes[i])) {
+ tag = true;
+ return lineJson;
+ }
+ }
+
+ if (tag == false) {
+ ApacheAccessLog accesslog = new ApacheAccessLog();
+ accesslog.LogType = "PO.DAAC";
+ accesslog.IP = matcher.group(1);
+ accesslog.Request = matcher.group(5);
+ accesslog.Response = matcher.group(6);
+ accesslog.Bytes = Double.parseDouble(bytes);
+ accesslog.Referer = matcher.group(8);
+ accesslog.Browser = matcher.group(9);
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'");
+ accesslog.Time = df.format(date);
+
+ Gson gson = new Gson();
+ lineJson = gson.toJson(accesslog);
+
+ return lineJson;
+ }
+ }
+
+ lineJson = "{}";
+ return lineJson;
+ }
+
+ public static boolean checknull(WebLog s) {
+ if (s == null) {
+ return false;
+ }
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ClickStream.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ClickStream.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ClickStream.java
new file mode 100644
index 0000000..76e8d7a
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/ClickStream.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+
+import java.io.Serializable;
+
+/**
+ * ClassName: ClickStream Function: user click stream data related operations.
+ */
+public class ClickStream implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ // keywords: query words related to the click behaviour
+ private String keywords;
+ // viewDataset: the dataset name user viewed
+ private String viewDataset;
+ // downloadDataset: the dataset name user downloaded
+ private String downloadDataset;
+ // sessionID: session ID
+ private String sessionID;
+ // type: session type name
+ private String type;
+
+ /**
+ * Creates a new instance of ClickStream.
+ *
+ * @param keywords the query user searched
+ * @param viewDataset the dataset name user viewed
+ * @param download: if user download the data set after viewing it, this parameter is
+ * true, otherwise, it is false.
+ */
+ public ClickStream(String keywords, String viewDataset, boolean download) {
+ this.keywords = keywords;
+ this.viewDataset = viewDataset;
+ this.downloadDataset = "";
+ if (download) {
+ this.downloadDataset = viewDataset;
+ }
+ }
+
+ public ClickStream() {
+ //default constructor
+ }
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * setKeyWords: Set the query user searched.
+ *
+ * @param query search words
+ */
+ public void setKeyWords(String query) {
+ this.keywords = query;
+ }
+
+ /**
+ * setViewDataset:Set the data set name user viewed
+ *
+ * @param dataset short name of data set
+ */
+ public void setViewDataset(String dataset) {
+ this.viewDataset = dataset;
+ }
+
+ /**
+ * setDownloadDataset: Set the data set name user downloaded
+ *
+ * @param dataset short name of data set
+ */
+ public void setDownloadDataset(String dataset) {
+ this.downloadDataset = dataset;
+ }
+
+ /**
+ * getKeyWords: Get the query user searched
+ *
+ * @return data set name
+ */
+ public String getKeyWords() {
+ return this.keywords;
+ }
+
+ /**
+ * getViewDataset: Get the data set user viewed
+ *
+ * @return data set name
+ */
+ public String getViewDataset() {
+ return this.viewDataset;
+ }
+
+ /**
+ * isDownload: Show whether the data is downloaded in the session.
+ *
+ * @return True or False
+ */
+ public Boolean isDownload() {
+ if ("".equals(this.downloadDataset)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * setSessionId: Set ID of session
+ *
+ * @param sessionID session id
+ */
+ public void setSessionId(String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ /**
+ * setType: Set session type name
+ *
+ * @param type session type name in elasticsearch
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Output click stream info in string format
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "Query: " + keywords + " || View Dataset: " + viewDataset + " || Download Dataset: " + downloadDataset;
+ }
+
+ /**
+ * toJson: Output click stream info in Json format
+ *
+ * @return session in string format
+ */
+ public String toJson() {
+ String jsonQuery = "{";
+ jsonQuery += "\"query\":\"" + this.keywords + "\",";
+ jsonQuery += "\"viewdataset\":\"" + this.viewDataset + "\",";
+ jsonQuery += "\"downloaddataset\":\"" + this.downloadDataset + "\",";
+ jsonQuery += "\"sessionId\":\"" + this.sessionID + "\",";
+ jsonQuery += "\"type\":\"" + this.type + "\"";
+ jsonQuery += "},";
+ return jsonQuery;
+ }
+
+ /**
+ * parseFromTextLine: Convert string to click stream data
+ *
+ * @param logline http log line
+ * @return {@link ClickStream}
+ */
+ public static ClickStream parseFromTextLine(String logline) {
+ JSONObject jsonData = null;
+ ClickStream data = null;
+ try {
+ jsonData = new JSONObject(logline);
+ data = new ClickStream();
+ data.setKeyWords(jsonData.getString("query"));
+ data.setViewDataset(jsonData.getString("viewdataset"));
+ data.setDownloadDataset(jsonData.getString("downloaddataset"));
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ return data;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Coordinates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Coordinates.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Coordinates.java
new file mode 100644
index 0000000..f416eb4
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/Coordinates.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+public class Coordinates {
+ /*
+ * public String lat; public String lon;
+ */
+ public String latlon;
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java
new file mode 100644
index 0000000..5ddc717
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/FtpLog.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import com.google.gson.Gson;
+import gov.nasa.jpl.mudrod.weblog.pre.ImportLogFile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * This class represents an FTP access log line.
+ */
+public class FtpLog extends WebLog implements Serializable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ImportLogFile.class);
+
+ public static String parseFromLogLine(String log) {
+
+ try {
+ String ip = log.split(" +")[6];
+
+ String time = log.split(" +")[1] + ":" + log.split(" +")[2] + ":" + log.split(" +")[3] + ":" + log.split(" +")[4];
+
+ time = SwithtoNum(time);
+ SimpleDateFormat formatter = new SimpleDateFormat("MM:dd:HH:mm:ss:yyyy");
+ Date date = formatter.parse(time);
+
+ String bytes = log.split(" +")[7];
+
+ String request = log.split(" +")[8].toLowerCase();
+
+ if (!request.contains("/misc/") && !request.contains("readme")) {
+ FtpLog ftplog = new FtpLog();
+ ftplog.LogType = "ftp";
+ ftplog.IP = ip;
+ ftplog.Request = request;
+ ftplog.Bytes = Double.parseDouble(bytes);
+
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'");
+ ftplog.Time = df.format(date);
+
+ return new Gson().toJson(ftplog);
+ }
+ } catch (Exception e) {
+ LOG.warn("Error parsing ftp log line [{}]. Skipping this line.", log, e);
+ }
+ return "{}";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/GeoIp.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/GeoIp.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/GeoIp.java
new file mode 100644
index 0000000..778224b
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/GeoIp.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import gov.nasa.jpl.mudrod.utils.HttpRequest;
+
+/**
+ * ClassName: GeoIp Function: convert IP to geo location
+ */
+public class GeoIp {
+
+ /**
+ * toLocation: convert ip to location
+ *
+ * @param ip ip address
+ * @return coordinates
+ */
+ public Coordinates toLocation(String ip) {
+ String url = "http://getcitydetails.geobytes.com/GetCityDetails?fqcn=" + ip;
+ HttpRequest http = new HttpRequest();
+ String response = http.getRequest(url);
+ JsonParser parser = new JsonParser();
+ JsonElement jobSon = parser.parse(response);
+ JsonObject responseObject = jobSon.getAsJsonObject();
+
+ Coordinates co = new Coordinates();
+ String lon = responseObject.get("geobyteslongitude").toString().replace("\"", "");
+ String lat = responseObject.get("geobyteslatitude").toString().replace("\"", "");
+ co.latlon = lat + "," + lon;
+ return co;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RankingTrainData.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RankingTrainData.java b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RankingTrainData.java
new file mode 100644
index 0000000..7ea17c0
--- /dev/null
+++ b/core/src/main/java/gov/nasa/jpl/mudrod/weblog/structure/RankingTrainData.java
@@ -0,0 +1,147 @@
+package gov.nasa.jpl.mudrod.weblog.structure;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * ClassName: train data extracted from web logs for training ranking weightss.
+ */
+public class RankingTrainData implements Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ // sessionID: session ID
+ private String sessionID;
+ // type: session type name
+ private String index;
+ // query: query words related to the click
+ private String query;
+ // datasetA
+ private String highRankDataset;
+ // datasetB
+ private String lowRankDataset;
+
+ private Map<String, String> filter;
+
+ /**
+ * Creates a new instance of ClickStream.
+ *
+ * @param query the user query string
+ * @param highRankDataset the dataset name for the highest ranked dataset
+ * @param lowRankDataset the dataset name for the lowest ranked dataset
+ */
+ public RankingTrainData(String query, String highRankDataset, String lowRankDataset) {
+ this.query = query;
+ this.highRankDataset = highRankDataset;
+ this.lowRankDataset = lowRankDataset;
+ }
+
+ public RankingTrainData() {
+ //default constructor
+ }
+
+ public String getSessionID() {
+ return sessionID;
+ }
+
+ /**
+ * setKeyWords: Set the query user searched.
+ *
+ * @param query search words
+ */
+ public void setQuery(String query) {
+ this.query = query;
+ }
+
+ /**
+ * getKeyWords: Get the query user searched
+ *
+ * @return data set name
+ */
+ public String getQuery() {
+ return this.query;
+ }
+
+ /**
+ * setViewDataset:Set the data set name user viewed
+ *
+ * @param dataset short name of data set
+ */
+ public void setHighRankDataset(String dataset) {
+ this.highRankDataset = dataset;
+ }
+
+ /**
+ * setDownloadDataset: Set the data set name user downloaded
+ *
+ * @param dataset short name of data set
+ */
+ public void setLowRankDataset(String dataset) {
+ this.lowRankDataset = dataset;
+ }
+
+ /**
+ * getViewDataset: Get the data set user viewed
+ *
+ * @return data set name
+ */
+ public String getLowRankDataset() {
+ return this.lowRankDataset;
+ }
+
+ /**
+ * setSessionId: Set ID of session
+ *
+ * @param sessionID session id
+ */
+ public void setSessionId(String sessionID) {
+ this.sessionID = sessionID;
+ }
+
+ /**
+ * setType: Set session type name
+ *
+ * @param index session type name in elasticsearch
+ */
+ public void setIndex(String index) {
+ this.index = index;
+ }
+
+ public void setFilter(Map<String, String> filter) {
+ this.filter = filter;
+ }
+
+ /**
+ * Output click stream info in string format
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "query:" + query + "|| highRankDataset:" + highRankDataset + "|| lowRankDataset:" + lowRankDataset;
+ }
+
+ /**
+ * toJson: Output click stream info in Json format
+ *
+ * @return session in string format
+ */
+ public String toJson() {
+ String jsonQuery = "{";
+ jsonQuery += "\"query\":\"" + this.query + "\",";
+ jsonQuery += "\"highRankDataset\":\"" + this.highRankDataset + "\",";
+ jsonQuery += "\"lowRankDataset\":\"" + this.lowRankDataset + "\",";
+
+ if (this.filter != null) {
+ for (String key : filter.keySet()) {
+ jsonQuery += "\"" + key + "\":\"" + filter.get(key) + "\",";
+ }
+ }
+
+ jsonQuery += "\"sessionId\":\"" + this.sessionID + "\",";
+ jsonQuery += "\"index\":\"" + this.index + "\"";
+ jsonQuery += "},";
+ return jsonQuery;
+ }
+}
[10/21] incubator-sdap-mudrod git commit: SDAP-1 Import all code
under the SDAP SGA
Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/pom.xml
----------------------------------------------------------------------
diff --git a/service/pom.xml b/service/pom.xml
new file mode 100644
index 0000000..1704c50
--- /dev/null
+++ b/service/pom.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>gov.nasa.jpl.mudrod</groupId>
+ <artifactId>mudrod-parent</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <relativePath>../</relativePath>
+ </parent>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>miredot</id>
+ <name>MireDot Releases</name>
+ <url>http://nexus.qmino.com/content/repositories/miredot</url>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <artifactId>mudrod-service</artifactId>
+ <packaging>war</packaging>
+ <name>Mudrod :: Service</name>
+ <description>Mudrod WebService implementation.</description>
+
+ <dependencies>
+ <!-- Core Module -->
+ <dependency>
+ <groupId>gov.nasa.jpl.mudrod</groupId>
+ <artifactId>mudrod-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Static web resources -->
+ <dependency>
+ <groupId>gov.nasa.jpl.mudrod</groupId>
+ <artifactId>mudrod-web</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Logging dependencies -->
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ </dependency>
+ <!-- End of Logging dependencies -->
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-client</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.tomcat.maven</groupId>
+ <artifactId>tomcat7-maven-plugin</artifactId>
+ <version>2.2</version>
+ <configuration>
+ <port>8080</port>
+ <systemProperties>
+ <CATALINA_OPTS>-Djava.awt.headless=true
+ -Dfile.encoding=UTF-8
+ -server -Xms1536m -Xmx1536m
+ -XX:NewSize=256m -XX:MaxNewSize=256m
+ -XX:PermSize=256m
+ -XX:+DisableExplicitGC
+ -XX:+UseConcMarkSweepGC
+ -XX:+CMSIncrementalMode
+ -XX:+CMSIncrementalPacing
+ -XX:CMSIncrementalDutyCycleMin=0
+ -XX:-TraceClassUnloading
+ </CATALINA_OPTS>
+ </systemProperties>
+ <contextFile>
+ ${basedir}/src/main/webapp/META-INF/context.xml
+ </contextFile>
+ <path>/${project.build.finalName}</path>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>2.6</version>
+ <executions>
+ <execution>
+ <id>self-contained-war</id>
+ <phase>package</phase>
+ <goals>
+ <goal>war</goal>
+ </goals>
+ <configuration>
+ <webResources>
+ <resource>
+ <directory>
+ ${project.build.directory}/war-legals/with-deps/
+ </directory>
+ <targetPath>/META-INF</targetPath>
+ </resource>
+ </webResources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>war-without-deps</id>
+ <phase>package</phase>
+ <goals>
+ <goal>war</goal>
+ </goals>
+ <configuration>
+ <classifier>without-deps</classifier>
+ <packagingExcludes>WEB-INF/lib/*.jar
+ </packagingExcludes>
+ <archive>
+ <manifest>
+ <addClasspath>true</addClasspath>
+ <classpathPrefix>lib/</classpathPrefix>
+ </manifest>
+ </archive>
+ <webResources>
+ <resource>
+ <directory>
+ ${project.build.directory}/war-legals/without-deps/
+ </directory>
+ <targetPath>/META-INF</targetPath>
+ </resource>
+ </webResources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Generates the distribution package -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>prepare-package</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <attach>false</attach>
+ <finalName>war-legals</finalName>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptors>
+ <descriptor>
+ ${basedir}/src/main/assembly/prepare-war-legals.xml
+ </descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ <configuration>
+ <descriptors>
+ <descriptor>${basedir}/src/main/assembly/with-deps.xml
+ </descriptor>
+ <descriptor>
+ ${basedir}/src/main/assembly/without-deps.xml
+ </descriptor>
+ <descriptor>
+ ${basedir}/src/main/assembly/server-embedded.xml
+ </descriptor>
+ </descriptors>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>com.qmino</groupId>
+ <artifactId>miredot-plugin</artifactId>
+ <version>2.0.3</version>
+ <executions>
+ <execution>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>restdoc</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- The license key expires on may 1st, 2019, after which
+ we can apply to Miredot for a new key. -->
+ <licence>cHJvamVjdHxnb3YubmFzYS5qcGwubXVkcm9kLm11ZHJvZC1zZXJ2aWNlfDIwMTktMDUtMDJ8dHJ1ZXwtMSNNQ3dDRkZ6QXBGdzA4dUdJVGtYcml3ckJRbis5WjdLWkFoUWgyaVRZS2EwVTF3NGlObWxlRDlDVzJoaWE5UT09</licence>
+ <organizationId>f3f4ce56-816e-4f1d-963e-e7936ee846c5</organizationId>
+ <restModel>
+ <restFramework>
+ <name>jax-rs</name>
+ </restFramework>
+ </restModel>
+ <output>
+ <html></html>
+ </output>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <resources>
+ <resource>
+ <directory>${basedir}/../</directory>
+ <targetPath>
+ ${project.build.directory}/apidocs/META-INF
+ </targetPath>
+ <includes>
+ <include>LICENSE.txt</include>
+ <include>NOTICE.txt</include>
+ </includes>
+ </resource>
+ </resources>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/LICENSE-server-embedded.txt
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/LICENSE-server-embedded.txt b/service/src/main/assembly/LICENSE-server-embedded.txt
new file mode 100644
index 0000000..8c1c026
--- /dev/null
+++ b/service/src/main/assembly/LICENSE-server-embedded.txt
@@ -0,0 +1,219 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+MUDROD DEPENDENCIES:
+
+The Murdor distribution packages include a number of dependencies with
+separate copyright notices and license terms. Your use of the binaries for these
+dependencies is subject to the terms and conditions of the following licenses.
+
+For the Google Gson (https://github.com/google/gson)
+This is licensed under the Apache License v2.0, see above
+
+For the Jetty Web Container (http://mortbay.com/)
+This is licensed under the Apache License v2.0, see above
+
+For the Apache Spark components (http://www.aduna-software.org/)
+This is licensed under the Aduna BSD license, see above
+
+... TODO
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/LICENSE-with-deps.txt
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/LICENSE-with-deps.txt b/service/src/main/assembly/LICENSE-with-deps.txt
new file mode 100644
index 0000000..8b0652f
--- /dev/null
+++ b/service/src/main/assembly/LICENSE-with-deps.txt
@@ -0,0 +1,217 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+MUDROD DEPENDENCIES:
+
+The Murdor distribution packages include a number of dependencies with
+separate copyright notices and license terms. Your use of the binaries for these
+dependencies is subject to the terms and conditions of the following licenses.
+
+For the Google Gson (https://github.com/google/gson)
+This is licensed under the Apache License v2.0, see above
+
+For the Jetty Web Container (http://mortbay.com/)
+This is licensed under the Apache License v2.0, see above
+
+For the Apache Spark components (http://www.aduna-software.org/)
+This is licensed under the Aduna BSD license, see above
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/LICENSE-without-deps.txt
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/LICENSE-without-deps.txt b/service/src/main/assembly/LICENSE-without-deps.txt
new file mode 100644
index 0000000..ccf4044
--- /dev/null
+++ b/service/src/main/assembly/LICENSE-without-deps.txt
@@ -0,0 +1,206 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+APACHE ANY23 DEPENDENCIES:
+
+TODO
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/NOTICE-server-embedded.txt
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/NOTICE-server-embedded.txt b/service/src/main/assembly/NOTICE-server-embedded.txt
new file mode 100644
index 0000000..e00d042
--- /dev/null
+++ b/service/src/main/assembly/NOTICE-server-embedded.txt
@@ -0,0 +1,4 @@
+Mudrod
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/NOTICE-with-deps.txt
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/NOTICE-with-deps.txt b/service/src/main/assembly/NOTICE-with-deps.txt
new file mode 100644
index 0000000..6e464c1
--- /dev/null
+++ b/service/src/main/assembly/NOTICE-with-deps.txt
@@ -0,0 +1,6 @@
+Mudrod
+Copyright 2011-2012 The Apache Software Foundation
+Copyright 2008-2011 Digital Enterprise Research Institute (DERI)
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/NOTICE-without-deps.txt
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/NOTICE-without-deps.txt b/service/src/main/assembly/NOTICE-without-deps.txt
new file mode 100644
index 0000000..e00d042
--- /dev/null
+++ b/service/src/main/assembly/NOTICE-without-deps.txt
@@ -0,0 +1,4 @@
+Mudrod
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/README.txt
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/README.txt b/service/src/main/assembly/README.txt
new file mode 100644
index 0000000..3cf10aa
--- /dev/null
+++ b/service/src/main/assembly/README.txt
@@ -0,0 +1,110 @@
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+
+Apache Any23 Service ${project.version} (${implementation.build.tstamp})
+
+ What is it?
+ -----------
+
+ ${project.description}
+
+ Documentation
+ -------------
+
+ The most up-to-date documentation can be found at ${project.parent.url}.
+
+ Release Notes
+ -------------
+
+ The full list of changes can be found at ${project.parent.url}/service.html.
+
+ System Requirements
+ -------------------
+
+ JDK:
+ ${javac.target.version} or above. (see http://www.oracle.com/technetwork/java/)
+ Memory:
+ No minimum requirement.
+ Disk:
+ No minimum requirement.
+ Operating System:
+ No minimum requirement. On Windows, Windows NT and above or Cygwin is required for
+ the startup scripts. Tested on Windows XP, Fedora Core and Mac OS X.
+
+ Installing Apache Any23 Service
+ ----------------
+
+** Windows 2000/XP
+
+ 1) Unzip the distribution archive, i.e. apache-${project.build.finalName}-bin.zip to the directory you wish to
+ install Apache Any23 ${project.version}.
+ These instructions assume you chose C:\Program Files\Apache Software Foundation.
+ The subdirectory apache-${project.build.finalName} will be created from the archive.
+
+ 2) Add the ANY23_HOME environment variable by opening up the system properties (WinKey + Pause),
+ selecting the "Advanced" tab, and the "Environment Variables" button, then adding the ANY23_HOME
+ variable in the user variables with the value
+ C:\Program Files\Apache Software Foundation\apache-${project.build.finalName}.
+
+ 3) In the same dialog, add the ANY23 environment variable in the user variables with the value %ANY23_HOME%\bin.
+
+ 4) Optional: In the same dialog, add the EXTRA_JVM_ARGUMENTS environment variable in the user variables to specify
+ JVM properties, e.g. the value -Xms256m -Xmx512m. This environment variable can be used to supply extra options.
+ By default, it is set to: -Xms500m -Xmx500m -XX:PermSize=128m -XX:-UseGCOverheadLimit
+
+ 5) In the same dialog, update/create the Path environment variable in the user variables and prepend the value
+ %ANY23% to add Apache Any23 available in the command line.
+
+ 6) In the same dialog, make sure that JAVA_HOME exists in your user variables or in the system variables and it is
+ set to the location of your JDK, e.g. C:\Program Files\Java\jdk1.5.0_02 and that %JAVA_HOME%\bin is in your Path
+ environment variable.
+
+ 7) Open a new command prompt (Winkey + R then type cmd) and run any23server to launch the service.
+
+** Unix-based Operating Systems (Linux, Solaris and Mac OS X)
+
+ 1) Extract the distribution archive, i.e. apache-${project.build.finalName}-bin.tar.gz to the directory you wish to
+ install Apache Any23 ${project.version}.
+ These instructions assume you chose /usr/local/apache-any23.
+ The subdirectory apache-${project.build.finalName} will be created from the archive.
+
+ 2) In a command terminal, add the ANY23_HOME environment variable, e.g.
+ export ANY23_HOME=/usr/local/apache-any23/apache-${project.build.finalName}.
+
+ 3) Add the ANY23 environment variable, e.g. export ANY23=$ANY23_HOME/bin.
+
+ 4) Optional: Add the EXTRA_JVM_ARGUMENTS environment variable to specify JVM properties, e.g.
+ export EXTRA_JVM_ARGUMENTS="-Xms256m -Xmx512m".
+ This environment variable can be used to supply extra options.
+
+ 5) Add ANY23 environment variable to your path, e.g. export PATH=$ANY23:$PATH.
+
+ 6) Make sure that JAVA_HOME is set to the location of your JDK, e.g.
+ export JAVA_HOME=/usr/java/jdk1.5.0_02 and that $JAVA_HOME/bin is in your PATH environment variable.
+
+ 7) Run any23server to launch the service.
+
+ Licensing
+ ---------
+
+ Please see the file called LICENSE.TXT
+
+ Apache Any23 URLS
+ ----------
+
+ Home Page: ${project.parent.url}/
+ Downloads: ${project.parent.url}/download.html
+ Release Notes: ${project.parent.url}/changes-report.html
+ Mailing Lists: ${project.parent.url}/mail-lists.html
+ Source Code: ${project.parent.scm.url}
+ Issue Tracking: ${project.issueManagement.url}
+ Available Plugins: ${project.parent.url}/plugins.html
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/prepare-war-legals.xml
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/prepare-war-legals.xml b/service/src/main/assembly/prepare-war-legals.xml
new file mode 100644
index 0000000..bc4ee1c
--- /dev/null
+++ b/service/src/main/assembly/prepare-war-legals.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+
+ <id>prepare-war-legals</id>
+ <formats>
+ <format>dir</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <files>
+ <file>
+ <source>${basedir}/src/main/assembly/LICENSE-with-deps.txt</source>
+ <destName>LICENSE.txt</destName>
+ <outputDirectory>/with-deps</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/src/main/assembly/NOTICE-with-deps.txt</source>
+ <destName>NOTICE.txt</destName>
+ <outputDirectory>/with-deps</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/src/main/assembly/LICENSE-without-deps.txt
+ </source>
+ <destName>LICENSE.txt</destName>
+ <outputDirectory>/without-deps</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ </files>
+
+</assembly>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/server-embedded.xml
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/server-embedded.xml b/service/src/main/assembly/server-embedded.xml
new file mode 100644
index 0000000..88e9433
--- /dev/null
+++ b/service/src/main/assembly/server-embedded.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+
+ <id>server-embedded</id>
+ <formats>
+ <format>tar.gz</format>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>${project.build.finalName}-server-embedded</baseDirectory>
+
+ <files>
+ <file>
+ <source>${basedir}/src/main/assembly/README.txt</source>
+ <filtered>true</filtered>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/src/main/assembly/LICENSE-server-embedded.txt
+ </source>
+ <destName>LICENSE.txt</destName>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/src/main/assembly/NOTICE-server-embedded.txt
+ </source>
+ <destName>NOTICE.txt</destName>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/../RELEASE-NOTES.txt</source>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ </files>
+
+ <fileSets>
+ <!--
+ | shell scripts
+ -->
+ <fileSet>
+ <directory>${basedir}/src/main/bin/</directory>
+ <outputDirectory>/bin</outputDirectory>
+ <fileMode>755</fileMode>
+ <filtered>true</filtered>
+ </fileSet>
+ </fileSets>
+
+ <dependencySets>
+ <dependencySet>
+ <useProjectArtifact>true</useProjectArtifact>
+ <outputDirectory>/lib</outputDirectory>
+ <includes>
+ <include>${project.groupId}:${project.artifactId}</include>
+ </includes>
+ </dependencySet>
+
+ <dependencySet>
+ <useProjectArtifact>true</useProjectArtifact>
+ <outputDirectory>/lib</outputDirectory>
+ <scope>provided</scope>
+ <includes>
+ <include>org.mortbay.jetty:jetty-runner</include>
+ </includes>
+ </dependencySet>
+ </dependencySets>
+
+</assembly>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/with-deps.xml
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/with-deps.xml b/service/src/main/assembly/with-deps.xml
new file mode 100644
index 0000000..be68d87
--- /dev/null
+++ b/service/src/main/assembly/with-deps.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+
+ <id>with-deps</id>
+ <formats>
+ <format>tar.gz</format>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>${project.build.finalName}-with-deps</baseDirectory>
+
+ <files>
+ <!-- with-deps -->
+ <file>
+ <source>${basedir}/src/main/assembly/LICENSE-with-deps.txt</source>
+ <destName>LICENSE.txt</destName>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/src/main/assembly/NOTICE-with-deps.txt</source>
+ <destName>NOTICE.txt</destName>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/../RELEASE-NOTES.txt</source>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ </files>
+
+ <dependencySets>
+ <dependencySet>
+ <useProjectArtifact>true</useProjectArtifact>
+ <outputDirectory>/lib</outputDirectory>
+ <includes>
+ <include>${project.groupId}:${project.artifactId}</include>
+ </includes>
+ </dependencySet>
+ </dependencySets>
+
+</assembly>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/assembly/without-deps.xml
----------------------------------------------------------------------
diff --git a/service/src/main/assembly/without-deps.xml b/service/src/main/assembly/without-deps.xml
new file mode 100644
index 0000000..5de0965
--- /dev/null
+++ b/service/src/main/assembly/without-deps.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0 Unless
+
+ required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS"
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ express or implied. See the License for the specific language
+ governing permissions and limitations under the License.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+
+ <id>without-deps</id>
+ <formats>
+ <format>tar.gz</format>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>true</includeBaseDirectory>
+ <baseDirectory>${project.build.finalName}-without-deps</baseDirectory>
+
+ <files>
+ <!-- without-deps -->
+ <file>
+ <source>${basedir}/src/main/assembly/LICENSE-without-deps.txt
+ </source>
+ <destName>LICENSE.txt</destName>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/src/main/assembly/NOTICE-without-deps.txt
+ </source>
+ <destName>NOTICE.txt</destName>
+ <outputDirectory>/</outputDirectory>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>${basedir}/../RELEASE-NOTES.txt</source>
+ <fileMode>666</fileMode>
+ </file>
+ <file>
+ <source>
+ ${project.build.directory}/${project.build.finalName}-without-deps.${project.packaging}
+ </source>
+ <outputDirectory>/lib</outputDirectory>
+ </file>
+ </files>
+
+</assembly>
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/bin/mudrodserver
----------------------------------------------------------------------
diff --git a/service/src/main/bin/mudrodserver b/service/src/main/bin/mudrodserver
new file mode 100644
index 0000000..00a3675
--- /dev/null
+++ b/service/src/main/bin/mudrodserver
@@ -0,0 +1,87 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ----------------------------------------------------------------------------
+
+BASEDIR=`dirname $0`/..
+BASEDIR=`(cd "$BASEDIR"; pwd)`
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ Darwin*) darwin=true
+ if [ -z "$JAVA_VERSION" ] ; then
+ JAVA_VERSION="CurrentJDK"
+ else
+ echo "Using Java version: $JAVA_VERSION"
+ fi
+ if [ -z "$JAVA_HOME" ] ; then
+ JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# If a specific java binary isn't specified search for the standard 'java' binary
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD=`which java`
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly."
+ echo " We cannot execute $JAVACMD"
+ exit 1
+fi
+
+if [ -z "$REPO" ]
+then
+ REPO="$BASEDIR"/lib
+fi
+
+EXTRA_JVM_ARGUMENTS="-Xms500m -Xmx500m -XX:PermSize=128m -XX:-UseGCOverheadLimit"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"`
+ [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"`
+ [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"`
+fi
+
+exec "$JAVACMD" $JAVA_OPTS \
+ $EXTRA_JVM_ARGUMENTS \
+ -jar "$REPO"/jetty-runner-${jetty.runner.version}.jar \
+ --path /${project.artifactId} "$REPO"/${project.build.finalName}.${project.packaging}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/bin/mudrodserver.bat
----------------------------------------------------------------------
diff --git a/service/src/main/bin/mudrodserver.bat b/service/src/main/bin/mudrodserver.bat
new file mode 100644
index 0000000..7bee368
--- /dev/null
+++ b/service/src/main/bin/mudrodserver.bat
@@ -0,0 +1,102 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed under the Apache License, Version 2.0 (the "License");
+@REM you may not use this file except in compliance with the License.
+@REM You may obtain a copy of the License at
+
+@REM http://www.apache.org/licenses/LICENSE-2.0
+
+@REM Unless required by applicable law or agreed to in writing, software
+@REM distributed under the License is distributed on an "AS IS" BASIS,
+@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@REM See the License for the specific language governing permissions and
+@REM limitations under the License.
+@REM ----------------------------------------------------------------------------
+@REM
+
+@echo off
+
+set ERROR_CODE=0
+
+:init
+@REM Decide how to startup depending on the version of windows
+
+@REM -- Win98ME
+if NOT "%OS%"=="Windows_NT" goto Win9xArg
+
+@REM set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" @setlocal
+
+@REM -- 4NT shell
+if "%eval[2+2]" == "4" goto 4NTArgs
+
+@REM -- Regular WinNT shell
+set CMD_LINE_ARGS=%*
+goto WinNTGetScriptDir
+
+@REM The 4NT Shell from jp software
+:4NTArgs
+set CMD_LINE_ARGS=%$
+goto WinNTGetScriptDir
+
+:Win9xArg
+@REM Slurp the command line arguments. This loop allows for an unlimited number
+@REM of arguments (up to the command line limit, anyway).
+set CMD_LINE_ARGS=
+:Win9xApp
+if %1a==a goto Win9xGetScriptDir
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto Win9xApp
+
+:Win9xGetScriptDir
+set SAVEDIR=%CD%
+%0\
+cd %0\..\..
+set BASEDIR=%CD%
+cd %SAVEDIR%
+set SAVE_DIR=
+goto repoSetup
+
+:WinNTGetScriptDir
+set BASEDIR=%~dp0\..
+
+:repoSetup
+
+
+if "%JAVACMD%"=="" set JAVACMD=java
+
+if "%REPO%"=="" set REPO=%BASEDIR%\lib
+
+set EXTRA_JVM_ARGUMENTS=-Xms500m -Xmx500m -XX:PermSize=128m -XX:-UseGCOverheadLimit
+goto endInit
+
+@REM Reaching here means variables are defined and arguments have been captured
+:endInit
+
+%JAVACMD% %JAVA_OPTS% %EXTRA_JVM_ARGUMENTS% -jar "%REPO%"/jetty-runner-${jetty.runner.version}.jar --path /${project.artifactId} "%REPO%"/${project.build.finalName}.${project.packaging}
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+if "%OS%"=="Windows_NT" @endlocal
+set ERROR_CODE=1
+
+:end
+@REM set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" goto endNT
+
+@REM For old DOS remove the set variables from ENV - we assume they were not set
+@REM before we started - at least we don't leave any baggage around
+set CMD_LINE_ARGS=
+goto postExec
+
+:endNT
+@endlocal
+
+:postExec
+
+if "%FORCE_EXIT_ON_ERROR%" == "on" (
+ if %ERROR_CODE% NEQ 0 exit %ERROR_CODE%
+)
+
+exit /B %ERROR_CODE%
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/DefaultExceptionMapper.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/DefaultExceptionMapper.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/DefaultExceptionMapper.java
new file mode 100644
index 0000000..a2d2731
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/DefaultExceptionMapper.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services;
+
+import com.google.gson.Gson;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import java.util.UUID;
+
+/**
+ * Created by greguska on 4/11/17.
+ */
+@Provider
+public class DefaultExceptionMapper implements ExceptionMapper<Throwable> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultExceptionMapper.class);
+
+ @Override
+ @Produces("text/html")
+ public Response toResponse(Throwable e) {
+
+ UUID errorId = UUID.randomUUID();
+ LOG.error("Internal server error " + errorId.toString(), e);
+
+ String errorString = "An error occurred while processing your request. Please contact the system administrator and provide the following error log ID " + errorId.toString();
+
+ return Response.serverError().entity(new Gson().toJson(errorString)).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/MudrodContextListener.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/MudrodContextListener.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/MudrodContextListener.java
new file mode 100644
index 0000000..84df5f6
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/MudrodContextListener.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services;
+
+import gov.nasa.jpl.mudrod.driver.ESDriver;
+import gov.nasa.jpl.mudrod.driver.SparkDriver;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+import gov.nasa.jpl.mudrod.ontology.OntologyFactory;
+import gov.nasa.jpl.mudrod.ssearch.Ranker;
+import gov.nasa.jpl.mudrod.ssearch.Searcher;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+import java.util.Properties;
+
+/**
+ * Application Lifecycle Listener implementation class MudrodContextListener
+ */
+@WebListener
+public class MudrodContextListener implements ServletContextListener {
+
+ MudrodEngine me = null;
+
+ /**
+ * Default constructor.
+ */
+ public MudrodContextListener() {
+ // default constructor
+ }
+
+ /**
+ * @see ServletContextListener#contextDestroyed(ServletContextEvent)
+ */
+ @Override
+ public void contextDestroyed(ServletContextEvent arg0) {
+ me.end();
+ }
+
+ /**
+ * @see ServletContextListener#contextInitialized(ServletContextEvent)
+ */
+ @Override
+ public void contextInitialized(ServletContextEvent arg0) {
+ me = new MudrodEngine();
+ Properties props = me.loadConfig();
+ me.setESDriver(new ESDriver(props));
+ me.setSparkDriver(new SparkDriver(props));
+
+ ServletContext ctx = arg0.getServletContext();
+ Searcher searcher = new Searcher(props, me.getESDriver(), null);
+ Ranker ranker = new Ranker(props, me.getESDriver(), me.getSparkDriver(), "SparkSVM");
+ Ontology ontImpl = new OntologyFactory(props).getOntology();
+ ctx.setAttribute("MudrodInstance", me);
+ ctx.setAttribute("MudrodSearcher", searcher);
+ ctx.setAttribute("MudrodRanker", ranker);
+ ctx.setAttribute("Ontology", ontImpl);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteData.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteData.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteData.java
new file mode 100644
index 0000000..206ce00
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteData.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.autocomplete;
+
+public class AutoCompleteData {
+ private final String label;
+ private final String value;
+
+ public AutoCompleteData(String label, String value) {
+ super();
+ this.label = label;
+ this.value = value;
+ }
+
+ public final String getLabel() {
+ return this.label;
+ }
+
+ public final String getValue() {
+ return this.value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteResource.java
new file mode 100644
index 0000000..84dbbb7
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/AutoCompleteResource.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.autocomplete;
+
+import com.google.gson.Gson;
+import gov.nasa.jpl.mudrod.main.MudrodConstants;
+import gov.nasa.jpl.mudrod.main.MudrodEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An AutoCompleteResource for term autocompletion suggestion.
+ */
+@Path("/autocomplete")
+public class AutoCompleteResource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AutoCompleteResource.class);
+ private MudrodEngine mEngine;
+
+ public AutoCompleteResource(@Context ServletContext sc) {
+ this.mEngine = (MudrodEngine) sc.getAttribute("MudrodInstance");
+ }
+
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD AutoCompleteResource: running correctly...</h1>").build();
+ }
+
+ @GET
+ @Path("/query")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response autoComplete(@QueryParam("term") String term) {
+ List<AutoCompleteData> result = new ArrayList<>();
+ List<String> suggestList = mEngine.getESDriver().autoComplete(mEngine.getConfig().getProperty(MudrodConstants.ES_INDEX_NAME), term);
+ for (final String item : suggestList) {
+ result.add(new AutoCompleteData(item, item));
+ }
+ String json = new Gson().toJson(result);
+ LOG.info("Response received: {}", json);
+ return Response.ok(json, MediaType.APPLICATION_JSON).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/package-info.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/package-info.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/package-info.java
new file mode 100644
index 0000000..24aa022
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/autocomplete/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Mudrod Autocompletion resources.
+ */
+package gov.nasa.jpl.mudrod.services.autocomplete;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java
new file mode 100644
index 0000000..e0ade84
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/OntologyResource.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package gov.nasa.jpl.mudrod.services.ontology;
+
+import com.google.gson.Gson;
+import gov.nasa.jpl.mudrod.ontology.Ontology;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A ontology-driven resource for user query augmentation.
+ */
+@Path("/ontology")
+public class OntologyResource {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OntologyResource.class);
+ private Ontology ontImpl;
+
+ public OntologyResource(@Context ServletContext sc) {
+ this.ontImpl = (Ontology) sc.getAttribute("Ontology");
+ }
+
+ @GET
+ @Path("/status")
+ @Produces("text/html")
+ public Response status() {
+ return Response.ok("<h1>This is MUDROD Ontology-driven User Query Augmentation Resource: running correctly...</h1>").build();
+ }
+
+ @GET
+ @Path("/synonym")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response getOntologySynonyms(@QueryParam("query") String query) {
+ List<String> result = new ArrayList<>();
+ if (query != null) {
+ Iterator<String> synonyms = ontImpl.synonyms(query);
+ while (synonyms.hasNext()) {
+ result.add((String) synonyms.next());
+ }
+ }
+ String json = new Gson().toJson(result);
+ LOG.info("Response received: {}", json);
+ return Response.ok(json, MediaType.APPLICATION_JSON).build();
+ }
+
+ @GET
+ @Path("/subclass")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes("text/plain")
+ public Response getOntologySubclasses(@QueryParam("query") String query) {
+ List<String> result = new ArrayList<>();
+ if (query != null) {
+ Iterator<String> subclasses = ontImpl.subclasses(query);
+ while (subclasses.hasNext()) {
+ result.add((String) subclasses.next());
+ }
+ }
+ String json = new Gson().toJson(result);
+ LOG.info("Response received: {}", json);
+ return Response.ok(json, MediaType.APPLICATION_JSON).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/package-info.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/package-info.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/package-info.java
new file mode 100644
index 0000000..55a68d6
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/ontology/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Mudrod ontology resources.
+ */
+package gov.nasa.jpl.mudrod.services.ontology;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sdap-mudrod/blob/7b76fa16/service/src/main/java/gov/nasa/jpl/mudrod/services/package-info.java
----------------------------------------------------------------------
diff --git a/service/src/main/java/gov/nasa/jpl/mudrod/services/package-info.java b/service/src/main/java/gov/nasa/jpl/mudrod/services/package-info.java
new file mode 100644
index 0000000..ef31bb1
--- /dev/null
+++ b/service/src/main/java/gov/nasa/jpl/mudrod/services/package-info.java
@@ -0,0 +1,17 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you
+ * may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This package includes base listeners, etc. for Mudrod services.
+ */
+package gov.nasa.jpl.mudrod.services;
\ No newline at end of file