diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a2da00f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* -text +*.woff binary +*.woff2 binary +*.ttf binary +*.eot binary +*.otf binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc18eaa --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +-* +node_modules +.idea +.DS_Store diff --git a/CNAME b/CNAME deleted file mode 100644 index 9130fc8..0000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -absolute-zero.optimade.science \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..51e9826 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 reatailret + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README b/README deleted file mode 100644 index 6e59993..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -Absolute Zero is the ultimate form of freezing and the point of cold at which the entropy hit its minimum level. Absolute Zero is also a secret character from a Mortal Kombat universe, related to Sub Zero. Finally, Absolute Zero is the mobile client for the MPDS materials science online database, to be rewritten in the $mol framework, as a part of the new HYOO contest. diff --git a/absolute-zero.jpg b/absolute-zero.jpg deleted file mode 100644 index 8c00150..0000000 Binary files a/absolute-zero.jpg and /dev/null differ diff --git a/index.html b/index.html deleted file mode 100644 index 3a549d0..0000000 --- a/index.html +++ /dev/null @@ -1,505 +0,0 @@ - - - - - - - - - - - - - -−273.15°C - - - - - - -
- -
- -
Unrecognized input
- -
- - - -
- -
- -
-
Login
-
or email an access link
-
- -
- -
-
Send link
-
or login with password
-
- -
-
- -
−273.15°C
-
-
- -
-
- -
−273.15°C
-
- -
Input
-
    - -
    Data summary
    -
      - -
      Results
      -
      - -
      New search
      -
      -
      - - - - - - diff --git a/jquery.min.js b/jquery.min.js deleted file mode 100644 index 7f37b5d..0000000 --- a/jquery.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===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]||I.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]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
      "],col:[2,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
      ",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({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)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0' + link_text + ''; - }); - $('a.extd_refine[rel=' + facet + ']').parent().hide().after(z(html)); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') wmgui.notify('Connection to server is lost, please try to reload'); - }); - return false; - }); - - $('#navicon').click(function(){ - if ($(this).hasClass('opened')){ - $(this).removeClass('opened'); - $('#hamburger').addClass('closed'); - $('#overlay, #menu_content').hide(); - } else { - $(this).addClass('opened'); - $('#hamburger').removeClass('closed'); - $('#overlay, #menu_content').show(); - } - }); - - $('#menu_content > ul > li > a').click(function(){ - $('#navicon').removeClass('opened'); - $('#hamburger').addClass('closed'); - $('#overlay, #menu_content').hide(); - return true; - }); - - $('#login_trigger').click(function(){ - if ($(this).data('busy')) return; - $(this).data('busy', true); - $.ajax({type: 'POST', url: wmgui.login_endpoint, data: {login: $('#login_email').val().trim(), pass: $('#login_password').val()}, beforeSend: show_preloader}).always(function(){ - $('#login_trigger').data('busy', false); - hide_preloader(); - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - if (!data.sid || !data.name || !data.acclogin) return wmgui.notify('Connection to server is lost, please try to reload'); - user_login(data.sid, data.name, data.acclogin, data.admin); - window.location.hash = '#start'; - $('#navicon').trigger('click'); - $('#loginbox, #restorebox').hide(); - - }).fail(function(xhr, textStatus, errorThrown){ - wmgui.notify("Login unsuccessful"); - }); - }); - - $('#restore_trigger').click(function(){ - if ($(this).data('busy')) return; - $(this).data('busy', true); - $.ajax({type: 'POST', url: wmgui.restore_endpoint, data: {login: $('#restore_by_email').val().trim()}, beforeSend: show_preloader}).always(function(){ - $('#restore_trigger').data('busy', false); - hide_preloader(); - - }).done(function(data){ - if (data.error) return wmgui.notify(data.error); - wmgui.notify('Please, check your inbox (and spam)'); - $('#navicon').trigger('click'); - $('#loginbox, #restorebox').hide(); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') wmgui.notify('A network error occured. Please, try again'); - }); - }); - - $('div.cross').click(function(){ - window.location.hash = '#start'; - }); - - $('#logout_item').click(function(){ - $.ajax({type: 'POST', url: wmgui.logout_endpoint, data: {sid: wmgui.sid}}).done(function(data){}).fail(function(xhr, textStatus, errorThrown){}); - user_logout(); - }); - - $(document).keydown(function(e){ - var key = window.event ? e.keyCode : e.which; - if (key == 13) $('#search_trigger').trigger('click'); - }); - - $(window).bind('hashchange', url_redraw_react); -} diff --git a/mgui.js b/mgui.js deleted file mode 100644 index e95a7a9..0000000 --- a/mgui.js +++ /dev/null @@ -1,327 +0,0 @@ -/** - * Mobile GUI for the chemistry DB - * Version: 0.5.5ce - */ -"use strict"; - -wmgui.notify = function(msg){ - console.log(msg); - alert(msg); - close_vibox(); -} - -function switch_viewmode(mode){ - - wmgui.viewmode = mode; - - if (mode == 2){ - $('#branding').hide(); - $('#content').show(); - window.scrollTo(0, 0); - - $('#summary, #results, #summary_caption, #results_caption').hide(); - - } else { - $('#content').hide(); - $('#branding').show(); - $('#search_field-selectized').focus(); - } -} - -function request_analysis(query_obj){ - var given_search = {}; - $.extend(given_search, query_obj); - try { wmgui.active_ajax.abort() } catch(e){} - wmgui.active_ajax = $.ajax({type: 'GET', url: wmgui.rfn_endpoint, data: {q: JSON.stringify(given_search)}, beforeSend: show_preloader}).always(hide_preloader).done(function(data){ - if (data.error) return wmgui.notify(data.error); - - var was_facet = null, - refine_html = '', - classes_chk = [], - max_count = 0; - - if (query_obj.classes){ // no whitespace in multiple classes - classes_chk = given_search.classes.split(',').map(function(i){ return i.trim() }); - given_search.classes = classes_chk.join(','); - } - - $.each(data.payload, function(i, found_obj){ - if (query_obj.formulae && found_obj.facet == 'elements') return true; // NB no sense to show elements in this context - - var link_text = found_obj.value, - nested_skip = false, - orepr = {}; - - if (found_obj.count > max_count) max_count = found_obj.count; - - $.each(given_search, function(key, val){ // compile individual search link - if (found_obj.facet == 'elements' && (key == 'elements' || key == 'formulae')) return true; - else if (found_obj.facet == 'props' && key == 'props') return true; - else if (orepr[key] && key == 'classes') val += ', ' + orepr[key]; - orepr[key] = val; - }); - - if (query_obj.classes && found_obj.facet == 'classes'){ - $.each(classes_chk, function(n, cls){ - if (cls == found_obj.value){ nested_skip = true; return false; } - }); - } - if (nested_skip) return true; - - if (found_obj.facet != was_facet){ - if (was_facet) refine_html += '
    • Show more
    • '; - refine_html += '
    • ' + wmgui.facet_names[found_obj.facet] + '
    • '; - was_facet = found_obj.facet; - } - if (found_obj.facet == 'props'){ - found_obj.value = found_obj.value.replace(/\(|\)/g, "").replace(/\/[\w\-]*/g, ""); // FIXME! - } - - // FIXME!!! lost classes in refinement: see #inquiry/classes=alkaline&years=2010-2018 - orepr[found_obj.facet] = found_obj.value; - if (orepr['elements']) orepr['elements'] = orepr['elements'].replaceAll(', ', '-'); - - refine_html += '
    • ' + link_text + '
    • '; - }); - - if (refine_html.length){ - refine_html += '
    • Show more
    • '; - if (max_count > 50){ - $('#summary > ul').empty().append(z(refine_html)).parent().show(); - $('#summary_caption').show(); - } - } - - request_data(query_obj); - - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') wmgui.notify('Connection to server is lost, please try to reload'); - }); -} - -function request_data(query_obj){ - wmgui.active_ajax = $.ajax({type: 'GET', url: wmgui.srch_endpoint, data: {q: JSON.stringify(query_obj)}, beforeSend: show_preloader}).always(hide_preloader).done(function(data){ - if (data.error) - return wmgui.notify(data.error); - if (!data.out.length) - return wmgui.notify('Nothing found!'); - if (data.notice) - wmgui.notify(data.notice); - if (data.fuzzy_notice) - wmgui.notify(data.fuzzy_notice); - - var cls_map = {7: ' ml_data', 8: ' ab_data', 9: ' ab_data', 10: ' ab_data'}, // NB space - result_cells = ''; - - data.out.sort(function(a, b){ - var x = a[2].toLowerCase(), - y = b[2].toLowerCase(); - return x < y ? -1 : x > y ? 1 : 0; - }); - - $.each(data.out, function(k, row){ - row[7] = parseInt(row[7]); - var dtype = row[0].substr(0, 1), - content, - dlinks = 'Log in to access', - biblio_html = (row[7] == 999999) ? '' : - '
      [' + row[5] + '’' + row[6].toString().substr(2, 2) + ']'; // special *ref_id*, only handled in GUI - - if (wmgui.sid && biblio_html) dlinks = 'Ref.PDF'; - - if (dtype == 'P'){ - content = '
      ' + row[2] + '
      '; - - } else if (dtype == 'C'){ - content = '' + row[0] + ''; // NB handled remotely - if (wmgui.sid) dlinks = 'PNG'; - - } else { - content = '' + row[0] + ''; // NB handled remotely - dlinks = 'PNGanim'; - } - - result_cells += ''; - }); - - if (result_cells.length){ - $('#results').empty().append(result_cells).show(); - $('#results_caption').show(); - } - }).fail(function(xhr, textStatus, errorThrown){ - if (textStatus != 'abort') wmgui.notify('Connection to server is lost, please try to reload'); - }); -} - -function close_vibox(){ - var iframe = $('#iframe'); - if (iframe.length){ - $('#iframe').remove(); - $('#overlay').hide(); - $('#hamburger').show(); - return true; - } - return false; -} - -function rotate_example(){ - var example = WMCORE.generate_example(); - $('#legend').html('e.g. ' + example['text'].replace(/\d/g, "Ȉ$&;") + ''); -} - -function rotate_motto(){ - $('#motto > span').animate({ opacity: 'hide' }, 2500, function(){ - $('#motto > span').html(wmgui.mob_motto[ Math.floor(Math.random() * wmgui.mob_motto.length) ]).animate({ opacity: 'show' }, 1500, function(){ - setTimeout(rotate_motto, 2500); - }); - }); -} - -function user_login(sid, name, acclogin, admin){ - $('#user_status > span').text(name); - $('#login_item').hide(); - $('#logout_item').show(); - wmgui.sid = sid; - window.localStorage.setItem('wm', JSON.stringify({sid: sid, name: name, acclogin: acclogin, admin: admin})); -} - -function user_logout(){ - $('#user_status > span').text('Hi, guest'); - $('#logout_item').hide(); - $('#login_item').show(); - wmgui.sid = null; - window.localStorage.removeItem('wm'); -} - -function satisfy_requirements(){ - - var locals = JSON.parse(window.localStorage.getItem('wm') || '{}'); - if (locals.sid && locals.name && locals.acclogin){ - user_login(locals.sid, locals.name, locals.acclogin, locals.admin); - } - - WMCORE = WMCORE(); - - rotate_example(); - setInterval(rotate_example, 2250); - $('#motto > span').html(wmgui.mob_motto[ Math.floor(Math.random() * wmgui.mob_motto.length) ]); - setTimeout(rotate_motto, 2500); - - var control = $('#search_field').selectize({ - plugins: ['remove_button', 'preserve_on_blur'], - dropdownParent: '#suggestions', - valueField: 'id', - labelField: 'label', - searchField: 'label', - create: false, - maxItems: 5, - closeAfterSelect: true, - diacritics: false, - options: [], - onInitialize: function(){ - $('#searchbox > div.selectize-control').append(''); - $('#search_field-selectized').focus(); - }, - load: function(query, callback){ - this.clearOptions(); - $('#selectize_msg').hide(); - if (!query.length) return callback(); - $.ajax({ - url: wmgui.api_host + '/search/selectize?q=' + encodeURIComponent(query), - type: 'GET', - error: callback, - success: function(res){ - //console.log(res.length); - $('#suggestions').show(); - if (!res.length){ - $('#selectize_msg').show(); - $('#search_trigger').hide(); - return; - } - callback(res); - } - }); - }, - score: function(){ return function(){ return 1 } }, // no client scoring - onFocus: function(){ - if ($.isEmptyObject(this.renderCache)) return; - $('#suggestions').show(); - }, - onBlur: function(){ - $('#suggestions').hide(); - }, - render: { - option: function(item, escape){ - return '
      ' + item.label + '
      '; - }, - item: function(item, escape){ - return '
      ' + item.label + '
      '; - } - }, - onItemAdd: function(value, item){ - $('#search_trigger').show(); - }, - onItemRemove: function(value){ - if ($.isEmptyObject(wmgui.selectize.read())) $('#search_trigger').hide(); - } - }); - wmgui.selectize = control[0].selectize; - - wmgui.selectize.read = function(){ - var result = {}; - $('div.selectize-input.items').children().each(function(){ - if (this.tagName == 'DIV'){ - var facet = this.getAttribute('data-facet'); - - if (result[facet] && facet == 'elements') - result[facet] += '-' + this.getAttribute('data-term'); - else if (result[facet] && (facet == 'classes' || facet == 'aetypes')) - result[facet] += ', ' + this.getAttribute('data-term'); - else if (facet == 'formulae') - result[facet] = this.getAttribute('data-term').replaceAll('', '').replaceAll('', ''); - else - result[facet] = this.getAttribute('data-term'); - } - }); - return result; - } - - wmgui.selectize.write = function(search_obj){ - var given_search = {}; - $.extend(given_search, search_obj); - - ['formulae', 'props', 'elements', 'classes', 'lattices', 'aetypes'].forEach(function(facet){ - if (!given_search[facet]) - return; - - else if (facet == 'elements' && given_search[facet].indexOf('-') > 0){ - given_search[facet].split('-').forEach(function(part){ - wmgui.selectize.display(facet, part); - }); - } else if ((facet == 'classes' || facet == 'aetypes') && given_search[facet].indexOf(',') > 0){ - given_search[facet].split(',').forEach(function(part){ - wmgui.selectize.display(facet, part); - }); - } else if (facet == 'formulae'){ - given_search[facet] = WMCORE.to_formula(given_search[facet]); - wmgui.selectize.display(facet, given_search[facet]); - - } else wmgui.selectize.display(facet, given_search[facet]); - }); - wmgui.selectize.clearOptions(); - } - - wmgui.selectize.display = function(facet, term){ - var random_id = Math.floor((Math.random() * 1000)); - wmgui.selectize.addOption({facet: facet, label: term, id: random_id}); - wmgui.selectize.addItem(random_id); - } - - window.location.hash ? url_redraw_react() : window.location.replace('#start'); -} - -// now, fire in the holl! - -satisfy_requirements(); - -register_events(); diff --git a/mrouter.js b/mrouter.js deleted file mode 100644 index d38eeef..0000000 --- a/mrouter.js +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Mobile GUI for the chemistry DB - * Version: 0.5.5ce - */ -"use strict"; - -function url_redraw_react(){ - var anchors = window.location.hash.substr(1).split('/'); - - if (!anchors.length) return; - $('#loginbox, #restorebox').hide(); - try { wmgui.active_ajax.abort() } catch(e){} - - if (window['url__' + anchors[0]]) window['url__' + anchors[0]](anchors.slice(1).join('/')); - else window.location.hash = '#start'; -} - -function url__start(arg){ - switch_viewmode(1); -} - -function url__search(arg){ - window.location.replace('#start'); -} - -function url__phase_id(arg){ - switch_viewmode(2); - var phid = parseInt(arg); - $('#input > ul').empty().append('
    • Distinct phase
      #' + phid + '
    • '); - request_data({'phid': phid}); -} - -function url__inquiry(arg){ - var inquiry = arg.split("&").map( function(n){ return n = n.split("="), this[n[0]] = n[1], this }.bind({}) )[0]; - - wmgui.facets.forEach(function(item){ - if (inquiry[item]) inquiry[item] = unescape(inquiry[item].replaceAll('\\+', ' ')); - }); - - wmgui.search = inquiry; - - switch_viewmode(2); - - $('#input > ul').empty().append( - z(WMCORE.get_interpretation(inquiry, wmgui.facet_names)) - ); - - $('#search_field-selectized').val(''); - wmgui.selectize.clear(); - wmgui.selectize.write(inquiry); - - request_analysis(inquiry); -} - -function url__modal(arg){ - if (arg == "login"){ - if (wmgui.sid){ - $('#navicon').trigger('click'); - - } else { - if ($("#restore_by_email").val()) $("#login_email").val($("#restore_by_email").val()); - else $("#login_email").val(''); - $("#login_password").val(''); - $('#restorebox').hide(); - $('#loginbox').show(); - } - - // for OAuth linking redirect only - var u_email = window.localStorage.getItem('wm_u_email') || false; - if (u_email){ - $("#login_email").val(u_email); - window.localStorage.removeItem('wm_u_email'); - } - - } else if (arg == "restore"){ - if (wmgui.sid){ - $('#navicon').trigger('click'); - - } else { - if ($("#login_email").val()) $("#restore_by_email").val($("#login_email").val()); - else $("#restore_by_email").val(''); - $('#loginbox').hide(); - $('#restorebox').show(); - } - } -} - -function url__access(arg){ - $.ajax({type: 'POST', url: wmgui.access_endpoint, data: {a: arg}}).done(function(data){ - window.location.replace('#start'); - if (data.error){ - return wmgui.notify(data.error); - } - if (!data.sid || !data.name || !data.acclogin){ - return wmgui.notify('Connection to server is lost, please try to reload'); - } - user_login(data.sid, data.name, data.acclogin, data.admin); - $('#navicon').trigger('click'); - $('#loginbox, #restorebox').hide(); - - }).fail(function(xhr, textStatus, errorThrown){ - return wmgui.notify('A network error occured. Please, try again'); - }); -} - -function url__entry(arg){ - switch_viewmode(2); - $('#input > ul').empty().append('
    • Entry
      ' + arg + '
    • '); - request_data({'entry': arg}); -} - -function url__junction(arg){ - wmgui.notify('Please retry to log in'); - window.location.replace('#start'); -} diff --git a/optimade/zero/api.ts b/optimade/zero/api.ts new file mode 100644 index 0000000..fabaa5d --- /dev/null +++ b/optimade/zero/api.ts @@ -0,0 +1,284 @@ +namespace $ +{ + + + + export class $optimade_zero_api extends $mol_object2 + { + + + query_params = { + + props: 'Physical properties', + elements: 'Chemical elements', + classes: 'Materials classes', + lattices: 'Crystal systems', + formulae: 'Chemical formulae', + protos: 'Prototypes', + sgs: 'Space groups', + numeric: 'Numerical search', // NB not a real facet! + authors: 'Authors', + years: 'Years', + codens: 'Journal codes', + doi: 'DOI', + aeatoms: 'Polyhedron atoms', + aetypes: 'Polyhedral types', + geos: 'Geography', + orgs: 'Organization' + } as Record + @$mol_mem + NLP() + { + //@ts-ignore + const cl = require( 'optimade-mpds-nlp' ) as typeof import( 'optimade-mpds-nlp' ) + return new cl() + } + @$mol_mem_key + string_to_facets( search: string ) + { + + return this.NLP().guess( search ) + } + @$mol_mem_key + facet_array_to_dict( val: $optimade_zero_api_Facet[] ) + { + + const result = {} as Record + const result2 = {} as Record + for( const facet of val ) + { + if( !result[ facet.facet ] ) result[ facet.facet ] = [] + result[ facet.facet ].push( facet.label ) + } + for( const key in result ) + { + if( result[ key! ] && result[ key! ].length ) + { + result2[ key ] = result[ key! ].join( ',' ) + } + } + return result2 + } + @$mol_mem_key + facet_dict_to_array( val: Record ) + { + const res = [] as $optimade_zero_api_Facet[] + + Object.keys( val ).map( ( el ) => + { + if( val[ el ] ) + { + const ar = val[ el ].split( ',' ) + for( const element of ar ) + { + res.push( { facet: el, label: element.trim() } ) + } + + } + } ) + return res + } + + + uri_to_facets() + { + const res = [] as $optimade_zero_api_Facet[] + const dict =$mol_state_arg.dict() + + Object.keys( this.query_params ).map( ( el ) => + { + if( dict[ el ] ) + { + const ar = dict[ el ].split( ',' ) + for( const element of ar ) + { + res.push( { facet: el, label: element.replaceAll( '-', ', ' ), id: '' } ) + } + + } + } ) + return res + } + @$mol_action + selectize( search?: string ): $optimade_zero_api_Facet[] + { + + if( search ) + { + return $mol_fetch.json( this.selectize_endpoint() + '?' + new URLSearchParams( { + q: search + } ).toString() ) as unknown as $optimade_zero_api_Facet[] + } + return [] + + } + + facet_dict_to_query(dict:object){ + return new URLSearchParams( { q: JSON.stringify( dict ) } ).toString() + } + @$mol_action + refinement( search?: Record | null ): $optimade_zero_api_FacetSuggestResponse + { + + if( search && Object.keys( search ).length ) + { + return $mol_fetch.json( this.rfn_endpoint() + '?' + this.facet_dict_to_query(search)) as unknown as $optimade_zero_api_FacetSuggestResponse + } + return { + error: '', + payload: [], + total_count: 0, + use_visavis_type: '' + } + + } + + @$mol_action + results( search?: Record | null ): $optimade_zero_api_SearchResponse + { + + if( search && Object.keys( search ).length ) + { + const response = $mol_fetch.json( this.srch_endpoint() + '?' + this.facet_dict_to_query(search) ) as unknown as $optimade_zero_api_SearchResponse + if( response.out ) + { + response.out = this.transform_results( response.out ) + } + return response + } + return { + error: '', + fuzzy_notice: '', + out: [], + estimated_count: 0 + } + + } + transform_results( results: $optimade_zero_api_SearchResponse[ 'out' ] ) + { + let out = results.sort( ( a, b ) => + { + var x = a[ 2 ].toLowerCase(), + y = b[ 2 ].toLowerCase() + return x < y ? -1 : x > y ? 1 : 0 + } ) + return out + + } + @$mol_mem + user_sid(next?: string):string + { + if(next !== undefined) { + $mol_state_session.value('sid', next) + } + return $mol_state_session.value('sid')??'' + } + @$mol_action + login( login: string, pass: string ) + { + + + const resp = $mol_fetch.text( this.login_endpoint(), { + method: 'POST', + body: new URLSearchParams( { login, pass } ) + + } ) as string + const data = JSON.parse(resp) + if(data.sid) { + this.user_sid(data.sid) + } + return resp + + + } + + @$mol_action + logout() { + this.user_sid('') + } + + cdn_host() + { + return 'https://mpds.io' + } + api_host() + { + return 'https://api.mpds.io/v0' + } + + login_endpoint() + { + return this.api_host() + '/users/login' + } + logout_endpoint() + { + return this.api_host() + '/users/logout' + } + restore_endpoint() + { + return this.api_host() + '/users/lost_password' + } + access_endpoint() + { + return this.api_host() + '/users/access' + } + srch_endpoint() + { + return this.api_host() + '/search/facet' + } + selectize_endpoint() + { + return this.api_host() + '/search/selectize' + } + rfn_endpoint() + { + return this.api_host() + '/search/refinement' + } + phph_endpoint() + { + return this.api_host() + '/search/phase_phid' + } + refs_endpoint() + { + return this.api_host() + '/download/bib' + } + dd_addr_tpl() + { + return this.api_host() + '/download' + } + + + } + + export type $optimade_zero_api_Facet = { + facet: string + label: string + id?: string + } + + export type $optimade_zero_api_FacetSuggestResponse = { + error: null | string + payload: { + facet: string + value: string + count: number + }[] + total_count: number + use_visavis_type: string + } + export type $optimade_zero_api_SearchResponse = { + error: null | string + fuzzy_notice: null | string + out: [ + id: string, + formula: string, + structure: string, + count: number, + unknown: boolean, + code: string, + year: number, + entry_id: number + ][] + estimated_count: number + } +} diff --git a/optimade/zero/app/app.meta.tree b/optimade/zero/app/app.meta.tree new file mode 100644 index 0000000..5672050 --- /dev/null +++ b/optimade/zero/app/app.meta.tree @@ -0,0 +1,3 @@ +deploy \/optimade/zero/app/assets +deploy \manifest.webmanifest +include \/mol/offline/install diff --git a/optimade/zero/app/app.view.css b/optimade/zero/app/app.view.css new file mode 100644 index 0000000..2fd653f --- /dev/null +++ b/optimade/zero/app/app.view.css @@ -0,0 +1,4 @@ +@font-face { + font-family: Exo2; + src: local('Exo 2 Regular'), local('Exo2-Regular'), url('data:font/woff;charset=utf-8;base64,d09GRgABAAAAAFIsAA8AAAAAncgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHREVGAAA7KAAAAF8AAAB8CowLI0dQT1MAADuIAAAVSgAAPpqssOM5R1NVQgAAUNQAAAFWAAACiiFJGmRPUy8yAAAB1AAAAE4AAABgX0f9PWNtYXAAAATcAAAArgAAAPQU4xbuZ2FzcAAAOyAAAAAIAAAACAAAABBnbHlmAAAHrAAALiEAAEmE1c5EOmhlYWQAAAFYAAAANgAAADYT81sIaGhlYQAAAZAAAAAhAAAAJAe+BChobXR4AAACJAAAArYAAAQsC381BGxvY2EAAAWUAAACGAAAAhiSP6NmbWF4cAAAAbQAAAAdAAAAIAEaALJuYW1lAAA10AAAArgAAAV56ruaBXBvc3QAADiIAAACmAAABAIpEjhYcHJlcAAABYwAAAAHAAAAB2gGjIUAAQAAAAIAQkYY3d5fDzz1AAsD6AAAAADNoAwSAAAAAOMfCx//Uv8JBMIDpwAAAAgAAgAAAAAAAHjaY2BkYGBe/p+TgYHl8/+g/woshxiAIsiAkRsAko4F7gAAAHjaY2BkYGDkZkhhYGfwYWBhAPKQADMDIwASjADOAAAAeNpjYGEyYZzAwMrAwNTFFMHAwOANoRnjGIwYVRiQQAMDgzpIHsb38/dzZTjAwKskyrz8PycDA/Nyhu9AYUaQHONzpk1ASoGBGQD61AvXAAB42nVTS0iUYRQ9934qVAQ5C1M0lTIfaTq+5qUzOurY+Bp1yAwsRVoIai8SAslyH0QuIqtJDKNFVJsiKFpkBO0CN4FB2EKholZWZFTT+X8pTOyHM+f757/3ft895356Av3gI238WViFJKNX+tGod1GkFfCasygxCajHHBplAC4iW57BpXnwYBEhmUUYS2jQRKRrD2rlAlK0DG4tQoUOIEdTydWoUyBP+xDi2o2PCOETmtSBSm1CM3mfrCBfX6JFj2GzDqNbffDrJNmJTk1Hl44goDF0SxKxH5nazm+KLnOUdWa5jjE+Qr7OuEFyKc8QQqpeRVT7kWweIEuPIE292KIuOKUJPZqEdHKB3EamPGTvVTzvbpRz71Z5zx798Ggaez6DDC1GAetF8I34zryfiEgB2s0wItb/6uF+DWQf3DLBbz9QJmPUxMeeHHAYD/fehu2aDIf8QqnUoBhfcUhq2fdWamhpDxxgnotn9GiUmg0ih/sd1mwE5Bo6TAOq5BE1XqI3ETTLU4S1gOe7CL8MUedWtMgUvHIZHvGhVIM8TyfyqXcYH7BTctnnE9ZYQqXpQ645TTxm7Gf2Zum+AcxEPG57YfmwBpIUX6AX1eS35ATqnvLXh3WQRRTba8uLtbC86GDODPW1dN8AZgDlthdp/wIr8Xms2Pya+KUltt+rPqxHFbW02PJiLeiFBphDZq2omYDfnOd8WnN9E0684VwWoVBm4OScAsvENHEK9qMHqf8mogNhM07mO+YRxCsE7BonEZTj9G6M6y/Ya2MIPaYNwYRllNh3indNdiBHslCI6XhULnF+bmGXjKJSrqBGRphzD/UyyR7O0bfnqLfvTCL17qVuMeIFMswN4h0y7HzL5z9z8J9anCc3e8tkn16JMe4O48YZN8W4UcbdZ9wU6ixdsCc+9xtsx78HAAB42mNgYGBiYGBgBmIRIMkIplkYHgBpEwYFIEuEgZehjuE/oyFjMNNupmNMt5juKHArCCiIKkgpyCkoKagpGCgYK1gpuCiUKKxRVFISUhL9/x+omxeoewFQVxBcFztQl5CChIKMggJYl5GCJaqu/9/+P/l/+P+k/0X/uP8x/n3/992DIw8OPNj/YO+DPQ92P9jxYP2DdQ9WPljwoOiBw/3T9+7cuwV2L8kAACJTQMwAALgB/4WwBI0AAAAAIQAhACEAIQAhAEUAWQB+ANcBPQGfAawByQHlAgsCIAI/AkwCZgJ2AqwCwgL6A0QDaQOjA+8ECwRvBLoExgTSBOUE+QUMBU4FqQXVBiUGVwaPBsAG4wcjBz8HTAdmB5gHsgfqCCAIVgiPCNMJFwlgCXQJmQm/ChMKOApdCnkKlgqlCsEK1ArgCu4LNAt2C6kL6QwjDEgMvQzmDQENJg1XDXINtA3ZDgsOSg6KDqkO7w8RDzYPXA+wD9AQAxAfEFYQYxCaEMMQwxDnES8RbhG+EfESBRJvEpES9BM2E0ITVRNdE8QT0RQAFBwUUBSSFKAU4RUMFRUVNBVKFXEVjhXIFhQWexa8FsgW1BbgFuwW+BcEF0wXWBdkF3AXfBeIF5QXoBesF7gX9xgDGA8YGxgnGDMYPxhYGJcYoxivGLsYxxjTGQwZchl9GYkZlBmfGaoZtRorGjcaQhpOGlkaZBpvGnoahRqQGtca4hrtGvkbBBsPGxobTxuKG5UboRusG7cbwxwFHBAcHRx/HOUdBx0aHS4dWh2CHYIdgh2CHYIdgh2KHZcdpB2xHbkd2R35HhgeUB6JHsEfDh+XH7EfwSBTIFsgYyB1IIcglyDGIOchHiFjIX0hzSIRIlIilyKkIrQi6yMiI10jqyP5JAEkCSQRJBkkISQpJDEkOSRBJEkkUiRbJGQkbSR2JH8kiCSRJJokoySuJMJ42rV8CXgb1bXw3DuSRrssyVqsXRrt1mKtI1uyZMuy5d3O4sRZ7ATiGEIoEEoJAUoCZSktpdC+LqEta/va0hZKwtJX9m4h0D5aeN0L3V5LgQLtC320BY/+c2dk2VmA9/7v//NZI82ZmXvPPffs50woCXUaRWEdPkTRFEOpKB1FGfWs3ks+XpNXD58PRdBdEf4SdBe/lnzwoaVJ8RNZujUCD1PzFEXdix+gpJSJPM2wIb0xbTaZ2mUs6wvmctl85rC8psjrdTq9Wa/V6vED/L8fOoTSS49qDXmDVjjAOEPol8jexIRCMAwLH2SX9shGZUUpPvRT+EdREioGkx5YjTGiWaMXPhbGy0nhg7iLahehChw+plr6rQr9jRxX8H6Q417mOAqe725cjhHtprqoLFWAccxmCxMMsj4tNrWbLRaz2dSuxbCGEGc2pzPpfD6XDQZDoWAwly1jowWmpENG1JE6MyvrPLMrkPPpookPT5fshdle33vqsuJw1pHr7TAE3dePle3cTCDuT+zzJnz4ESRX9WFaauwMdsdVrHHbdGk0pJNpBhDdlkiEYxbGb5yfKo0E1PwdmPfRN/N9GD1CAYWTjTfoSfworNpNsVSGGgCKpwmeMhngCXjl8xafTAbom5fxDSAWvds9T5fqLle9VCTHoj9iMET8gYheH0FH+P4SejRZGnK5hsTLPf5oW1sULsNN+NHI5tGRzdHo5pHRzZG8s1ooVJ3iMUIozT8f3TQysiUS2TIysimad8CVAadzAK47YL8HGv+Nf4wfEleB0kD7BPaxy5h5Ge/yz3yeswj7QHDnciL5pfp2cyYjwnN6Dm31rI0rlf5YzFAZ9XQU0+haxF+Q73dYu1OjZ4a1nuFNxeFNkeJ4JevqOx1FXb5RpS4c1JTKCvwQzfQjhPTpbDLTPmDtySXzZhRL5KNpEzs9NLWNkcjWjJaGWfV9/KWsqyyR0aU8Qp8DpAnPUtcJvEgZgVuvazIqXMk3tqBh2kxp4TaLuBDCXLAC1Kta2BJeP6D64P79tDmS+vmd5351LxvJvfD4t/5ExvTAk2nxSaOwbUyojGGXQtFr9++/VjmwLrx5gTZn//Stx1/IRdi9Xz33zp+nCDfn0XvRR/BhSk5pKAPBx8KEmBAXgm8mFICT3JvyhcjERHSBObAXqS5FQ/r3q/Hh2y53XXKx68BtmxNmrTeV9mjNsDcFajN6Fb3ZlEWTN8fRLI1e5UffQn0IjfX1fZ3fhm4j2A42LqVupi4kM3Ki1AO+wFW+XC6fz+w3aBQ6VVgqtaK2tgu1hj5HPmVRu7MBRw/IPKKGqV+hfchJ6EdmQfv4p5Gzvx+u1ECr3Arj6lrjtrTJAaIzHESdXLhKgcAz9sYj6CVxNxBwPXqJ3zuErgWpV+PXiabqaxzDdkF6WIHjTpAJIvYunEkTaicwim86Mx4/c9MsOc529rA6HdvT2Vkk30X86OjNl11286h4nHBXd0+Mn111u6tnj0/srroBFzPM4AJcFPAN2hQYF/YCuWYx/WX11wVFxOpculx/He4FZYTewo+sxophgHoZIAk8yOXzoQQmkkE4Aemq2zKWfOJ7tqL9Jb4oY56oAtDdHfb09HfKkvVe/Ii5r9I5vibzHMYznMoo/139nJTPrcQMU1OpJDBftnEMvQx0SK+azwT8aRaoEeIIEUTFwLI5gR7C9GRfER6fixk6w7UMQtHta7lzczJfpewpDLhNxe4DByIpK4NsvbnUFpbJbMOPOod6YyMpuUS1pT60JaZi6rQUd5TSwW7PoJmNW2OdOildUyhgb/ywQUWgl8C7iJaBBjCBCggGOaMF6Meh0ccVej06uJX/mCOoUn3ntXVgtfgz200VhSfdgW6+cukZ9ND5lLC619FvYCRCTcbLWFz0KjVOFsblE5hocc6Ivi/hn1eO1raV7PrkbD1ydkGZnPdVq1aEOrgt1YTOiNrwobGHZFJbeqIQnSwH1Jq6XOmtxLs4u0pCY1MbCpM5q43XsRR2MNfUZMGgj23xU5OUzf3LpJftSgITRYYmTeNRuTkQdWWGoga5s5gpdutNhYy30BOUeEv1rpG1vrbEhqGRrSmjt7oTPyIB24HN5YtOH1ss2gLDme6auy0SiCVzptiO9bmNZa938gOnX/wvE3bAKwT4/BZooRZ3mgGTBev3htDXTFZG9tPZb0mVMv5LEnxIZzcufRhntR3qMaJLBkE320A3s7CiQfKsC4tcIn4vywyXE9dgFE1m054kMH2CfUFd1ZmUsb2TjaXagzu3zS2GTWk4aW9PzdSSJZ+mY6C3t8+q8fQkuksWS293T7HdVMIPmWODyXgtIpFIklP5yppgcE0lP5WE00gtnhyMmflr1M5sOMFZLFwiknWqYInZeDJjbM8k4lkigBQHvPAG7Et2eQ2r7bko5+wqXFfZmTxqH9uS0Lkqi8OWqaTcGoz7srA/jK0n2w3YFVJeDvbH0zvUVV/ri5yGH2Gnr1644IYJh0TVj7G1cv7mqV1lW3A4mx706yP+TtiensX+qV25RoNQlLoNfaMtBLyOULVNRhkQBfAR0KVfaMKlArxNSlaRo+bQU+iflIxoSanUFMihp/h70Th/Fvpn7bpra1+pEe02Sn0GU+iuFZ0thQ+m+FF0P3zuqlSe7esjo9VhtOfE0YxSkzQXCNTRJ2GocRjyn3fBYNdeB6MRtv53/ATlIP4WEBZIRzNssExz+WVWpk9085Bk505/LhfEI8iTSvsQrgymKhmf1BZN9IaJ52cR3L8nxqbj/fnukSw3XcpkvekuLKV7pYyMXrprtT7H1Fjju/hqPAK71y/ioGdDzQ0i02WAtdimmNGgLoAvZQka+JHmLAxsKuyqsKnoteGpPrmhPBENFb093U/70wf6J8MahS29rhfhvgP9688b9KmV7t6FsZ8cYp0+j7OvZMEj/RP80TFDyGbPhTJdXGfYp07s3DSyLW+V9UkkSBMYft+G9ecPBTToLxJkd9r8rjaniWCthMMCyJyRsojawMjS4DayQDNB/DJGYul2qg3081sOSxQSh0QuPbzledqg/hV/Oz6kUS0t4rzWqdE4tUtP4ptUGv788XEYd2Pj7ziNvwlaO9/S20RtLwvksnoTnFTQ24LTAHvlE9QOA0oUcTMLca480Rs7bao4MxzSmi9Zy1Xsjmr388+lizZHfyE1WWzXspWxjRvwN92T9dFJmYSZX1efdCMJPYSwMZvK91jRADJmEsm0AeEhCY3kxNUDvuoFHWgGWXOL2BF3bpVscZYVtYHGY5WcQ+HK9IQHJkFdDfRtjCo6t9R27M3l9oKCUzADtARnL9616+KsVFZVqwY/e+WVnx0UaPAG3owfFLzfEyV6laIllkpY8MToGRWns3LGaH1fPhg9o1Il01XLO5LB/L6Ns/hB/9oPLix8cK1fKhlGdGbfrl37shgNSaQKYU2YWtNoIB58qg7KSTxtotrBLTUR39Mr6oqQPp+nIUz6SXrnjoSEf9ntdLqRSZLYsTPdW0eonkfn8TfgwzQ96Gb5RdZTozHq59B3Cn38c3WYYQbW8XeYQSv4bALdhBmIy0DG/UXX6dtjUn6J9cwOc+gM/iA+jLCk5maXfoG5Yj//bJ3wXBk8my6w6D5BblvUX9HKx2k2EKOQHs2z1bJT4a702AoTCZOjygUrnE1tqKzPTZwW4/ajUp9Wjh+VKORVWoJMpfM2L+7Lm4GBTQnPxC2XXvuZPv6H/J7FdmQCjbMRkBhsxWRCDCn4c/B99yy6jb8b3TwrRl/8H8bHkV0gL/AMPEfd3fSfhXvFm+CKq/EGogR/APyn9iaDZ9I5Pbic/RrWq1KmSTz36/FJWiYpj2N/E4uSYO0slF3wIkS/BgTQ6CXSAsJiYvVGE5vDiaMKvVpjlj+z428v8b+RyaTMxoevAvR+pzGqsdqq5p9Eu9DIz1x5p6NgexMu/LxeJxjPAEf8WcTLKIYgAl/n9F/1+v4h6b9mYLwP0PqFz1OT4tECTpFnRsCk+uEZL9kbE2DD0kRphuAb6JnJpC3g6FtInANn+Pd+52yH6Sa5a8qtuKndOmvH7IJDcblcxRgYNXO5HLzKwNJ78S6edrnQ0tKn8EcCLn6LJWG1JjrQHS6Rqvis5nz6dqKeQ4IGMpsFvoIJzeKMwA96fJZvg84ge1FhlbVhPMuug5PfqTpUeoRhIXtYrRa92J42mROWpTfxR+GUZ005mz1rQ4JP3QucNw+cZzxeIkW/4MQ4E02O7SLyuGtsbFef09m3a6w25fVO1YQjftS/7kM7d35onX/5eyq77yxQAaAIztqXJdIPE/pA+j3EW1zx38Gb49Lplr5bUXe1dadFI3OT0Ym+uILOnV9IFzsgMly716QNVifnQfyDczMz8wEJI6fzyNLLFUpWjOug3EXxB44qNzi8TVidneo8eX1GMagLGU9c59TyOsfPJOs8ky1eOeqYvCJfba530uebPHm9S+YOn2q2rduDf3iKlffCysNNa2xe9sYsFjZEFg0fboUC7DIFBqdPj9u4hN7rYAbmezUxtndzyUD/OlO02YoZkRBT2zfiB9kNk4WxiEwq6Yg4f/GzkBeBCTd3ZzKcGQ+u0EP0p3jQ8V3/22wJsqzKkkQS100X7YXZ0uosScj10bFeO7f+bbMj/Zhu60quzo4Q/rPCId7KGpG8FdE7k7OIW3pZVCaTkwTztcCnw3CfSdQnoi3SZ/TLu6bHw11nb5k7Lz3rHi6V6h6Q+A0LF3PcxQvoTn7D6MZAYOMoupOMpIcZpwX7LmgYUbwyLQnG0z+SGNSbNAb6R1vukKokdnCxwawvnaHU6ZT44NJzxoDRGDRiHxkLbCX9CRgrs3qsZWfh5LFJTLgsu+Sc/sR1tEG7oDHisyVyiUnCSHbTRs1OOL9u7myJTGIB6G5s1GwHbHZLGdwBuvI9gMuZKp1OjZn2kNEYNi79Q63TqfCnl/5o7LRYou1oSdPWpuFpc9Rk6mzHdiIHHbDmUcBTupxxE1SqkWTAENGmvfd/e/vD9/BfvOfh7d+6D/WB8uEP859BO9FE6/snNcFLVTX3S0PoiEADrqyOht3D8RenXpq/UaFjGKZNfuMHwSDwBfQE/xwgagwbkJ+/kP8ZiblowoOYWbE5yIJCwt6Tz63b+RtPQz/lI+iHfB6fiZZ+j8bG8BljY0DzLY0tyAMGh8xvYn1gzCHQFlQ4cWE9i1rt4kctbreFpgptb73cVrA56G6razm/8HLTWiEWnY6urfN7m+kFREUaW6hXxHGJY0yMFomeYVj4fsDqclmv36nT7aQpl/WtI1ZXoY02tRWIpUPnoevwLOFfo4UJsUyIe/3TvhvkN7IH8ewz5rvuMj8Dd1GNR9H9FFk3JawSfHohT+LHNoTwswJO8PTMV52P4Wc/FrqI0DoDNvSX6BhwarKpNYjlJ16zqCQtzGo32aSlW641yubHggMaWaQn+N6C3Ldm/R3oRdbhDzvqwy5VpHsw3FkN1PvQMWetyH/5LNXv4iG5tCJTyo70IcS63UHWFPNVtAHW4u6N5borgMs4eIcSiCi9VHQ5nsCi6oYQ+TjVHSKW2mIED2X95g2m1LpKR0+p21qz5zKWZLetPZMMDydlrkrtRlomRzPo2PuurWzv90oUGkWPXEkj35rBgSlfZ6Db02k+er87a9fy10rwFyghJ/c6+g7Qo+WhilH5io+0ykV1mfPdVpV3xNZTc7lqPbourkMR2Ni5fjGeWETHJEoFR9Oe6Xp9jQdLJN0adfq8+fnzUoTqBZjlVVipk/hixvTbTUNmCQieGEeI/peu+U5pcjgSzVgt6ZAzmfPLw4vFrVPhtahUVSpkEoyOddhy2jbn5PDwtEfns5UC2Sv2bzu36+hSbYZBkzpH1vnJ5VX+CVYZFOlslrHenDedzx2HxXH+oPmcHajQy/8nknnbUb4ftLG7VgjNBRSWgbpj/WIyuQMdm57qH6nG7cmwe2Jwcq2LkXYr1LLMnrnt5yZhzQ6Y68P4B6Ab2pdpyy57sXkLyR8i3JbOGpmFrtCMo/wp/oE5/ANE05VgbOkpXE5UfH8cKEtJdj/SyGMrYK8Di+umpk6Vp5OJHAsswzFMiAZyNs2P6AwIiQmIAFenJIghSmBYqm5ySyi0dVI4Tox0d4+MFgqPSS9lX0vp1Ub3/YP5zsWN1c2c1RjxlkKpdrvGVi0W+20aP3u3O6CVAWaeGpcb9HprOW7Q0x9JdUWjXalILqns5v+b0XX6pU5ltbe76tCxhain09fm1QZ0Tq/F59do/d4Om1ZqlXhi8RDQjJilfwKfaMU4USDWcvASshAZIBb8wis3uIPxzWVJ93mfRVKpAhj+av7jaCYViIZ7O9NHH/f2mHX8VTCOMCJ1J74fdEGzjsOlQbrBiIBMZ/51fdlmC9ts6AW+A73wtK3bBn+EX+2NHPUVeEpJcpZG/XIC97iHv2SJOpNOe6WjQxxBE6oXzQF2OImOtUaihRX9GTBZ9r+Zpv9tYWkuZDzO/0a/Osi0M/D35R2P3/MTWJhUMvOlPeiFwwqjFEstqpeQ5Yc/5o+6c8T9/lf8EH9huQy8PQUazS3QjDLSqwsAn0esJ6lUeFl1vh8/tPSkx9svkdF9JTwi4kV7gafaYIWh5UyCfjkll89LLYTUARDV5T0QwPiWysB65IvYkoWwNLfAh2VAfUO5itYGgx3J7ogst4CO1apkN+IRvd9ZSibVc7AX6AX1wACBJkNtfhdAqeXdBhy0ooQct9uMpbnVM57mVn+Zka1sdCzYG0s1R4aROPBkkCAh7lNKx/GeqGP9zlhs5/p1O+PxnetyvTZbby4HjFBGx9J75ub2pMXjsBdU2bRXPBJswe9VwxzOZjzZnOKkMBvcTMC9ua9o56bJ8JpK11wMFFm4M2M1J0PhyazcXhv7GigwmijrD+yfP7fLZs9o9K7J+uA0Gwx1O6MW9U4N/4QaFNhH8NeFFXLoVZjdQ0VEn5tEs6I8r6guIb4AuoWyeS6EDJYCGIlBWz5t7urpiPUlxrpU7lo9OLPWlF5/ZGYGSWQKUNsKjbwoV0oQ8q4d2zQT8hYcEfPFVxH74aaXFr/oydi1zb3aD/NLBTkSmYNp7lXmBpV8BqWUjs4NZSb/ngx6obnl06wnF0sDj6Ybf0NPQXCUWI7ngVZBYVdWtNRxTjJRTWTv/uIZrruYxFwinrX42et7uPjWuu2MssyaL7q5si3KXhfuMofXwzJk0jKmkczmDlrlHm1PuVRqlyjLiFY6nX6AKL25cHdPuyDbb6AdeC9wnbEVrzYlRtDKT7j8o8q2aFjd2/cX/hvb8V5ex7qI5NT60Fs3EJVMsnDH0J+B8wTONeplK9mcHCkUgwG7FfmjkTXdqu7d3FXotppcARrizkQwFCjGE1ejc/iOrTp0KVCGZPYbMNLbeM6ocUiiU00o2ySHtlwk1zIauY65CIZKKFUqJXqG/4op1m7qNCGSMiEeKe2Gsf5vPWf39bRBPaEGd13CSNUShWSKNmjG1Qb6+tmdUjmtkSoka7BeM6HW09NwVSOVyXYCLimVRqdGY8Zge3vQyN+n1mlU6Gn+oCFggD80Dp60hr/P4DcaWSM6g+hEotv/AXgue84MBGycF8wjF5ISPfjKp+7YesvH+Vc/fvPcHZ9Ctl3ohT+/+eafyedotQrUNzTSiIfndWJGQ0sTJiQlIQ78b7IaRlgp4r+t9mcG4/Jin9Eqb2P2809dLlXSFodNqafvQS8s8Z5yxoMLxr5ET3uXEe3mP6Fz6vrVSvQjgiVJU/wAZjmVL717G/+9beiz/AI6yJ+Fbkf8HWhwEN0+NAS7kGhsRFZaKsTjJjDM4G3IGIiRiaSaZCTCIqY3B/6dmFLPBpEu5A+E24LZ3nFWYzdbOxTsOE3lQ4nDkS4bo3LE2FfiobzEUU4iytahlZflKrv7SLLshNm2NjZSN9Ga5WzRTWVa89YofT9cCQMeBhEPY55oI1JuNYHGIOYslANnAXDgEgSNIBsrj7GKDqvZoWbHyrkAagv72ZAukKMpqbOcPOK2q2BWbYetQSXLDkk+FH+FjTlUjK0rcjhBzAc1TP0aPYHmSOxpdNEWcz6XMctCCToUlJnYYD5/ky2XS1ttxhgTD7m4TJfZbohJjUG0FelNBkzb3KUSxm3kp90Tzdlglzc0StRX0CvNHgqh4HVi1fN2xYw8QfLnZlL5RLZD/H+g2KFntQaOADmSMZcImeFvQ4RC8qMhMWPxzn6uERiRhHEcfCPnss9bGnK7h0q6FGcFnzcKPm98cZsmrlnDJtiiJq7Gc1Klolsq+L/TXiwl/m+K+L9pPnzVVehL/AZ051XXXCPUkSksw4+A1x9YyUuSIj9IInAKSCVhM/B36GAZGxlvCJXauwdYabsvkPKXEnQb1nicoGVQmC9kXRIdbU2P3ob56xB+BNzuIYRRvJdvJAezFgwBnm1HBeHicEDDHy0UKBlVpS7BWlwD2TEKHolbiINOsJAhi1gdZ5rf9AkWFYVD1RD564e/P6wLrEN3BNcG3gpvCqMLZoMbd3GzudymfH4THNFfQ9VwuBoMkmNo3frAumBwTeC/4db1GwMb0drcJk64L89typHdIjXPoWYsbCIa7eR4WGryhgLwwUMvTr+45UZlm5yR6+U3XDuLlPwIQt+AA0TIE+gw/4ohYjRG9Kid/zD/bdS7O5PZk80Sz2MOpOYzgtQwotyQz2fKZZAe/jx0w9IvyFHIIc+j3ws55EG4T0b8tma1T4zSLIRgecFaccblFDMYNkYm3Mmw+WDLlF1Hy73ur7njHalNRdfoRIDxFXv9oYIHBx23p+JS1f3u8UmPzJkpJ0M9boSCzttTMam6LFF64KmENbEJXdnZGzOcbogUIj2FNkRL6QGweEjW4fJH2jbbqhs5VKSlkioGV0hmhchUv8U2sJHr7E0YdhjChTCQj6x9Gk+iCXwf6DTRx245tOyq3yhntTqs1k9YLE6LBd9n5aytP6Ibi41jtELIAaZWaqGrcpwnRXir5Ys7savg9rErdnDcjivGxq44vVA4/YrpZI9L7sl1dhUslkJXsuyWuftT9Q3B4IZq354NqdSGPX39e2ZSqZk9+NHc9g9MTn5ge275+xqZvAsj11C5t+7CkhQj79y+Zs1pnZsSM3tqA+fPJBIz5w/U9swkhN4HpETn4W1gg+NifsL0rqkAQe3w+VJGSdv9vrUhxlqovA/d5jA77NZcV5vcHck6Y/lUDG9L9v5+WP4vVqeU7qIZyTWsEpmNhg6T0d0WVDns+lhnMNjZaFAxKoTuRk+1hajfUQ9TVJuM+p1crFxeiSk0urpyyTYrl1U02t+vePhheLrZKwJP6SlB1yHwgkG36ITc8+ApfGGiRk+Qdia9XDZbzpz6QhxIW4hUNX1Ch4OpvFAqLZTLO0ulnTi8kNuYzW7M5TZksxtiXJfdozZLXVGHrL2tM61Gi6wTIScbyCsZWxw/svxYGYbYyi8hupIF7TCbFY8ld8zpgTjeaFg7DU6EA7XbnAbkwojYlF58GlqHb211wqzjX8K3VkjmJIseQ5zQteI8ZbfXquXdzxZZ8leCo98dN/lMJl97DD/q62FZ8a+bzUa9Jra9nTV5o4S7x6ghjLC6ZfmbVh9sgh4jsXb8FupH1/T18Y2+PnQ1fx8aI/h2ozPQbrC4nhZODJNPZyyM2LIC3J5fDm+e6Or3RsIXGZyGg4h/Wip7v91nQBHWXYxIEjVaqouEfLXIXox6/HKt7FJbNGhwtkmkGaVQ+y6gbWiOlpG8t3Fl78yrGlWafSockCDUCqm+NdnniiRYhGvTgTGv1BIOm7IRNcvOzLBuBfKn3RWLxFulZZFchJNjJhOr9DDSNKgYT8TgMqSRya3zmGk6JWMAhxT2Ii3+5XKO7bnUY078y+pFISHmhUipCzwnA2iYcNPHXl1v0xsZBkIjIc+8XCvKhfS3R8LxsTii2/L1aGcNnHrlCLpVotJ4ZMaQgQ3Q4Goezvrzm3O3ubNuT18Knc6/59b3o8tQmr+qzarJMExnrKMN7QEMwo0E+mtTDiytTjpSc14WggyJLje7Z1iZtVIydx44t/ea0/v/sx8/wigzUinmq8oLLp07J6V/63J6/9I6/DVKkLYj1OdRbxsDK5PAb0T5GibqycbPiRdrAR8L4jEIYvIcWITNoZQVodholyaSQcjq75QoXK5o0SaLo5DboBH42wXu8DO4QfqhjK1+qGeqCJ0tPx83+DNRXmFUOpNRog+KSI4uB12lFjysVvQJy1md/Hl+84inXto8MrI5H43m85EI3jaxrTzunZjfNpFLD9ZSqdpgGkbLgdb5N/QU+AOkZmcxkZ44Tvzacett8f2X/V44oqe+1/6k6/5DLvGLaJggbHBOyPdqKJsQbSMWeVe6uRixSwlQ4zhB2eCr+P5e9Cj/CbBLe+Tvw9TFEqUK0T1/73Dq9t9ZUTdLoKejohIWm+jk//xfCk1SxrremuLvQaoazETmHGrOGT9pxlNIGvBai+vxfr6/jB7jP9Ocn04N+MLR/Ua38WbEH5XILo9EUCzo6e6UdA2chMsxbSTsq0UvxagYBEF8f7hsd2lpaVop5OXAk6NvwA8Iefde8KwEzALvIJGhHCekdZcbx04m1ksisazr+tzxtB9EdX1ggpVYoxFzPqYJBDZs8PsUoZy3bJWw/XgtkFKNcPc/CCm/WG7280oj+Ug3g5lcrK/ISNLgDXijRpcRx2kiwT4LximplH/hBCpjKtLoRE9DhC92t5ghqpItiy0t5hbokxxwFG51taTLWa/Q1RJfWBQaXrpI14qJHJCHmy5mcr5UEkvoXolcRo9Pxfu57uHss1p9gbjqcAD5ErpE6A8ZgsQzBimrUedRD7TgH2vB91KProLva8GPUDupr7fgZ7XgTwL8ay34thZ8N7WLurMF/2wLfpS6jbqbohvwj57Hh1fFDc0U7uoaN/Abia9h58s0bfJyAalJirm5D1bphjvgZRt0/V9Gs31GjVzj1vLf2Io2GiLZwTj/H3JkQ9v5W/FhLBkKePjdPu+gBNey6AFTVMF4LUtH8ZCn06rk946MnIHqQi9Ub0NBukkAz5CA5yXUY43XAS50ZNC3ADzSpNs51Pdb8C+24HupR1bBr2/Bj1A7qO+24O9twXdTZ1CPABF+Db7FQ/SNAI+L4zceJHCqBDTpoA+24HvBWpL7fwPwIH2gBT/S+LqwXxIiIfRiC767cS91D0iPufEGnscPwi9WyEUSe/vufSxj/FOo+I69LOiaVApl37GfBbASOgPoPYBVusktN1H3CtQ+hueFVWeaVP2gsGoRfrAF30v9dBX8QAt+hHq/sGoRvqcFfxLgK+MvtuC7qcuBGphKUGeih9Avm54fsqAAgzj0Mf6zUbQgHKLol/xjGdSfzsAXsbe9je8B/V4VMishMVNhfLeug1cS/PXxZ96p9eBV41svt+M/vHMDAqxDqCILdOpu0ulqgR4i/GALvpf6ySr4gRb8CPDxAy34Ygu+mzpA3QNwoTpKfxTgvc1xvkDd2+p8OPQ/6XwICXX/ddvfsfOBC85v2LCt1fnQ3dMrdD7Q6BKx0o8pR+Nv+DL8I6qfGlrVcdCs9be6QAV+FacXK/2ku7bV7iokucuYAW+eQzPTCwltALxSi899pjtoDE/1uNd0SYPDzlCXRecynxWI+wpev8Pa281VbDPunnUHrtyKf2Ttztg7wyaDxWa1dWgTWk8y0F00SZg+GiO5y2PpMCiT+lw0GPcY2gNus0NnTHctvYTdxaGA+qVaFZNdE+qg+Dmg6qAQddRGlS3oH5pQQuuD1Ar8+627j1ToFvThFvTJysrIh1rQ3QNLLehrLejRSzDwa6bxOhD7GHDtgND1BRqWENGbAz4VHddTFed0+G1KtFxayLqvhHB44ZwdyF6I8a++FbQhrlnGC28Nys21umPdGYnEjh1iFdc5POZSRXvqEaGKe3F+LLihVegllb54r6fa6UxETi71rdR3E2xFF/Q367tHnLXi4uJyERgokG8oSKUVKFBvau8bBe0t1CaFnRgRd2KNsgX9QxNKduI2agX+/dbdR+p0C3qoBd09BjQHv5Si7sfPA/Tb4sj3qci9QGcj/mMLulcK0MYvAOoRxhWhR+4k9o+HEd4UxhWhu+9aEqst6DX8BNjEJMkttprJyd5kjk+uNbufaYakkS7PnzVfjxiSG2vnnR3ePGbv7XMykfFYqmCp1Ho4g69ndG0YBV3fd+Nv0ubC9hsWqu+Z7Dx338hiXuV2Btr1gXp6dji3ODJ32WRYi8dDnwsSfhNrhoQL14pcOEegQkUI/xyg68S1b5C1oL9tQkVdsgJ/onX3kbFGC/pvLeiTY2+1oHe1oLun/gGcXKX60N8xySiJXV9gwywnOEsntQb/nR/9g/AGmEGjMZhbv1C9r+9TWoPgP8EBzen0KeIkpfQ6ou25xn0wf1drJkHbv0vF6xMh/rehf32bshfuMi592og73774BasWKh74N7DqTSI9ZzQt6J+aUJGeK/CnW3cfGZW1oPe1oLunyMhCNl/gx7nmGB8HnS/W26T4IfBHo+9Yb4MQV+iOaJXcNmybDkyVs2ck25Lj/s6MxZKOBMZixtjpexEtEUtul3xw/twupzNnNHmnh+rTvoC3EE4evdOZdaj5zwtFN/qqFdwONXEDjEtLpG8KpOKLQmVAiNu+OCPWjwVLfIwmnX8s2Kr+U/b8NhWZaJWlp+qeJS4lDU4kmgxyGafHEkp4RbPMJkJWtzNTCDWtNepJnX5anOYbPq/XB44V6a/NDtTzaAf/Ofwoo1NXGYU0s2836RhWMRWtXr5sw9XHtd4O96Cv9wzzzxMvU+CvY/TmZi0VNJW0yVOZJo+FVr27Qda06rqgu1lBd5/UWIEcIt+JPCjwXU7gQfTl9YuJ2GmT5y8gd5X7598iHoxL/ekeq7vWHZwLyM0Ddc3bcmY9c/48ROnTQ1zZVvHHQ0HPRK2lnsmbWNhB3UKbhEofUDaUFTP9JuAmBiRxQa9BijZlRCpVaZBOjx1aQ58zlzKr3NmATtMjvkHVhQPoQnx0dS/SX69yXS6/wnklPro/cNppgf3kDQLcT30Sf03o9F2VR73UZrPbbPhrHaQhoAO4uhPbEcKviLUr4zv0cXzSmXI6u1zkmHJ2+HwdNp8Pv+JIupxdDji6ko6Y1+Hwko+I5QBg+TDJdqyuv+Dl+ssVFghGTM72sCwe8qU6OxzGsMQYwg9inbGNltgchSJNA6K03RXOWk/KLIpvpT2+6q20x/lrmm+lwRUsX7mC5XzfyhW6sHKFLiy1kSvi6OQKjP6sMHo/+it1E/6F0O9NtGMZi9tkIi8wbDdokLz1xhz6q0ZftKcTJpUz5bPl9aQZmiqjF6lP4Wea/eImkxaveuHuouOex8+c4vnBxtXULdS5b/fGnlGj0Kmbz5974uOYYI8yAvaBU+GfeZcVHXjn9Z08H6wWdQmrFStIJ6yXPQmC9O8w4UkEOYk+mNAHcQJ9YMbA/2RG6zvMeO67TCih4o0PoCeEKpAdYtFcs04hY1jB0cswYr+2Sahp5wJCIVuUuWCIgYA8QywBeVPaqJRIMxKZ8l5lwp7s6EjaE0pEdSRtSaUSDh0zUklGSjM5OT6kHHQV7PaCa1D5rFIqTUulSuEDv6/05G22vOe33/0uBTrgeMw48GbXQfT8v8CPJnqhiWI7y4nAnHhLYNVTuawxYxbOyKjkjndbzbhSBsuRKO8TzgQ4f27rznszYPrAAGYkEoQk77TgpZ8oh1yc3c65hpT/oZQKYwozS5UpJWI6QvYhW9RiidqGHEHSO0rdg9rQotAXcoKH83DS70+qU4FACi02f6iTfpB/sI20jLqQvNWFUmBZ4RsvChbWsESonGy8IfnWce90C1T+f/Fed+D/z3vfaOr45+AJ8bkTXgh3VLsLAw7HQKG76ni3F8Lzb/+qONCw+Z61QUZsjnhO/q8AOJcJOtUPUdV/CTleYrfIu87fiV+2P34besp16H7Xk6TlCjz4EPWP5XuE9O/sbbfHVhK/pDkFvB00ueoN4kkhRdl8KYVEA2grmqel71SLWabt93N9Tnd/NtvvclfTXV5vl9ev1fppaWx+bHQ+FpsfHZuPcUOzs4OuwZ7ioIuMzqIz0AUwtVroIc6QnGTGxDC+IBcgCdMvDOyRydWvdb1ms6qQuaKkqVc06owMdVrv5u9DTI28KQj4lfGS8OYHwzIrgfqKK5kXQ3WOQwn8dVmcq3kspYIhGjMzjoI54NcgWykdVKiQAi9xO2hsy8e9vSGakWaljMFrZV0KjJFG8U1C0QrMthmokVzV6XTcm6CtVrpMehWlyvi3ShfbJm1nba6gRaHw+T1uhS3c7mMt2FnorGbMpUJPxWoK99JSJJF2YazyDha5Plt7yB5jlVYzTNMz3lnx+TdODm9K6AGTOFCuDutWCTai+Zor6MSgUSvbP3AOLZM8SeMlo56/HlXkOqab+H4DgP3ZtKSp21pVrJU36lr/28Cy3DRT26Hjam4/y5ZsDnfQbe/rXt8P347SlNev8aZSHg3rjXk1PpfHo/bQEnNXMJyWYkkxGUhZcoVkUQIucbg78yeN2+F3Ov1Ot/peG2t1qNUOK2sj7xQDfluBugnBzjY3sJXqWU4JrDQTL79Y/JCCDeql7VG7M2hWyD2BZIct1O7zm7Gju7OSt5byxbKlPVyC0aVAW1rlG+wpVGyJcCerEEhbHolUWHZ2cng2qSd0yjVex2PCe31ss3tSaOJo5oLMJ/aTeHMB+KCbCmOsUheIxKzVSXZqwV3q7lCw64qL+7LZfR9m+PejQww/gx9RKms06Gpcvnju2g9BqCeT1pSa6Vsu3HvzNH9ZT88HenqEnSrRF+NvUD4qKMZHllO8QyV01wmNE1w+Q0om5O15ep0Z67rbVFtl7UkDs1UNvzFIjpoel8okKikjGZMZlo6VH+cfwt+w8p9FE/zr7e1IzR9GC1al8lcau0Zr1/yynb8SXZrJwJ6MIgZTqN7y/0iNGiJY8r5/49voNaE+ImqO1/hz6ujj+AHx/x6QkA5prMM/EDrxLM03/S2mE5qkvSf07CJsqnWsF1qmX+c3z6GPr4coItzRgX9ASyqRzNKPcTZV85PW6RN6eh2NN/DH8b9TLnEm0kJ5XPMfGzy+ORu15fqrxXZfs4eW6/t8V3CDo/wR/ltb8Q8wltJLD3q9eeF/vsBuFM0KMw/6XyAdgrSwth8L3d/u5fzk6v7vwKn7wXWxhF62ARbnrqCLSXO4bKcw6aeW3jOHHyPN4d7U0s9wOt7n1ZzcKi4ls9Jrmz3nhDMzy1poZSbyBjQXOJ7Q0hNo/KY2ltQzMwIeuGfJMoe+b67bNglER+Vlgh+Pz88Bgz8etwXH0Z8m9KefB/rrQHozp6LIu+7ICeQ55fbcsHTBSZR6l80iOR3qDTSPbwXb+QfqM3Dugkj4GfxpOL+UOgjn3YhCu/HNcP4+4bwA988J5xdSn4ZzFq5fgA/C+R+F6zm4Xhaef0EYrwLnm4Xx/yScx+H+Ov4knL8o3D8A18/Gt8D5S8L1KpxvFe5/WTjnGn9D8+jmNgbwo3jyBBhH6hn0aYBc2oSAAke7hXve14QUGn9Hc+gWgFzYhBDOvwAdBMgfm5AcjFxGnwTIC01IBSCbhXH+1ISQmmtduOfFJmQA7jkbfQ4gLzUhVYBsFZ56uQkRsiT47lbu8AkdqInGj9A05UEPEaskeMJNz9gkxMloWoyT/w8A0Zp3AAAAeNqdks1O20AQx8cmfJUPqadWXDpHkMD5gBNIlSJIUKQ0hiTKpScnWWwjx47sDYZT1XsPPbaX3voEfYA+Tl+j/11vVAeJS2Ot9zezM/+ZnZiIDqz3ZFHxc7EKtmgdVsE2bdLQ8Bq9oY+GK7RHqeF18CfDG7RLXwxvwf/N8HaJd+iAfhreLfEefaXfhvfRm4uKVmUb1g8rNGzRK3vTsE379mvDa+TY7wxX6MD+YHgd7BveoLf2Z8Nb8H83vF3iHTqzfxneLfGexfYfw/t0Vtm8TOZPaegHkhu1+ikPA8Gtx4QbfJMm92IiubmQQZJmfBhIOc/Oq1U/lMFi7EySWbV31RlcuqNWv4qck4ZTO9K5feEvIi+FXatf9Nxe6wLuxolxF/LGGIk0C5OYdWw5qudJL/ZExNfezFOlUTnPcyeehtkkeRCpmKoWhkGYcTuJJQ+SO5l7qWA4onAi4kxMeRFPRcoSlxp0uuzORVwEd4uAY17Wrzt1h7WYyVUy3oMXRt44Epzjzuxxu3nLnjxn0082ScO5zJwsjJwk9atuu/vyCV1SQnN6wucWkk8BSWJqUI3qdAoawiOwt+gRceqE6QaxCd3DP9HRTVpgD+BLKYN9qFUkVDM6pyoeH9oqYkFjcpCV0AzeHl1RhwbowKURKvThK+qcoI6DHo5Kdfuo50MhIg91inPV5QV0XKwWqIhuIH81utz96skIluo6xHmsI5a6L2n18JZYMZaAj+kaNMNa3rq4c64fB3FTqGf61g+6moBnOQU131BPra07UPMcgO5Aua6npl9ERNgnsGNYSoPRk1JXmqznK3R2h7rYXXQi9J3+KXdXFI7heX7/OjpTi0udrdZdduPhNh5YTWWMtzrJzf+sTlXdJt1qlpgJP5uPmoj65ubwZaiYaS1Hf0U+zl3kd/8n5y/hCgeseNptkFVsFFEYRs9fFxxa3K2lNt12WYq3xZ1SXErpzrYD7QysFHfXQEh4g2AvQHANwd0lOAGecXgAXqE7cx+5ydzzzZcvc5IhAvv8PY2L/xxJDF9ESASRRBFNDLHEEU8CidSiNnWoSz3q04CGNCKJZBrThKY0ozktaEkrWtOGtrSjPR3oSCc6k0IqXUgjnQwyyUIju8aeQy5uuuKhG3l0pwc96UVv+tCXfAoopB/9GcBABjGYIQxlGMMZwUhGMZoixlDMWMYxnglMZBKTmcJUplHCdEolkn2sYjUX2cFH1rCFjezkAPslig28ZSXbJVpi2CyxrOM6HySOXRzkN7/4w14Oc5fbHGEGZWzFy3107nCPxzzgIY/4hI9nPOEpRynnJ9t4yXNeUMEXvrGemRjMoopKTHZjMYfZ+AkQIkg1c/nMPBYwn4UsZhHn2MNSlrCM5XzlO+d5xTGOSzyvecd73kiCJEotqS11pK7U4wQnpT5nOMsNTnGam6zgGms5xC1pIA25xGUuSCNJkmRpLE2kqTST5mzih7TgClelpbSS1tJG2ko7aS8dpKN0ks6SIqnSRdIkXTIkU7JEk2xxSY7kijuisCg2ZBqalq8p9nNY4FLMUXQr5tl0FRSE6dI0j2I3xTzFfEW1y9YSfEZ5yK97SwMVqnLHVBlmKKjHBPQyy/Q6rUdTzFV0K3ZVVEKPEnryovqH/Jb94sp2R/pKfNE1T4lh35XxC3S/lWmGqvxxlqk7ITjXaRKCFX7d6eJ9VsivklGtdgFjnrML6NW66UTdKK8IOkPTUB90HF7TqrIddgg7wkE5wtFxOCnssHdhh71zHHZ0HPbQdtjJyKy0yiqLi4Ymz9b9huUt082gXvM77bowv/gfDYT69gABAAH//wAPeNolzTEORAAQRuE3O52o9krsZdAgQazrIbiGqCQU9P7EvGTyZZrBgJB3PnxxIoxYOT8SOVVORi4Xyimp5Fo5Da38V05HLw+M8sSsvbDqsilj59A+ufTntgB7AJlMFLEAeNrdWwtUVdeZ/s+5vC5cUAFFCSKioqLiI8YYQiw0lCgapYlSY2kiJp2yGrXWYTIZJ8l0zHStOuPqysOmRJOONbMyiekEFZOQahMfMT5b8YVvRZSHKHB5gzz2fPs/517OuQ9AY2xX7173u/vsvc/e//6fe+9zDylEFEjjKY0sqWlz5lP4s/+ycimFL83OXU7h5INaEoJU/CikPv/jlcspZFn2yudRJ0uIETXkl1gODCAL2WxnRr2Aso8pFbVPKNOU1UoOvu+o/dV4dYn6B7XDut0SZUmyFVrykLZZjlhu+gz2WeczBd8PfHb6FPtG+k713eR7wC/aL93vOb8jfvW2Qv+5/gdshfgtDhgf8NOA4wE3rX7WcNtq69O21VqyLkVaZd1o3W7dYy0ypEt6umm9FZge+H5QalCpLQ53vGb7HX8LQfkgzFXO1g9JAUdCUBaG5E9xNBHzmkzJFAoupVEszUQaQek0m0bS4zQXLRYhjaEspLH0DGVTPD2HNIFWIyXQGnobfWygTehjCxXg7q+Q5tApKsb9Z+gszSM70vcxWoK4CWkkikpgkugELhJVwDXiKvBNUDiedkvOi3pLlmUH+J0obkAaSagJx0hAH5W24tdC+SgJR94PuE3WiOOWVyxfYh42cZaWU7y4DEwQ5cDJogyYiFbLedzlNBeULKcFYj9wkTgMzBIlwGdELXANRl1Or1MU8A3RCswX7cBtfFeBOAPcLU4xNvosBDXBGDOcUkQFMFtUAwtEk+9G8DZBlNIUjGQHLgIFU9D7DmA+57eC3ilM/xTcUaOV+w2iIAoTG6FjCeBMKlOeij6KgYtECzALbVPR02bU5EM6qcyVVPTkDywQ9cAq9LSebKCtGPIMEw3AEZhHOnrtACaKW8Ak0QVMEdeA2ZhfOnqVtbK/dMzPDqwGz9JFlf8tyNuHOR/J9ZFMeaTkAjAYPX7J9RFc72OorwOGgJIDQB/wOBP5TmCY+CMwQRwDpmDcTOZUJubXAlwj3gXm03DgVuoHlP1lYn6yh93gQSbtle3FeSuBuxbmajjTFo76Zgq3nkEvJ9xqGoHJoiZwDNMb6TYfO0WK6sDF0HU/UFoGK5AyiAONNcBs3B/HPcbxfXHQkg60dh2licIDF1u+wLz6YdY1KA0W52BHIchlYe47gQniJDAJHMpC79eBCyCXLNaVLIxUA1wjPgXmc8lWSDhLahdQ0plFquVz8FKzixCUdQGRDwo0lNVQSFAXc8SVxluwnFpbrGUX/MIm2MAM+khsAOZD1jNoi2gDbqWhwG3g1Qz6RLwN/Ey8BtwrPgTWiSvAEaLclubWux3oR/7BPjQAHKikHGgJAcOgKTk0EjqZAx7LkgRYUA48kcwnMy4Q54FZ4F4OcyCHacpB3yFAqek54MN1oJRnDqipoByMlAKf7ou2sRSDtkFAKdUYtGoA7kXbGEs6BQd/AFp8wLkM1sUM1r8MjNoCXAQPkEFLGZfhjgx6GTzMQK9DgHJ2GdxrBksig2eaAVanWVZhvvk0CTqxRdcPP+A22GEcWtUC94pDQJXtqNuP+TO/Gii833z0MYn6w49V0BL4sSpgAni3BH6sBpgEOpfAg7UCF0CfloDaUmAW9HQJPFgjUHqwJfBgkcB88GAJbeX22xgLuKXKHtWXrTYGnl7yaAEojEF/fwZKfwQk6t+l224mhbDlhcHDZULil9h2m4CJ4gIwCWNnwq5OszWfBy6Cv5HW3AzMxqiZ7F0y4VFk+xFEA1oRh3zQXy5rRi7bRi5GOAocQVZgAuaSC/sbAExCf7kcrXIphWsXQENzEZX8gWtAdy7HkVzMOhW4FVzNBfejgAXgYS5Vcy2FzsQ9Cs86ILSeVmA8qQ1VrA2HgSEs3TD0mMG6mYGxpTYks36kgOMZbKkZ7DUz2MtIbZC6Ui11RTSh39+AxmBY1XRwqwOYyAjPA0wBP6azvk1HH3ZgAbzAdNxdCVRYN6UWVLMW2FkL6lgLGln+HSz/Mpb/TZa/neXfJOUP6qX8I4BvcMt82LfUgg7Wgg7WAqkjP4Ghvg89fJ0t1mi9/0Q0sJhjWw3HtkaObfBpKF3Pa6NExJkA8h9YbFkIHYsH32TEOgGczPlEsQuYhEiZCnqLOYZ9zTHsKMew4xzDSjhiodzyDo+osD0HKLCfiPV81SxHifgAdPlCSkOhlSl0H3Ax62w2DWbrbqaYiE/RxgbNDoaeh3AZ5BhRYvmC++miAHE5YAtWCQp75wDLHkqLKHHWNQyOtuzkKzuuOgdP169qMT5GhlxkND3E0fQ0R9NyjqaXOZq2cjSV+WRYroypVzimXueYWsrRtIujaRWiad3gl0C5jIZ2jobn2Loa2a7q2aKq2ZbsbEvlbEtXpS1xBMxmO1zGLX8Or5EJ/1TPdoUehkgLrYOn8kXbPOl/gYGcD+J8MCSfxxqeBxuLBCYzSs+Zh1WgLJ/D+DjjXMZ5jBmMixmzoUd59HPOb2HczXiKsRhRLw8rQJk/y/lq6HOeqBjSipl7py4E1i3psjFdxHTdugO6lnFeo+5lE3XBTB0xdcFMHTF1QCVKiVFiQYkfrorwK1Hyq4j5VSR9FjAZGlHEdBXxaEXcXxH3VMQ9FWHGwfCBayHVLmAY+lgL2dYBE2BRayFhmU+CJNdCzs3AFGjYWo78a2EdbUDpW9ZCe2Q+n8urobdrWSvrYCP7eJciY4k/4p2MdrEcUyLZim2OtTGRsx1pqwMg/BlWR+pAu9wbDLKPa8Y6Mo3uyUd0gHOuZTd6au9WUme6qtd/b8FnGsvbu1vw+ouc7ar1XIOogl259l6ktcL3GiTjnS6ehfgCdoOdpH71BmMN390pa7Rr0+z1PkWlKBfnIFGCnZMoFmXwA65j7Ge8zH1eAuVN3SPfEefb+9y2vXc59Hj/Hv2XZSLyGF24Cc32dGe9qIPP09uLy+DTJbc2Rxm1Vlcccu+m0EyrOCRHEk2a3AXbDfwwa4CzzTl4aflbYrivUpwRp7TRJWIVpN/nbFEjbsDHy9xZSY04Bpv1wjdNG8ReU91rjHaXO5o88qVWVEtN0KjGeJXiohfdveqguBcZHTBdvc/Y2GcJlzvkCwlc9yCjIgOfS29fl3SLavVSazdalVlzWdodnv0L1kw9+BhdRl95kFGdyx0ePQM0t9Ygo/MeZXSM8ZrDsg1zbXd4JuM8TVefo027tByjnppanNC8iENPHTMXLdCeq2wFLYbWf3aOfdQbP40aaLra4lbf2UfNaQQ1N9hrGj3jFW+z9h5F4BFbe/dcPUcW9OTmhzSbdnqvtl76OW5q/V5f7jHczR4D6wTYLeLRZbf6vxha6b4OUadO2i88G+YgDmIFzbPB+lTTvAYHB8Vu8SfN68FXXcDvEXFGo0/jk/gfcRocuGq2C822JR9ECe4ocegQ4y5NE9kGK+7ZmqGtL2sG0dWtOWZ9xjxllC0XO/jqbeZ3kSGWHIW1btZ9/WmjJqB0s8jn/GZ8P4TuVqCfLkfsEFvF/yF2r0TJSfGRbCV505Memn2HJ2/PXrWjt/UQZFgr5QYrqDfUlxp0u7ObM15GL2W9adP99KVuO9f6lB7JPaahrAL+pFqTv6zHdSO0t1ZGTYdey3qxnuPoTb42xVxR7NZni+nqT6JZp+2Q2c6cLf6oScrp46oMcfkarx0uufg6bf30Zbc39xxrHRwEZ1vcyts0Lnriiqs2OiOSoS1ss9oZb7q6Y5xjteihn7Omq02uLd2jhqm2wbCeqZZeFrOqMvcOT2zvjkq9+8w7WxO62XS9N79rjr+yHWatrdv+V/OvyG3Q6BUXRKFe8qa+/t4vCsUm9otnTHE9n+d62DyK9Io6d86JHbp3a9V93euMhRx5t3lfjcj1o+nqt64tzetGt7ubTDIqZf0y+Fap59LajSsY3cI9eBmzPogt4LToSb/MdQb/0uL0M21e1ks3e92r2T3t3KCBXV72anWmNUGbaa9W2uNercm8cvS2q8HYbV7Wmh29r4EM2muksxPy6vTgJWr09Y7m+Zqcvq/Vw3rWLN1mF0s7rvv1Oi/01LntIrT+TphXZ6C0we3eGpc1ZqcuIy86i51oiVH6jvuda0zT7MQR59inu0cyRCZz631yB4I9YIlh/1tmWpO1iDzNZsUp053rxFuuEaIXGZZ4X6FqlPNOQqdPHDTKxamXezQqZF/grdNTi8+wcqi9LWpq6G/+o8ux1d13Ye6ddysyeNJurzVXTFcfu2q3YzXieQ2mW6lcbVVB5yp45WDwMhxfGrTRPe8c/0bkcqnPLY/3fuL29/wxr/d6Ot/7q1DXcbu7IOOZh7f9kTMyqBRPvnz27k9WUihYPveifhSKsnAairIYGkFhNIrGUgSNowSKoklIMTSF7qfh9AA9hPqHkcbQIzQDrVLoUbT7HlICPUazaCLNpiflfx7oKbT6IVIy/YieRrtsWoK2P6YctF2GNIt+RisonXLpBZpDLyLNo5foZcqgf6N/pyfoVdqIXt6jbfSPtJ124XoP7aPX6DidoHV0GuktOof0W7pIVyiPriG9SzeRfkc1SP9NdqpDH41ImxSrYkVfKmjsjxRNA5CGYd6hyA9CGkWDkYbTfUgjMesozHko0gjUjAJ34jiNRgrH3MdQJOY+liyY+zjcnYA0mjnVH3OfAo7ej6SAXw8ApyENoAeRbDQdKQJcfIgCmI9R4OMjFAJezsDIko9+oPEx0DILyQfcnE1DwJ85kM08pFjwJwNUfx8csoLTT2JOC5D8KVM+m6UfIAXTQpLP5J5C8mcZDIUMfkSBkMPTNBBcX4G5v0q/wrzWIFnoP5HC6b/o18i/iRQJDq/DLH5Db4P+DUgKvQOOBoCfG0Hte/QB6PwQyYc2Iw2mj+hj5LcjWekT+hxU7UBSaSd9CRp2kfyHwR6kQP6HkAWS3If2UpbDWJbRLMtoSKwOs5MyCyU1NEo+nQhdEbYQkkljT3y9e3Xlsj5q4jXQNWP87l41YO9Z0ftO3Gll5fKEynnqep3jQ7Pz/OPaN7Hh2zmfugv+xPR0Qxy+zbsb7mDEVk8j82egecfBewBf0eU4ITVH8j6N1ceI7L4GEGV8GlSjr8uvd8+2e0fj7STcfdd6x9K5ZThPE/p53Dpd69pNT5Dsns5JxA3sFi+wZjqeIJ338gSpRH+C1C7vda7Xz/dKYbW+Es5zrnZNOz6sci/1pClYU1V53JUUmmUDLTjT01mQLrPabg55GKvA/ezUXW5G63Q9bdDP5Fsd+wrHPtLDjumKFl3FWw4+uNRv4edFt7zu1prERZfTLm2PU2DYD7bx6eMR4+7QI1/0nR+fT7T0dEbhlTMtfdLTDvdnGR7WIdrT0G3ftq/zsIOu8LjOtd89e3U/89FPHi7pJ6Jl3s56YKUXHFRxpLp+u/4WMamh53Wtc0fa4RYbmzl23nA7a6pxf6rTt+c3d8yxM8a9v/aczVVHvGmZ+3lxn0bUz7K1Xrt3qebzJ/ZAtXcS7+6SJlV7evpyz6lo9xCP3tTjkfkfDdWe47GHqN+nkw/eZ7exLyszSkF8jn25Hb7yKMuwUGqsdqLVrQ3dscSl1+13REsZRuyA35XPVtoRX6/jqhHfSuZCByJiO7DDKCX5JORb8i+liCEXQVEl6LmI+N2Kseo4tlSg5JqUC0vmvNPyr97+Ouob6kuV+5ka6Gz6q2hwmfva5+/gzKLDQ7S72fddCGy5nJ8X2/V/hhjXuzd69uqIK413eTamU1fN2/Q96t9dHy2O8GmzvtvTnw3XmaO4MVYbLV1chq+4Dd6IFn5Wu18UYd1+BH7lHH4Py38MwY4reWVwCiVHcV3Dz1EPOM8mj7iuju+p9h25J6PsF4fAja+xUjroTIeRDmGPcUwcwLcV+YNio7RqsY+f5h79dmjDTkr+h+KiLgGnR+Xncq3dTwf5icZpxxrL85ruLu0R2z38r8zzP4NavT/V+Mb7gKa+7bCxE2txjfC3TUvPayCF5Ns7fhRIQWSjEAqjaBpGIymeJtJkmkqJlETfoWRKo3SaT4soi56hZ+k5WkWr6fe0iQpoN7+lJt9RK6WrVE8NpFIcvyvnw+/Kyb7l23JB/H9gG9J9uAqhfvz2XDSPp2LEkdQfo8aTFeNOBl1TkQIxfiLuSEIKBh3fkW8cOd+zGwCa0skCuuaTL79hN4zfsIsBjc+g72eRfPg9u0GgdxVF8dt2Q0H370HLJqTBoL+ABmIOu9HDKSR/zKWYAjCfM8ifRQrAvEppCOZ2lSIxv3qM2IAUId8uUPz4zZsYfOW/nCdy7hGaRPINqGh8v0ujMDP5GYZvLA3H+MRnntonGXP1RY8qvn40gn8tNBrf/pCMja/lNwhU+tMEUJwA3g0h+a7bVL0PH8xVwRwV8DQCecnvMHDKymfTVnDNCu4NwExS+Ww0FJyQn/vxjWcdsBDxP7PlHB6gh7k2mlJMmvIQvjM4J98kTNRLfQ1Jvo/jpyeLM8k5OJI8OffXUwjq+ul64kiKMwXqaRrPwZEkrQF6CuXzdvl+luJVu6V2EY2j8ZCEhtonkmUWQw/SdA93PcrYz5n6+gnk90MlhQpmHQvKfkEXWAKp9DytpH+mf6WvaT8dpEMonQDNGA0Zj2XKJkCuE6E3k/kJwTSm7CFIQj4d+B49RjNpFs2mOfQ4zaMMPrV+kjLpB7SQnqIf8pOBNbSBPqQdtJf2YUT51pR8E1TqCfGbMFJ28n3bdCL+n38myg6oMcCj6gTOS3yRS37J8/iZOgZ4Qh0NfIvzx9V4UPop7aQ9dID+QifpHJVQOd2EVbRSl+KjBCr9lUFKlBKrjFESlKlKopKspClzlCeUhcrTynPKT5UVygvKS8pqDPAr5dfKOmW9slF5X/mDsk0pVL5QvlIOKUWoK1YuqC+qryBXqlQqNUqjcgsK5KcuVVeqNjVUHaxGqyPVeHWSOk2FPqrfVWeqc9X56iLkF+P7D/jKtuhD/Q85G+VB9TRwGlYaipKiXgKmcn4G5x/l/DT1BnA8t5+plgFnYd2gKHPVconMlVdle0hW5k+q8r2XIm4frx4DjtbboFyZwOWfcf+fcH4p53/C+QzOz+H8RM4/zPmhnL+P6Ynl/HAun8v52Zw/r14ERqsnZUsuGcK1sZwPhZQUxZ97sHF+EOf3qnuAcZwfwuUhiC+K0l/mIXlZO45LtLe5V6m1wB1cskdNABZyfiLfO1bm6QLfu0q7i/NtiG4KbVR/CWzh8qFSs5RwWa68y/cGMW7hll2ct8i8+oA2R8Z9XB6txgEjeayXuf9XuM+z6oj/B1F6YT4AAHjaXZDNSsNAFIVPTJPG+Fc0iAuF4CqIC1ddiVBbu2itlBJEurJUIsK0hWBFXblyKT6DTyHiS/gIgjs3/kJX1tvTGEwY5ps5Z+69M3egAbBxr+Whl8q7Ppz2RajgqNZpF0tYl1MPZqG54yJfLPguysWGcL9aaLoI/JFz5jeqLq6B4RAZidcwgUkqI1J6SmdS2khpM6WzKW2Jto+6vQ62grDVRkmdHLewp3ptBZ9skodkQCoy7PY7Ic5ZR2rKy2xMYZp6jsySIE1SJ8edjV9gIYdVHMhQ8bjDFW6EDxhgoOWiXEvmJtdRV4uyq8scE9xtxITEaHGWiVueXCa8R3q1f56H10TEEyMWEt4zKztYEc/kPba8XxdvXuZ21PEMM19ify3yZ5k91KxI/1W16X/jR7xM7Oe5GvKnDpblFg9fUrEiHX9yreFN8mp4F9bxIazw3sovD1BNpAAA') format('woff'); +} diff --git a/optimade/zero/app/app.view.css.ts b/optimade/zero/app/app.view.css.ts new file mode 100644 index 0000000..adc0854 --- /dev/null +++ b/optimade/zero/app/app.view.css.ts @@ -0,0 +1,9 @@ +namespace $.$$ +{ + + $mol_style_define( $optimade_zero_app, { + font:{ + family: 'Exo2', + } + }) +} diff --git a/optimade/zero/app/app.view.tree b/optimade/zero/app/app.view.tree new file mode 100644 index 0000000..84e6caf --- /dev/null +++ b/optimade/zero/app/app.view.tree @@ -0,0 +1,20 @@ +$optimade_zero_app $mol_book2_catalog + plugins / + <= Theme $mol_theme_auto + param \optimade_zero_app_page + menu_title \Absolute zero + menu_tools / + <= Lighter $mol_lights_toggle + spreads * + search <= Search $optimade_zero_search + Spread_close <= Spread_close + Words => SearchField + profile <= Profile $optimade_zero_profile + tools / + <= Spread_close + about <= AboutPage $mol_page + title @ \About + tools / + <= Spread_close + body / + <= about_text @ \The largest and most comprehensive inorganic materials dataset diff --git a/optimade/zero/app/app.view.ts b/optimade/zero/app/app.view.ts new file mode 100644 index 0000000..50cd711 --- /dev/null +++ b/optimade/zero/app/app.view.ts @@ -0,0 +1,21 @@ +namespace $.$$ { + export class $optimade_zero_app extends $.$optimade_zero_app { + + @$mol_mem + focus_to_search(){ + + if(this.$.$mol_mem_cached(()=>this.focus_to_search())){ + return true + } + if(!this.$.$mol_state_arg.dict()[this.param()]){ + this.$.$mol_state_arg.value(this.param(), 'search') + //this.SearchField().bring() + } + return true + } + auto(){ + this.focus_to_search() + } + + } +} diff --git a/optimade/zero/app/assets/apple-touch-icon-180x180.png b/optimade/zero/app/assets/apple-touch-icon-180x180.png new file mode 100644 index 0000000..6a074b3 Binary files /dev/null and b/optimade/zero/app/assets/apple-touch-icon-180x180.png differ diff --git a/optimade/zero/app/assets/icon.svg b/optimade/zero/app/assets/icon.svg new file mode 100644 index 0000000..4848b65 --- /dev/null +++ b/optimade/zero/app/assets/icon.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/optimade/zero/app/assets/manifest.webmanifest b/optimade/zero/app/assets/manifest.webmanifest new file mode 100644 index 0000000..2163e75 --- /dev/null +++ b/optimade/zero/app/assets/manifest.webmanifest @@ -0,0 +1 @@ +{"name":"Absolute Zero","short_name":"Absolute Zero","start_url":"/","display":"standalone","background_color":"#ffffff","lang":"en","scope":"/","description":"The world's biggest high-quality curated database of materials","theme_color":"#ffffff","icons":[{"src":"pwa-192x192.png","sizes":"192x192","type":"image/png"},{"src":"pwa-512x512.png","sizes":"512x512","type":"image/png"},{"src":"pwa-512x512.png","sizes":"512x512","type":"image/png","purpose":"any"},{"src":"pwa-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}]} diff --git a/optimade/zero/app/assets/pwa-192-192.png b/optimade/zero/app/assets/pwa-192-192.png new file mode 100644 index 0000000..ece0d8b Binary files /dev/null and b/optimade/zero/app/assets/pwa-192-192.png differ diff --git a/optimade/zero/app/assets/pwa-512x512.png b/optimade/zero/app/assets/pwa-512x512.png new file mode 100644 index 0000000..674bd46 Binary files /dev/null and b/optimade/zero/app/assets/pwa-512x512.png differ diff --git a/optimade/zero/app/assets/pwa-64x64.png b/optimade/zero/app/assets/pwa-64x64.png new file mode 100644 index 0000000..ad24e37 Binary files /dev/null and b/optimade/zero/app/assets/pwa-64x64.png differ diff --git a/optimade/zero/app/index.html b/optimade/zero/app/index.html new file mode 100644 index 0000000..45181b8 --- /dev/null +++ b/optimade/zero/app/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + −273.15°C + + +
      + + + diff --git a/optimade/zero/profile/profile.view.css.ts b/optimade/zero/profile/profile.view.css.ts new file mode 100644 index 0000000..03e4416 --- /dev/null +++ b/optimade/zero/profile/profile.view.css.ts @@ -0,0 +1,31 @@ +namespace $.$$ +{ + + $mol_style_define( $optimade_zero_profile, { + flex: { + basis: '400px', + }, + LoginCard: { + Content: { + flex: { + direction: 'column', + } + } + }, + + LoginRow: { + + flex: { + direction: 'column', + } + }, + + LogoutRow: { + + flex: { + direction: 'column', + } + + } + } ) +} diff --git a/optimade/zero/profile/profile.view.tree b/optimade/zero/profile/profile.view.tree new file mode 100644 index 0000000..e7d4259 --- /dev/null +++ b/optimade/zero/profile/profile.view.tree @@ -0,0 +1,37 @@ +$optimade_zero_profile $mol_page + api $optimade_zero_api + login_endpoint => login_endpoint + title \Profile + body / + <= LoginCard $mol_card + status <= login_status \ + content <= page_content / + LogoutRow $mol_row + sub / + <= login_title2 @ \Your profile + <= logout_button $mol_button_major + title <= logout_button_label @ \Logout + event_click? <=> event_logout? null + LoginRow $mol_row + sub / + <= login_title @ \Please login + <= Login $mol_form + form_fields / + <= email_field $mol_form_field + name <= email_label @ \Email + bid <= email_bid \ + control <= Email_control $mol_string + value? <=> email? \ + autocomplete_native \email + <= pass_field $mol_form_field + name <= pass_label @ \Password + bid <= password_bid \ + control <= Pass_control $mol_string + value? <=> password? \ + type \password + autocomplete_native \current-password + buttons / + <= Login_submit $mol_button_major + title <= login_submit_label @ \Submit + event_click? <=> event_login_submit? null + disabled <= login_submit_disabled true diff --git a/optimade/zero/profile/profile.view.ts b/optimade/zero/profile/profile.view.ts new file mode 100644 index 0000000..71b2f9c --- /dev/null +++ b/optimade/zero/profile/profile.view.ts @@ -0,0 +1,63 @@ +namespace $.$$ { + export class $optimade_zero_profile extends $.$optimade_zero_profile { + + @$mol_mem + email(next?: string) { + + return next ?? '' + } + + @$mol_mem + email_bid() { + + try { + $mol_data_email(this.email()) + return '' + } catch (error) { + return 'Enter valid email' + } + } + + @$mol_mem + password_bid() { + + return this.password() ? '' : 'Enter password' + } + + @$mol_mem + login_submit_disabled() { + + return !!this.email_bid() || !!this.password_bid() + } + + @$mol_action + event_login_submit() { + + try { + this.api().login(this.email(), this.password()) + } catch (error) { + if($mol_promise_like(error)) { + $mol_fail_hidden(error); + } else { + this.login_status('Login failed') + console.log(error) + // set random sid + //this.api().user_sid($mol_guid(16)) + } + } + + } + @$mol_action + event_logout() { + this.api().logout() + } + @$mol_mem + login_status(next?: string) { + return next ?? (this.api().user_sid() ? 'logged in' : 'not logged in') + } + @$mol_mem + page_content(){ + return this.api().user_sid() ? [this.LogoutRow()] : [this.LoginRow()] + } + } +} diff --git a/optimade/zero/readme b/optimade/zero/readme new file mode 100644 index 0000000..b672639 --- /dev/null +++ b/optimade/zero/readme @@ -0,0 +1,4 @@ +contest app +telegram @soundrmx +desktop usage video https://drive.google.com/file/d/1MUHfX4wWMaCNvVTnEg845Yt7Dg89P8rj/view?usp=sharing +PWA APP https://azero.milkyway-studio.ru/ diff --git a/optimade/zero/resultitem/resultitem.view.css.ts b/optimade/zero/resultitem/resultitem.view.css.ts new file mode 100644 index 0000000..6622473 --- /dev/null +++ b/optimade/zero/resultitem/resultitem.view.css.ts @@ -0,0 +1,21 @@ +namespace $.$$ +{ + + $mol_style_define( $optimade_zero_resultitem, { + alignSelf: 'stretch', + Content:{ + flex:{ + direction: 'column', + } + }, + Formula:{ + font:{ + size: '0.9rem', + }, + display: 'block', + }, + Title:{ + display: 'block', + } + }) +} diff --git a/optimade/zero/resultitem/resultitem.view.tree b/optimade/zero/resultitem/resultitem.view.tree new file mode 100644 index 0000000..e5ea61a --- /dev/null +++ b/optimade/zero/resultitem/resultitem.view.tree @@ -0,0 +1,45 @@ +$optimade_zero_resultitem $mol_card + minimal_width 210 + minimal_height 100 + data * + content <= calculated_content / + card_content / + <= Title $mol_html_view + html <= title \ + <= Formula $mol_html_view + html <= formula \ + minimal_height 30 + image $mol_image + uri <= image_url \ + title <= image_alt \ + minimal_height 100 + png_link $mol_link + uri <= png_link_url \ + title \PNG + target \_blank + pdf_link $mol_link + uri <= pdf_link_url \ + title \PDF + target \_blank + ref_link $mol_link + uri <= ref_link_url \ + title \Ref. + target \_blank + anim_link $mol_link + uri <= anim_link_url \ + title \anim + target \_blank + login_link $mol_link + arg * + show_login \1 + title \Login to access + current false + hint <= login_hint @ \Login to access + text $mol_paragraph + title <= textcontent \ + has_access \ + cdn_host \ + dd_addr_tpl \ + user_sid \ + refs_endpoint \ + diff --git a/optimade/zero/resultitem/resultitem.view.ts b/optimade/zero/resultitem/resultitem.view.ts new file mode 100644 index 0000000..5fc2260 --- /dev/null +++ b/optimade/zero/resultitem/resultitem.view.ts @@ -0,0 +1,95 @@ +namespace $.$$ { + export class $optimade_zero_resultitem extends $.$optimade_zero_resultitem { + + @$mol_mem + data(next?:any) + { + return next ?? [] + } + + @$mol_mem + title(next?:string) + { + return next ?? (this.data().length ? this.data()[ 2 ] : '') + } + @$mol_mem + formula(next?:string) + { + return next ?? (this.data().length ? this.data()[ 1 ] : '') + } + + @$mol_mem + contentblock(){ + + if(!this.data().length) return [] + const row = this.data() + row[7] = parseInt(row[7]); + const dtype = row[0].substr(0, 1) + let content = [this.image()] + let dlinks = this.has_access() ? [] : [this.login_link()] + + if(this.biblio_html() && this.has_access()){ + dlinks = [this.ref_link(), this.pdf_link()] + } + + if(dtype === 'P'){ + content = [] + } + else if(dtype === 'C'){ + + if(this.has_access()){ + dlinks = [this.png_link()] + } + } + else{ + dlinks = [this.png_link(),this.anim_link()] + } + return [...content,this.text(), ...dlinks] + } + @$mol_mem + calculated_content(){ + return [...this.card_content(), ...this.contentblock()] + } + @$mol_mem + biblio_html(){ + const row = this.data() + const biblio_html = (row[7] == 999999) ? '' :'[' + row[5] + '`' + row[6].toString().substr(2, 2) + ']' + return biblio_html + } + @$mol_mem + textcontent(){ + return this.biblio_html() + } + @$mol_mem + dtype(){ + return this.data()[ 0 ].substr(0, 1) + } + @$mol_mem + image_url(){ + return this.cdn_host() + '/' + ((this.dtype() ==='C') ? 'pd_thumbs' : 'rd_thumbs') + '/' + this.data()[ 0 ].split('-')[0] + '.png' + } + @$mol_mem + image_alt(){ + return this.data()[ 0 ] + } + @$mol_mem + png_link_url(){ + return (this.dtype() ==='C') ? + this.dd_addr_tpl() + '/c?q=' + this.data()[ 0 ] + '&fmt=png&sid=' + this.user_sid(): + this.dd_addr_tpl() + '/s?q=' + this.data()[ 0 ] + '&fmt=png' + } + @$mol_mem + anim_link_url(){ + return this.dd_addr_tpl() + '/' + this.dtype().toLowerCase() + '?q=' + this.data()[ 0 ] + '&fmt=gif' + } + @$mol_mem + pdf_link_url(){ + return this.dd_addr_tpl() + '/' + this.dtype().toLowerCase() + '?q=' + this.data()[ 0 ] + '&fmt=pdf&sid=' + this.user_sid() + } + @$mol_mem + ref_link_url(){ + return this.refs_endpoint() + '?ref_id=' + this.data()[ 7 ] + '&sid=' + this.user_sid() + '&fmt=bib' + } + + } +} diff --git a/optimade/zero/search/helpers.ts b/optimade/zero/search/helpers.ts new file mode 100644 index 0000000..91c4b97 --- /dev/null +++ b/optimade/zero/search/helpers.ts @@ -0,0 +1,147 @@ +namespace $ +{ + export class $optimade_zero_search_helper + { + + static arity_keys = [ 'unary', 'binary', 'ternary', 'quaternary', 'quinary', 'multinary', 'multinary', 'multinary', 'multinary', 'multinary' ]; + + static periodic_elements = [ "h", "he", "li", "be", "b", "c", "n", "o", "f", "ne", "na", "mg", "al", "si", "p", "s", "cl", "ar", "k", "ca", "sc", "ti", "v", "cr", "mn", "fe", "co", "ni", "cu", "zn", "ga", "ge", "as", "se", "br", "kr", "rb", "sr", "y", "zr", "nb", "mo", "tc", "ru", "rh", "pd", "ag", "cd", "in", "sn", "sb", "te", "i", "xe", "cs", "ba", "la", "ce", "pr", "nd", "pm", "sm", "eu", "gd", "tb", "dy", "ho", "er", "tm", "yb", "lu", "hf", "ta", "w", "re", "os", "ir", "pt", "au", "hg", "tl", "pb", "bi", "po", "at", "rn", "fr", "ra", "ac", "th", "pa", "u", "np", "pu", "am", "cm", "bk", "cf", "es", "fm", "md", "no", "lr", "rg" ]; /* exact */ + + static periodic_elements_cased = this.periodic_elements.map( function( x ) { return x[ 0 ].toUpperCase() + x.slice( 1 ).toLowerCase() } ); + static periodic_elements_xed = [ "x" ].concat( this.periodic_elements ); + + static periodic_element_names = [ "hydrogen", "helium", "lithium", "beryllium", "boron", "carbon", "nitrogen", "oxygen", "fluorine", "neon", "sodium", "magnesium", "aluminium", "silicon", "phosphorus", "sulfur", "chlorine", "argon", "potassium", "calcium", "scandium", "titanium", "vanadium", "chromium", "manganese", "iron", "cobalt", "nickel", "copper", "zinc", "gallium", "germanium", "arsenic", "selenium", "bromine", "krypton", "rubidium", "strontium", "yttrium", "zirconium", "niobium", "molybdenum", "technetium", "ruthenium", "rhodium", "palladium", "silver", "cadmium", "indium", "tin", "antimony", "tellurium", "iodine", "xenon", "caesium", "barium", "lanthanum", "cerium", "praseodymium", "neodymium", "promethium", "samarium", "europium", "gadolinium", "terbium", "dysprosium", "holmium", "erbium", "thulium", "ytterbium", "lutetium", "hafnium", "tantalum", "tungsten", "rhenium", "osmium", "iridium", "platinum", "gold", "mercury", "thallium", "lead", "bismuth", "polonium", "astatine", "radon", "francium", "radium", "actinium", "thorium", "protactinium", "uranium", "neptunium", "plutonium", "americium", "curium", "berkelium", "californium", "einsteinium", "fermium", "mendelevium", "nobelium", "lawrencium", "roentgenium" ]; /* fuzzy */ + + static lat_p2i = { 'cubic': 1, 'hexagonal': 2, 'trigonal': 3, 'tetragonal': 4, 'orthorhombic': 5, 'monoclinic': 6, 'triclinic': 7, 'rhombohedral': 3, 'cub': 1, 'hex': 2, 'hexag': 2, 'trig': 3, 'tet': 4, 'tetr': 4, 'tetrag': 4, 'orth': 5, 'ortho': 5, 'monocl': 6, 'tric': 7, 'tricl': 7, 'rhom': 3, 'rhomb': 3 } + static lat_fgrs = Object.keys( this.lat_p2i ); + static lat_i2p = { 1: 'cubic', 2: 'hexagonal', 3: 'trigonal', 4: 'tetragonal', 5: 'orthorhombic', 6: 'monoclinic', 7: 'triclinic' } + + static most_frequent_els = [ 'O', 'Si', 'Al', 'Fe', 'Ca', 'Na', 'Mg', 'K', 'Ti', 'H', 'Cl', 'S', 'Br', 'C' ]; + static probable_els = this.periodic_elements_cased.slice( 0, 55 ).filter( el => el != 'Xe' && el != 'Tc' && el != 'Kr' && el != 'Ar' && el != 'Ne' && el != 'He' ); + + + static classes_groups = [ 'transitional', 'chalcogen', 'rare earth', 'lanthanoid', 'metalloid', 'alkaline', 'halogen', 'pnictogen', 'alkali', 'actinoid' ]; // NB noble gas + static classes_families = [ 'metal', 'intermetallic', 'oxide', 'conductor', 'nonmetal', 'antiferromagnet', 'ferromagnet', 'semiconductor', 'intermediate valence', 'superconductor', 'close-packed', 'perovskite', 'high-tc superconductor', 'silicide', 'diamagnetic', 'cuprate', 'ferrimagnet', 'sulfide', 'spin glass', 'rocksalt', 'ferroelectric', 'frank-kasper', 'selenide', 'adamantane', 'paramagnet', 'friauf-laves', 'boride', 'semimetal', 'pauli paramagnet', 'fluoride', 'telluride', 'hydrate', 'carbide', 'ionic conductor', 'chloride', 'spinel', 'intercalation', 'fluorite', 'hard magnet', 'arsenide', 'ferroelastic', 'orthophosphate', 'phosphide', 'nitride', 'piezoelectric', 'antiferroelectric', 'hydroxide', 'silicate', 'organic', 'hydride', 'iodide', 'bromide', 'charge-density wave state', 'spin-density wave state', 'ruddlesden-popper', 'sulfate', 'superionic conductor', 'pyrochlore', 'orthosilicate', 'borocarbide', 'molybdate', 'borate', 'garnet', 'cyanide', 'thermoelectric', 'helimagnet', 'vanadate', 'zeolite', 'birefringent', 'deuteride', 'orthoborate', 'van vleck paramagnet', 'mictomagnet', 'carbonate', 'phosphate', 'chevrel', 'gamma-brass', 'polaron conductor', 'nasicon', 'luminescent', 'tungstate', 'arsenate', 'nitrate', 'radioactive' ]; // NB pyrite-marcasite, pyroelectric, clathrate, heavy fermion etc. + static most_frequent_classes = [ 'metal', 'oxide', 'conductor', 'nonmetal', 'antiferromagnet', 'semiconductor', 'perovskite', 'sulfide', 'paramagnet', 'ab initio literature', 'hydrate', 'chloride', 'spinel', 'fluorite', 'orthophosphate', 'silicate', 'machine learning', 'ab initio calculations' ]; + + static most_frequent_props = [ 'magnetism', 'crystal structure', 'electronic properties', 'mechanical properties', 'thermodynamics', 'phase transitions', 'optical properties', 'superconductivity', 'enthalpy of formation', 'heat capacity', 'thermal expansion', 'Seebeck coefficient' ]; // TODO cell parameters + + static most_frequent_lats = [ 'cubic', 'tetragonal', 'orthorhombic', 'monoclinic' ]; + static most_frequent_formulae = [ 'Ag2S', 'Ag2Se', 'Ag2Te', 'Ag3Sn', 'AgBr', 'AgCe', 'AgCl', 'AgCu4Yb', 'AgGaS2', 'AgGaSe2', 'AgI', 'AgYbGe', 'Al2O3', 'Al4C3', 'AlAs', 'AlF3', 'AlN', 'AlP', 'AlSb', 'Al[PO4]', 'As2S3', 'As2Se3', 'As2Te3', 'AsS', 'AuSn', 'AuTe2', 'B13C2', 'Ba2Cu2YFeO7', 'Ba2Cu3DyO7', 'Ba2Cu3ErO7', 'Ba2Cu3EuO7', 'Ba2Cu3GdO7', 'Ba2Cu3HoO7', 'Ba2Cu3LaO7', 'Ba2Cu3NdO7', 'Ba2Cu3PrO7', 'Ba2Cu3SmO7', 'Ba2Cu3TmO7', 'Ba2Cu3YO6', 'Ba2Cu3YO7', 'Ba2Cu3YbO7', 'Ba2Cu4YO8', 'Ba2CuTl2O6', 'Ba2MoFeO6', 'Ba4Ga8Ge15', 'Ba4Ga8Sn15', 'BaBiO3', 'BaCl2', 'BaF2', 'BaFe12O19', 'BaFe2As2', 'BaIrO3', 'BaLaMn2O6', 'BaMnF4', 'BaO', 'BaPbO3', 'BaRuO3', 'BaTiO3', 'BaVS3', 'BaYCo4O7', 'BaZrO3', 'Be13U', 'BeO', 'Bi2O3', 'Bi2S3', 'Bi2Se3', 'Bi2Te3', 'C60', 'Ca2ReFeO6', 'Ca2RuO4', 'Ca3Co2O6', 'Ca3Co4O9', 'CaAl2', 'CaAlSi', 'CaCu3Ti4O12', 'CaF2', 'CaFe2As2', 'CaIrO3', 'CaMnO3', 'CaO', 'CaRuO3', 'CaS', 'CaSi2', 'CaTiO3', 'Ca[CO3]', 'Ca[WO4]', 'Cd2Nb2O7', 'Cd3As2', 'CdAs2', 'CdCr2S4', 'CdCr2Se4', 'CdF2', 'CdI2', 'CdO', 'CdS', 'CdSb', 'CdSe', 'CdTe', 'Ce2Fe17', 'Ce3Al11', 'Ce3Sn', 'CeAl2', 'CeAl3', 'CeB6', 'CeBi', 'CeCo2', 'CeCo5', 'CeCoGe3', 'CeCoIn5', 'CeFe2', 'CeFe4Sb12', 'CeIn3', 'CeIrSi3', 'CeMn2Si2', 'CeNi', 'CeNi2Ge2', 'CeNi2Si2', 'CeNi2Sn2', 'CeNiGe2', 'CeNiSn', 'CeO2', 'CeP', 'CePd2Al3', 'CePd2Si2', 'CePd3', 'CePdSn', 'CePt2Si2', 'CePt3Si', 'CePtSn', 'CeRh2Si2', 'CeRh3B2', 'CeRhAs', 'CeRhGe', 'CeRhIn5', 'CeRhSb', 'CeRhSn', 'CeRu2', 'CeRu2Ge2', 'CeRu2Si2', 'CeRuRhSi2', 'CeSb', 'CeSi2', 'Co2Al9', 'Co2B', 'Co2Si', 'Co3O4', 'Co3[VO4]2', 'CoAl', 'CoGa', 'CoO', 'CoPt', 'CoS2', 'CoSb3', 'CoSi', 'CoSi2', 'Cr23C6', 'Cr2FeS4', 'Cr2O3', 'Cr2S3', 'Cr3C2', 'Cr3Si', 'Cr7Al45', 'Cr7C3', 'CrAs', 'CrB2', 'CrN', 'CrO2', 'CrSi2', 'CrTe', 'Cs2ZnI4', 'CsBr', 'CsC8', 'CsCl', 'CsI', 'Cu2Ce', 'Cu2CeSi2', 'Cu2GdSi2', 'Cu2Nd', 'Cu2O', 'Cu2S', 'Cu2Se', 'Cu2Te', 'Cu2UGe2', 'Cu2USi2', 'Cu2Y', 'Cu2Y2O5', 'Cu2YbSi2', 'Cu2ZnSnS4', 'Cu33Al17', 'Cu3As', 'Cu3Au', 'Cu3Sb', 'Cu3Sn', 'Cu41Sn11', 'Cu4CeAl', 'Cu4YbIn', 'Cu5U', 'Cu5Zn8', 'Cu6Ce', 'Cu9Al4', 'CuAl', 'CuAl2', 'CuAu', 'CuBr', 'CuCl', 'CuCr2Se4', 'CuCrO2', 'CuFe2O4', 'CuFeO2', 'CuGaS2', 'CuGaSe2', 'CuGd2O4', 'CuGeO3', 'CuI', 'CuInS2', 'CuInSe2', 'CuInTe2', 'CuIr2S4', 'CuLa2O4', 'CuNd2O4', 'CuO', 'CuPr2O4', 'CuS', 'CuTi2', 'CuV2S4', 'CuZn', 'Dy2Fe14B', 'Dy2Fe17', 'DyAl2', 'DyCo2', 'DyFe2', 'DyFe4Al8', 'DyMn2', 'DyMn2O5', 'DyMo2Fe10', 'DyTiFe11', 'Dy[VO4]', 'Er2Fe14B', 'Er2Fe17', 'Er2Fe17C3', 'Er5Si4', 'ErAl2', 'ErCo2', 'ErFe2', 'ErFeO3', 'ErMn2O5', 'ErNi2B2C', 'ErRh4B4', 'ErTiFe11', 'Eu2O3', 'Eu4Ga8Ge15', 'EuB6', 'EuFe2As2', 'EuFe4Sb12', 'EuMo6S8', 'EuO', 'EuS', 'EuSe', 'EuTe', 'Fe2As', 'Fe2B', 'Fe2CoO4', 'Fe2NiO4', 'Fe2O3', 'Fe2P', 'Fe3Al', 'Fe3C', 'Fe3Ga', 'Fe3O4', 'Fe3P', 'Fe3Si', 'Fe4Al13', 'Fe4N', 'Fe5Si3', 'FeAl', 'FeAs', 'FeB', 'FeBiO3', 'FeCl2', 'FeCo', 'FeCo2Si', 'FeGaO3', 'FeGe', 'FeGe2', 'FeNi3', 'FeO', 'FeP', 'FePt3', 'FeRh', 'FeS', 'FeS2', 'FeSb2', 'FeSe', 'FeSi', 'FeSi2', 'Ga2O3', 'GaAs', 'GaN', 'GaP', 'GaS', 'GaSb', 'GaSe', 'GaTe', 'Ga[PO4]', 'Gd2Fe14B', 'Gd2Fe17', 'Gd2O3', 'Gd2[MoO4]3', 'Gd3Co', 'Gd5Ge4', 'GdAl2', 'GdB6', 'GdCo2', 'GdCo5', 'GdFe2', 'GdFe3[BO3]4', 'GdMn2', 'GdMn2Ge2', 'GdMnO3', 'GdN', 'GdNi2', 'GdSi2', 'GdTiFe11', 'GeO2', 'GeS', 'GeSe', 'GeSe2', 'GeTe', 'H2', 'H2Cs[PO4]', 'H2K[PO4]', 'H2O', 'H2Rb[PO4]', 'H3Na[SeO3]2', 'HK[CO3]', 'HfB2', 'HfC', 'HfO2', 'HgCr2S4', 'HgCr2Se4', 'HgI2', 'HgS', 'HgSe', 'HgTe', 'Ho2Fe14B', 'HoAl2', 'HoCo2', 'HoFe2', 'HoMn2O5', 'HoMnO3', 'HoNi2', 'HoNi2B2C', 'In2O3', 'In2S3', 'In2Se3', 'InAs', 'InBi', 'InN', 'InP', 'InSb', 'InSe', 'InTe', 'K2[SeO4]', 'K3Mo10O30', 'K3Na[SeO4]2', 'K3[C60]', 'KBr', 'KC24', 'KC8', 'KCl', 'KLi[SO4]', 'KMnF3', 'KNbO3', 'KOs2O6', 'KTaO3', 'KTi[PO4]O', 'K[CN]', 'La2NiO4', 'La2O3', 'La3Ga5SiO14', 'La3S4', 'LaAl2', 'LaAlO3', 'LaB6', 'LaCoO3', 'LaCrO3', 'LaF3', 'LaFe11Si2', 'LaFe4Sb12', 'LaFeAsO', 'LaFeO3', 'LaGaO3', 'LaH3', 'LaMn2Ge2', 'LaMnO3', 'LaNi5', 'LaNiO3', 'LaTiO3', 'LaVO3', 'Li2Pd3B', 'Li2S', 'Li3N', 'LiAl', 'LiBr', 'LiCl', 'LiCoO2', 'LiF', 'LiFe[PO4]', 'LiH', 'LiMn2O4', 'LiNbO3', 'LiNiO2', 'LiTaO3', 'LiTi2O4', 'LiV2O5', 'LiVO2', 'LiYF4', 'Lu2Fe17', 'Lu5Ir4Si10', 'LuNi2B2C', 'Mg17Al12', 'Mg24Y5', 'Mg28Al45', 'Mg2Si', 'Mg2Sn', 'Mg2TiO4', 'Mg2[SiO4]', 'MgAl2O4', 'MgB2', 'MgCu2', 'MgF2', 'MgFe2O4', 'MgFeAlO4', 'MgFe[SiO4]', 'MgO', 'MgSiO3', 'MgZn2', 'Mn11Al15', 'Mn3C', 'Mn3O4', 'Mn5Si3', 'MnAl6', 'MnAs', 'MnBi', 'MnF2', 'MnFe2O4', 'MnNi2Ga', 'MnNi2In', 'MnNi2Sb', 'MnNi2Sn', 'MnNiSb', 'MnO', 'MnO2', 'MnP', 'MnS', 'MnSi', 'MnTe', 'Mo2S3', 'Mo3Al8', 'Mo4O11', 'Mo6PbS8', 'Mo7Ni7', 'MoB2', 'MoO3', 'MoS2', 'MoSi2', 'NaBr', 'NaCl', 'NaF', 'NaI', 'NaNbO3', 'Na[NO2]', 'Na[NO3]', 'Nb2Al', 'Nb3FeSe6', 'Nb3Ge', 'Nb3Si', 'Nb3Sn', 'Nb5Si3', 'Nb7Ni6', 'NbAl3', 'NbB2', 'NbC', 'NbCr2', 'NbFe2', 'NbH', 'NbN', 'NbNi3', 'NbO2', 'NbSe2', 'NbSe3', 'NbSi2', 'Nd2Co14B', 'Nd2Fe13CoB', 'Nd2Fe14B', 'Nd2Fe17', 'Nd2O3', 'Nd6Fe11Al3', 'NdAl2', 'NdB6', 'NdCo2', 'NdCo5', 'NdFeAsO', 'NdFeO3', 'NdMn2Ge2', 'NdMnFeGe2', 'NdMnO3', 'NdMo2Fe10', 'NdNiO3', 'NdTiFe11', 'NdTiO3', 'NdV2Fe10', 'Ni2Al3', 'Ni2B', 'Ni2Si', 'Ni31Si12', 'Ni3Al', 'Ni3B', 'Ni3Si', 'Ni3[VO4]2', 'Ni4B3', 'NiAl', 'NiAl3', 'NiO', 'NiS', 'NiS2', 'NiSb', 'NiSi', 'NiSi2', 'NpPd5Al2', 'O2', 'PbF2', 'PbI2', 'PbO', 'PbO2', 'PbS', 'PbSe', 'PbTe', 'Pb[WO4]', 'Pd2Si', 'PdAl', 'PdH', 'Pr2Fe14B', 'Pr2O3', 'PrAl2', 'PrB6', 'PrCo5', 'PrFe2Ge2', 'PrFe4P12', 'PrFeAsO', 'PrMn2Ge2', 'PrMnO3', 'PrNi2Si2', 'PrNi5', 'PrOs4Sb12', 'Rb2ZnBr4', 'Rb2ZnCl4', 'Rb3[C60]', 'RbBr', 'RbCl', 'RbF', 'RbI', 'RbLi[SO4]', 'Rb[C60]', 'ReO3', 'RuAl2', 'Sb2S3', 'Sb2Se3', 'Sb2Te3', 'SbSI', 'Sc2[WO4]3', 'ScAl3', 'Si3N4', 'SiC', 'SiO2', 'Sm2Co17', 'Sm2Fe17', 'Sm2Fe17N3', 'Sm2O3', 'SmB6', 'SmCo5', 'SmFeAsO', 'SmMn2Ge2', 'SmS', 'SmTiFe11', 'SnO2', 'SnS', 'SnS2', 'SnSe', 'SnSe2', 'SnTe', 'Sr14Cu24O41', 'Sr2CuBi2O6', 'Sr2LaMn2O7', 'Sr2MoFeO6', 'Sr2RuO4', 'SrAl4', 'SrCoO3', 'SrCuLaO4', 'SrF2', 'SrFe12O19', 'SrFe2As2', 'SrFeO3', 'SrLaMnO4', 'SrLaNiO4', 'SrMnO3', 'SrNb2Bi2O9', 'SrO', 'SrRuO3', 'SrTa2Bi2O9', 'SrTiO3', 'SrZrO3', 'TaC', 'TaS2', 'TaS3', 'TaSe2', 'Tb3Fe5O12', 'TbFe2', 'TbMn2', 'TbMn2O5', 'TbMnO3', 'TbNi2Si2', 'TbRh2Si2', 'TbTiFe11', 'TeO2', 'ThO2', 'Ti2Ni', 'Ti2O3', 'Ti3Al', 'Ti3Bi4O12', 'Ti5Si3', 'TiAl', 'TiAl2', 'TiAl3', 'TiB2', 'TiC', 'TiCo', 'TiCo2Al', 'TiCo2Sn', 'TiCoSb', 'TiCr2', 'TiFe', 'TiFe2', 'TiFeO3', 'TiH2', 'TiN', 'TiNi', 'TiNi3', 'TiO', 'TiO2', 'TiPbO3', 'TiS2', 'TiSe2', 'TiSi2', 'TiVO3', 'Tl2S', 'Tl5Se3', 'Tl5Te3', 'TlBr', 'TlCl', 'TlGaSe2', 'TlI', 'TlInS2', 'TlS', 'TlSe', 'TlTe', 'Tm2Fe14B', 'TmSe', 'TmTe', 'U2C3', 'U2Ni2Sn', 'U2Pt2In', 'U6Fe', 'UAl2', 'UAs', 'UC2', 'UCo2Ge2', 'UCoAl', 'UFe10Si2', 'UFe2', 'UFe4Al8', 'UGe2', 'UMn2', 'UNi2Al3', 'UNiAl', 'UNiGa', 'UNiSn', 'UO2', 'UPd2Al3', 'UPd3', 'UPdSn', 'UPt3', 'UPtGe', 'URu2Si2', 'USb', 'UTe', 'V2MnO4', 'V2O3', 'V2O5', 'V3Ga', 'V3Ge', 'V3O5', 'V3Si', 'V4O7', 'V5Al8', 'V5O9', 'V6O11', 'V6O13', 'V7O13', 'VAl3', 'VFe2Al', 'VO2', 'VSe2', 'W2C', 'WBi2O6', 'WMnO4', 'WO3', 'WSi2', 'Y2Co17', 'Y2Fe14B', 'Y2Fe17', 'Y2O3', 'Y3Al5O12', 'Y3Fe5O12', 'YAl2', 'YAl3', 'YB6', 'YCo2', 'YCo3', 'YCo4B', 'YCo5', 'YFe2', 'YFe4Al8', 'YH3', 'YMn2', 'YMnO3', 'YMo2Fe10', 'YNi2B2C', 'YTiFe11', 'YTiO3', 'YV2Fe10', 'YVO3', 'Yb2O3', 'Yb4As3', 'YbAl3', 'YbFe4Sb12', 'YbMnO3', 'YbRh2Si2', 'Zn10Fe3', 'Zn2Zr', 'Zn3As2', 'Zn3P2', 'ZnCr2O4', 'ZnCr2Se4', 'ZnF2', 'ZnFe2O4', 'ZnGeP2', 'ZnO', 'ZnS', 'ZnSe', 'ZnSiP2', 'ZnTe', 'Zr2Ni', 'ZrAl2', 'ZrAl3', 'ZrB2', 'ZrC', 'ZrCo2', 'ZrCr2', 'ZrFe2', 'ZrMn2', 'ZrMo2', 'ZrN', 'ZrNiSn', 'ZrO2', 'ZrPbO3', 'ZrV2', 'Zr[WO4]2', '[NH4]2ZnCl4' ]; + + static most_frequent_anonymous = [ 'AB', 'AB2', 'ABC3', 'ABC', 'ABC2', 'ABCD3', 'AB3', 'AB2C4', 'AB2C2', 'ABC4', 'ABC2D6', 'ABCD4', 'A2B3', 'ABC2D4', 'ABCD', 'ABCD2', 'AB2C3', 'AB2C6', 'AB2C5', 'AB2C3D7', 'A3B4', 'A3B5', 'ABC2D2', 'A2B2C7', 'AB3C5', 'ABC2D5', 'ABC2D7', 'AB5', 'AB3C6', 'AB3C4', 'ABC5', 'ABC2D8', 'AB3C3', 'AB4', 'AB6', 'AB2C2D7', 'AB4C12', 'A2B17', 'AB3C4D12', 'ABCD5', 'ABCD6', 'A2B3C4', 'ABC3D7', 'A2B3C5', 'AB2C10', 'A2B2C5', 'AB2C2D6', 'AB2C3D8', 'AB2C8', 'ABC2D3', 'A2B5', 'AB2C3D6', 'AB4C8', 'ABC6', 'AB2C2D8', 'AB6C6', 'AB3C7', 'A4B5' ]; + + /* + * Utilities: + */ + static get_random_term( sequence: number[] | string[] ) + { + return sequence[ Math.floor( Math.random() * sequence.length ) ] + } + static get_realistic( facet: string, cur_arity: number = 0 ): string + { + var term + if( facet == 'elements' ) + { + var i = 0, + els = [], + prob_arity = [ 2, 3 ], // 4 is improbable + cur_arity = cur_arity || ( this.get_random_term( prob_arity ) as number ) + while( i < cur_arity! ) + { + var el + if( i < 2 ) + el = this.get_random_term( this.probable_els ) + else + el = this.get_random_term( this.most_frequent_els ) + if( els.indexOf( el ) > -1 ) continue + els.push( el ) + i++ + } + term = els.join( '-' ) + + } else if( facet == 'formulae' ) + { + term = this.get_random_term( this.most_frequent_formulae ) + + } else if( facet == 'anonymous' ) + { + term = this.get_random_term( this.most_frequent_anonymous ) + + } else if( facet == 'props' ) + { + term = this.get_random_term( this.most_frequent_props ) + + } else if( facet == 'classes' ) + { + term = this.get_random_term( this.classes_families ) + + } else if( facet == 'lattices' ) + { + term = this.get_random_term( this.most_frequent_lats ) + + } else return this.get_realistic( [ 'elements', 'formulae', 'props', 'classes', 'lattices' ][ Math.floor( Math.random() * 5 ) ] ) + + return term as string + } + + static generate_example( scene: number | string = 0 ) + { + var scenarios = [ 1, 2, 3, 4, 5, 6, 7, 8 ], + scene = scene || this.get_random_term( scenarios ), + result = { 'text': '', 'terms': [], 'facets': [] } as { text: string, terms: string[], facets: string[] } + + if( scene == 1 ) + { // classes-elements, 4% fails + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'classes', 'elements' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_random_term( this.most_frequent_classes ) as string, this.get_realistic( 'elements', 2 ) as string ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ' ' + result[ 'terms' ][ 1 ] + + } else if( scene == 2 ) + { // classes-classes, 4.5% fails + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'classes', 'classes' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_random_term( this.classes_groups ) as string, this.get_realistic( 'classes' ) as string ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ' group, ' + result[ 'terms' ][ 1 ] + + } else if( scene == 3 ) + { // formulae-lattices, 1% fails + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'formulae', 'lattices' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'formulae' ), this.get_realistic( 'lattices' ) ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ' ' + result[ 'terms' ][ 1 ] + ' crystal' + + } else if( scene == 4 ) + { // props-classes, always correct + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'props', 'classes' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'props' ), this.get_realistic( 'classes' ) ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ' for ' + result[ 'terms' ][ 1 ] + if( !result[ 'text' ].endsWith( 'd' ) && !result[ 'text' ].endsWith( 's' ) ) + result[ 'text' ] += 's' + + } else if( scene == 5 ) + { // classes-lattices, 3% fails + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'classes', 'lattices' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'classes' ), this.get_realistic( 'lattices' ) ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ', ' + result[ 'terms' ][ 1 ] + ' crystal' + + } else if( scene == 6 ) + { // elements-lattices, 3% fails + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'elements', 'lattices' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'elements' ), this.get_realistic( 'lattices' ) ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ', ' + result[ 'terms' ][ 1 ] + ' crystal' + + } else if( scene == 7 ) + { // props and anonymous formulae + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'props', 'formulae' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'props' ), this.get_realistic( 'anonymous' ) ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ' ' + result[ 'terms' ][ 1 ] + + } else + { // props-formulae, 4% fails + result[ 'facets' ] = [ ...result[ 'facets' ], ...[ 'props', 'formulae' ] ] + result[ 'terms' ] = [ ...result[ 'terms' ], ...[ this.get_realistic( 'props' ), this.get_realistic( 'formulae' ) ] ] + result[ 'text' ] += result[ 'terms' ][ 0 ] + ' of ' + result[ 'terms' ][ 1 ] + } + return result + } + } +} diff --git a/optimade/zero/search/search.view.css b/optimade/zero/search/search.view.css new file mode 100644 index 0000000..62cc0ad --- /dev/null +++ b/optimade/zero/search/search.view.css @@ -0,0 +1,27 @@ +[optimade_zero_search_searcherexamplelink] { + text-overflow: ellipsis; +} +[optimade_zero_search_refinementshowmorelink] { + font-size: 0.8rem; + font-weight: 500; +} +[optimade_zero_search_searcheregright] { + display: flex; + align-items: center; + font-size: 0.8rem; +} +[optimade_zero_search_searchertitle] { + color: var(--mol_theme_shade); +} +[optimade_zero_search_searcherlabelrow] { + justify-content: space-between; + flex-wrap: nowrap; + padding-bottom: 0; + padding-top: 0; + align-items: center; +} +[optimade_zero_search_searchinputrow]{ + flex-wrap: nowrap; + padding-left: 0; + padding-right: 0; +} diff --git a/optimade/zero/search/search.view.css.ts b/optimade/zero/search/search.view.css.ts new file mode 100644 index 0000000..27ae572 --- /dev/null +++ b/optimade/zero/search/search.view.css.ts @@ -0,0 +1,84 @@ +namespace $.$$ +{ + const { vary } = $mol_style_func + + $mol_style_define( $optimade_zero_search, { + + + FacetSelectorLabeler: { + Content: { + flex: { + direction: 'column', + } + + + } + + }, + SearchPage: { + flex: { + basis: '400px', + }, + Body_content:{ + padding: { + left: 0, + right: 0, + } + } + }, + ResultsPage: { + flex: { + grow: 3, + }, + Body_content:{ + padding: { + left: 0, + right: 0, + } + } + }, + SearchInputRow: { + width: '100%', + }, + RefinementLabel: { + Content: { + flex: { + direction: 'column', + } + } + }, + SearchLabel: { + Content: { + flex: { + direction: 'column', + } + } + }, + FoundStr: { + font: { + size: '0.8rem', + weight: 500, + } + }, + SearchSubRow: { + margin: 0, + padding: 0, + }, + ShowResultsLink: { + font: { + size: '0.8rem', + weight: 500, + + }, + padding: 0 + }, + Results: { + display: 'grid', + gridTemplateColumns: 'repeat( auto-fit, minmax( 20rem, 1fr ) );', + }, + + + + + } ) +} diff --git a/optimade/zero/search/search.view.tree b/optimade/zero/search/search.view.tree new file mode 100644 index 0000000..d4d05e6 --- /dev/null +++ b/optimade/zero/search/search.view.tree @@ -0,0 +1,100 @@ +$optimade_zero_search $mol_book2 + api $optimade_zero_api + dd_addr_tpl => dd_addr_tpl + cdn_host => cdn_host + refs_endpoint => refs_endpoint + user_sid => user_sid + title <= page_title @ \Search page + pages <= visible_pages / + LoginPage $optimade_zero_profile + title @ \Login + tools / + <= Login_close_link $mol_link + arg * + show_login 0 + hint <= close_hint @ \Close page + sub / + <= Spread_close_icon $mol_icon_close + SearchPage $mol_page + title @ \Search + tools / + <= Spread_close null + body / + <= auto_url + <= SearchLabel $mol_labeler + Label <= SearcherLabelRow $mol_row + minimal_height 32 + sub /$mol_view_content + <= SearcherTitle $mol_view + sub / <= SearcherTitleInputText @ \Input: + <= SearcherEgRight $mol_view + sub /$mol_view_content + <= SearcherTitleEg @ \e.g. + <= SearcherExampleLink $mol_link + title <= example_link_title \ + current false + event_click*?event <=> example_link_click*?event null + content / + <= SearchInputRow $mol_row + sub / + <= Words $mol_search + hint \Type property, elements, classes + query? <=> word? \ + suggests <= suggests / + suggest_select*?event <=> suggest_select*?event null + <= SearchButton $mol_button_major + title <= sblabel @ \Search + click? <=> search_click? null + <= SearchSubRow $mol_row + sub / + <= FoundStr $mol_paragraph + sub / + <= found_str @ \Items found: + <= found_count + <= ShowResultsLink $mol_link + title <= show_results_title @ \Show results + arg * + results 1 + <= ClassesPreselector $mol_check_list + options <= preselect_classes_options * + option_checked*? <=> preselect_classes_checked*? false + <= RefinementLabel $mol_labeler + title <= label2 @ \Data summary: + content <= facet_blocks /$mol_view_content + <= FacetSelectorLabeler*0 $mol_labeler + title <= facet_selector_label* \ + content /$mol_view_content + <= FacetSelector* $mol_check_list + options <= refinement_options* * + option_checked*? <=> facets_checked*? false + <= RefinementShowMoreLink*?next $mol_link + title <= show_more_title @ \Show more + event_click <= show_more_click* null + current false + foot / + <= ClearSearchButton $mol_button_minor + title <= clear_search_title @ \New search + click* <=> clear_search* null + <= ReloadButton $mol_button_minor + title <= reload_title @ \Reload search + click* <=> reset* null + ResultsPage $mol_page + title @ \Results + tools / + <= Spread_close_link $mol_link + arg * + results 0 + hint <= close_hint @ \Close page + sub / + <= Spread_close_icon $mol_icon_close + body / + <= Results $mol_row + sub <= result_items / + ResultItem* $optimade_zero_resultitem + data <= result_item* * + dd_addr_tpl <= dd_addr_tpl + cdn_host <= cdn_host + refs_endpoint <= refs_endpoint + user_sid <= user_sid + has_access <= user_sid + diff --git a/optimade/zero/search/search.view.ts b/optimade/zero/search/search.view.ts new file mode 100644 index 0000000..c48894e --- /dev/null +++ b/optimade/zero/search/search.view.ts @@ -0,0 +1,280 @@ +namespace $.$$ +{ + export class $optimade_zero_search extends $.$optimade_zero_search + { + @$mol_mem + auto_url(){ + if($mol_mem_cached(()=>this.auto_url()) === ''){ + return '' + } + this.preselect_search_facets(this.api().uri_to_facets()) + return '' + } + @$mol_mem + visible_pages() + { + const pages = $mol_state_arg.dict()[ 'results' ] ? [ this.SearchPage(), this.ResultsPage() ] : [ this.SearchPage() ] + if($mol_state_arg.dict()[ 'show_login' ] && !this.user_sid()){ + pages.push(this.LoginPage()) + } + return pages + } + @$mol_action + suggest_select( id: string, event?: MouseEvent ) + { + const facets = this.selectizes().filter( el => el.label === id ) + this.preselect_search_facets( [ ...this.preselect_search_facets(), ...facets ] ) + this.Words().suggests_showed( false ) + + this.word( '' ) + + } + @$mol_mem + suggests() + { + return this.selectizes().filter( el => !this.preselect_search_facets().some( el2 => el2.id === el.id ) ).map( el => el.label ) + } + @$mol_mem + selectizes() + { + this.reload_search() + this.$.$mol_wait_timeout( 200 ) + + return this.api().selectize( this.word() ).map( el => ({...el, label:el.label.replace(/<\/?(?:sup|sub)>/g, '')}) ) + } + + @$mol_action + search_click() + { + + if( !this.word() ) return + + const finded = this.api().string_to_facets( this.word() ) + delete finded[ 'ignored' ] + if( Object.keys( finded ).length ) + { + this.preselect_search_facets( this.api().facet_dict_to_array( finded ) ) + } + } + @$mol_mem + reload_search( next?: number ) + { + return next ?? Date.now() + } + @$mol_action + clear_search() + { + this.preselect_search_facets( [] ) + this.Words().bring() + } + @$mol_action + reset() + { + this.reload_search( Date.now() ) + } + + @$mol_mem + combined_facets() + { + const dict = this.api().facet_array_to_dict( this.preselect_search_facets() ) + for( const key in dict ) + { + dict[ key ] = dict[ key ].replaceAll( ', ', '-' ) + } + const old = $mol_mem_cached( () => this.combined_facets() ) + $mol_state_arg.dict() + if( old ) + { + + for( const key in old ) + { + $mol_state_arg.value( key, null ) + } + } + for( const key in dict ) + { + + $mol_state_arg.value( key, dict[ key ] ) + } + return dict + } + @$mol_mem + refinements() + { + this.reload_search() + this.$.$mol_wait_timeout( 200 ) + + const resp = this.api().refinement( this.combined_facets() ) + + return resp + + } + + @$mol_mem_key + override refinement_options( id: string ) + { + const opts = {} as Record + this.facets_grouped()[ id ]?.map( ( el, index ) => opts[ `${ id }_${ el }` ] = el.charAt( 0 ).toUpperCase() + el.slice( 1 ) ) + return opts + } + + @$mol_mem_key + override facet_selector_label( el: string ) + { + return this.api().query_params[ el ] + } + + @$mol_mem + facets_grouped(next?: Record): Record + { + if(next){ + return next + } + + const resp = this.refinements() + + if(resp.error) + { + throw new Error( resp.error ) + } + if( Object.keys( this.preselect_classes_options() ).length ) + { + const groups = {} as Record + resp.payload.map( el => groups[ el.facet ] ? groups[ el.facet ].push( el.value ) : groups[ el.facet ] = [ el.value ] ) + + + return groups + + } + else + { + return {} + } + + } + + @$mol_mem + override facet_blocks() + { + + return Object.keys( this.facets_grouped() ).map( ( val ) => + { + return this.FacetSelectorLabeler( val ) + } ) + } + @$mol_mem + found_count() + { + return this.results().length + } + @$mol_mem_key + override preselect_classes_checked( id: string, next?: any ) + { + + if( next === false ) + { + const facetIndex = this.preselect_search_facets().findIndex( el => `${ el.facet }_${ el.label }` === id ) + const spl = [ ...this.preselect_search_facets() ] + spl.splice( facetIndex, 1 ) + this.preselect_search_facets( spl ) + return next + } + return true + } + @$mol_mem_key + override facets_checked( id: string, next?: any ) + { + + if( next === true ) + { + const [ key, val ] = id.split( '_' ) + const facet = { facet: key, label: val, id: '' } + const spl = [ ...this.preselect_search_facets(), facet ] + this.preselect_search_facets( spl ) + + } + return this.preselect_classes_options()[ id ] ? this.preselect_classes_checked( id, next ) : false + } + @$mol_mem + result_items() + { + this.$.$mol_wait_timeout( 500 ) + return this.results().map( ( el, index ) => this.ResultItem( index ) ) + } + @$mol_mem_key + result_item( index?: number ) + { + return this.results()[ index! ] ?? {} + } + @$mol_mem + results() + { + this.reload_search() + this.$.$mol_wait_timeout( 200 ) + const response = this.api().results( this.combined_facets() ) + return response.out ?? [] + + + } + + @$mol_mem + preselect_search_facets( next?: $optimade_zero_api_Facet[] ) + { + + return next ?? [] + } + @$mol_mem + override preselect_classes_options() + { + + const result = { + } as Record + + this.preselect_search_facets().map( el => + { + const label = el.label + result[ `${ el.facet }_${ label }` ] = label + } ) + return result + } + @$mol_mem + example_link_title(){ + + return this.example_generated().text + } + @$mol_mem + example_generated(){ + $mol_state_time.now(4000) + return $optimade_zero_search_helper.generate_example() + } + @$mol_action + example_link_click(){ + const facets = [] as $optimade_zero_api_Facet[] + for (let index = 0; index < this.example_generated().facets.length; index++) { + const facet = this.example_generated().facets[index]; + facets.push({ + facet: facet, + label: this.example_generated().terms[index] + }) + } + this.preselect_search_facets(facets) + } + @$mol_action + show_more_click(id: string){ + + const facets = this.combined_facets() + facets['extd_refine'] = id + const resp = this.api().refinement(facets) + if(!resp.error && resp.payload.length){ + const groups = {...this.facets_grouped(),[id]:[...this.facets_grouped()[id],...(resp.payload as any[]).map(el=>el[0])]} + + this.facets_grouped(groups) + + } + this.RefinementShowMoreLink(id, null as unknown as undefined) + } + + + + } +} diff --git a/readme b/readme new file mode 100644 index 0000000..91e5314 --- /dev/null +++ b/readme @@ -0,0 +1,4 @@ +contest app +telegram @soundrmx +desktop usage video https://drive.google.com/file/d/1MUHfX4wWMaCNvVTnEg845Yt7Dg89P8rj/view?usp=sharing +PWA APP https://azero.milkyway-studio.ru/ \ No newline at end of file diff --git a/selectize.js b/selectize.js deleted file mode 100644 index 39ebad5..0000000 --- a/selectize.js +++ /dev/null @@ -1,3684 +0,0 @@ -/** - * sifter.js - * Copyright (c) 2013 Brian Reavis & contributors - * - * 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. - * - * @author Brian Reavis - */ - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define('sifter', factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.Sifter = factory(); - } -}(this, function() { - - /** - * Textually searches arrays and hashes of objects - * by property (or multiple properties). Designed - * specifically for autocomplete. - * - * @constructor - * @param {array|object} items - * @param {object} items - */ - var Sifter = function(items, settings) { - this.items = items; - this.settings = settings || {diacritics: true}; - }; - - /** - * Splits a search string into an array of individual - * regexps to be used to match results. - * - * @param {string} query - * @returns {array} - */ - Sifter.prototype.tokenize = function(query) { - query = trim(String(query || '').toLowerCase()); - if (!query || !query.length) return []; - - var i, n, regex, letter; - var tokens = []; - var words = query.split(/ +/); - - for (i = 0, n = words.length; i < n; i++) { - regex = escape_regex(words[i]); - if (this.settings.diacritics) { - for (letter in DIACRITICS) { - if (DIACRITICS.hasOwnProperty(letter)) { - regex = regex.replace(new RegExp(letter, 'g'), DIACRITICS[letter]); - } - } - } - tokens.push({ - string : words[i], - regex : new RegExp(regex, 'i') - }); - } - - return tokens; - }; - - /** - * Iterates over arrays and hashes. - * - * ``` - * this.iterator(this.items, function(item, id) { - * // invoked for each item - * }); - * ``` - * - * @param {array|object} object - */ - Sifter.prototype.iterator = function(object, callback) { - var iterator; - if (is_array(object)) { - iterator = Array.prototype.forEach || function(callback) { - for (var i = 0, n = this.length; i < n; i++) { - callback(this[i], i, this); - } - }; - } else { - iterator = function(callback) { - for (var key in this) { - if (this.hasOwnProperty(key)) { - callback(this[key], key, this); - } - } - }; - } - - iterator.apply(object, [callback]); - }; - - /** - * Returns a function to be used to score individual results. - * - * Good matches will have a higher score than poor matches. - * If an item is not a match, 0 will be returned by the function. - * - * @param {object|string} search - * @param {object} options (optional) - * @returns {function} - */ - Sifter.prototype.getScoreFunction = function(search, options) { - var self, fields, tokens, token_count, nesting; - - self = this; - search = self.prepareSearch(search, options); - tokens = search.tokens; - fields = search.options.fields; - token_count = tokens.length; - nesting = search.options.nesting; - - /** - * Calculates how close of a match the - * given value is against a search token. - * - * @param {mixed} value - * @param {object} token - * @return {number} - */ - var scoreValue = function(value, token) { - var score, pos; - - if (!value) return 0; - value = String(value || ''); - pos = value.search(token.regex); - if (pos === -1) return 0; - score = token.string.length / value.length; - if (pos === 0) score += 0.5; - return score; - }; - - /** - * Calculates the score of an object - * against the search query. - * - * @param {object} token - * @param {object} data - * @return {number} - */ - var scoreObject = (function() { - var field_count = fields.length; - if (!field_count) { - return function() { return 0; }; - } - if (field_count === 1) { - return function(token, data) { - return scoreValue(getattr(data, fields[0], nesting), token); - }; - } - return function(token, data) { - for (var i = 0, sum = 0; i < field_count; i++) { - sum += scoreValue(getattr(data, fields[i], nesting), token); - } - return sum / field_count; - }; - })(); - - if (!token_count) { - return function() { return 0; }; - } - if (token_count === 1) { - return function(data) { - return scoreObject(tokens[0], data); - }; - } - - if (search.options.conjunction === 'and') { - return function(data) { - var score; - for (var i = 0, sum = 0; i < token_count; i++) { - score = scoreObject(tokens[i], data); - if (score <= 0) return 0; - sum += score; - } - return sum / token_count; - }; - } else { - return function(data) { - for (var i = 0, sum = 0; i < token_count; i++) { - sum += scoreObject(tokens[i], data); - } - return sum / token_count; - }; - } - }; - - /** - * Returns a function that can be used to compare two - * results, for sorting purposes. If no sorting should - * be performed, `null` will be returned. - * - * @param {string|object} search - * @param {object} options - * @return function(a,b) - */ - Sifter.prototype.getSortFunction = function(search, options) { - var i, n, self, field, fields, fields_count, multiplier, multipliers, get_field, implicit_score, sort; - - self = this; - search = self.prepareSearch(search, options); - sort = (!search.query && options.sort_empty) || options.sort; - - /** - * Fetches the specified sort field value - * from a search result item. - * - * @param {string} name - * @param {object} result - * @return {mixed} - */ - get_field = function(name, result) { - if (name === '$score') return result.score; - return getattr(self.items[result.id], name, options.nesting); - }; - - // parse options - fields = []; - if (sort) { - for (i = 0, n = sort.length; i < n; i++) { - if (search.query || sort[i].field !== '$score') { - fields.push(sort[i]); - } - } - } - - // the "$score" field is implied to be the primary - // sort field, unless it's manually specified - if (search.query) { - implicit_score = true; - for (i = 0, n = fields.length; i < n; i++) { - if (fields[i].field === '$score') { - implicit_score = false; - break; - } - } - if (implicit_score) { - fields.unshift({field: '$score', direction: 'desc'}); - } - } else { - for (i = 0, n = fields.length; i < n; i++) { - if (fields[i].field === '$score') { - fields.splice(i, 1); - break; - } - } - } - - multipliers = []; - for (i = 0, n = fields.length; i < n; i++) { - multipliers.push(fields[i].direction === 'desc' ? -1 : 1); - } - - // build function - fields_count = fields.length; - if (!fields_count) { - return null; - } else if (fields_count === 1) { - field = fields[0].field; - multiplier = multipliers[0]; - return function(a, b) { - return multiplier * cmp( - get_field(field, a), - get_field(field, b) - ); - }; - } else { - return function(a, b) { - var i, result, a_value, b_value, field; - for (i = 0; i < fields_count; i++) { - field = fields[i].field; - result = multipliers[i] * cmp( - get_field(field, a), - get_field(field, b) - ); - if (result) return result; - } - return 0; - }; - } - }; - - /** - * Parses a search query and returns an object - * with tokens and fields ready to be populated - * with results. - * - * @param {string} query - * @param {object} options - * @returns {object} - */ - Sifter.prototype.prepareSearch = function(query, options) { - if (typeof query === 'object') return query; - - options = extend({}, options); - - var option_fields = options.fields; - var option_sort = options.sort; - var option_sort_empty = options.sort_empty; - - if (option_fields && !is_array(option_fields)) options.fields = [option_fields]; - if (option_sort && !is_array(option_sort)) options.sort = [option_sort]; - if (option_sort_empty && !is_array(option_sort_empty)) options.sort_empty = [option_sort_empty]; - - return { - options : options, - query : String(query || '').toLowerCase(), - tokens : this.tokenize(query), - total : 0, - items : [] - }; - }; - - /** - * Searches through all items and returns a sorted array of matches. - * - * The `options` parameter can contain: - * - * - fields {string|array} - * - sort {array} - * - score {function} - * - filter {bool} - * - limit {integer} - * - * Returns an object containing: - * - * - options {object} - * - query {string} - * - tokens {array} - * - total {int} - * - items {array} - * - * @param {string} query - * @param {object} options - * @returns {object} - */ - Sifter.prototype.search = function(query, options) { - var self = this, value, score, search, calculateScore; - var fn_sort; - var fn_score; - - search = this.prepareSearch(query, options); - options = search.options; - query = search.query; - - // generate result scoring function - fn_score = options.score || self.getScoreFunction(search); - - // perform search and sort - if (query.length) { - self.iterator(self.items, function(item, id) { - score = fn_score(item); - if (options.filter === false || score > 0) { - search.items.push({'score': score, 'id': id}); - } - }); - } else { - self.iterator(self.items, function(item, id) { - search.items.push({'score': 1, 'id': id}); - }); - } - - fn_sort = self.getSortFunction(search, options); - if (fn_sort) search.items.sort(fn_sort); - - // apply limits - search.total = search.items.length; - if (typeof options.limit === 'number') { - search.items = search.items.slice(0, options.limit); - } - - return search; - }; - - // utilities - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - var cmp = function(a, b) { - if (typeof a === 'number' && typeof b === 'number') { - return a > b ? 1 : (a < b ? -1 : 0); - } - a = asciifold(String(a || '')); - b = asciifold(String(b || '')); - if (a > b) return 1; - if (b > a) return -1; - return 0; - }; - - var extend = function(a, b) { - var i, n, k, object; - for (i = 1, n = arguments.length; i < n; i++) { - object = arguments[i]; - if (!object) continue; - for (k in object) { - if (object.hasOwnProperty(k)) { - a[k] = object[k]; - } - } - } - return a; - }; - - /** - * A property getter resolving dot-notation - * @param {Object} obj The root object to fetch property on - * @param {String} name The optionally dotted property name to fetch - * @param {Boolean} nesting Handle nesting or not - * @return {Object} The resolved property value - */ - var getattr = function(obj, name, nesting) { - if (!obj || !name) return; - if (!nesting) return obj[name]; - var names = name.split("."); - while(names.length && (obj = obj[names.shift()])); - return obj; - }; - - var trim = function(str) { - return (str + '').replace(/^\s+|\s+$|/g, ''); - }; - - var escape_regex = function(str) { - return (str + '').replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); - }; - - var is_array = Array.isArray || (typeof $ !== 'undefined' && $.isArray) || function(object) { - return Object.prototype.toString.call(object) === '[object Array]'; - }; - - var DIACRITICS = { - 'a': '[aḀḁĂăÂâǍǎȺⱥȦȧẠạÄäÀàÁáĀāÃãÅåąĄÃąĄ]', - 'b': '[b␢βΒB฿𐌁ᛒ]', - 'c': '[cĆćĈĉČčĊċC̄c̄ÇçḈḉȻȼƇƈɕᴄCc]', - 'd': '[dĎďḊḋḐḑḌḍḒḓḎḏĐđD̦d̦ƉɖƊɗƋƌᵭᶁᶑȡᴅDdð]', - 'e': '[eÉéÈèÊêḘḙĚěĔĕẼẽḚḛẺẻĖėËëĒēȨȩĘęᶒɆɇȄȅẾếỀềỄễỂểḜḝḖḗḔḕȆȇẸẹỆệⱸᴇEeɘǝƏƐε]', - 'f': '[fƑƒḞḟ]', - 'g': '[gɢ₲ǤǥĜĝĞğĢģƓɠĠġ]', - 'h': '[hĤĥĦħḨḩẖẖḤḥḢḣɦʰǶƕ]', - 'i': '[iÍíÌìĬĭÎîǏǐÏïḮḯĨĩĮįĪīỈỉȈȉȊȋỊịḬḭƗɨɨ̆ᵻᶖİiIıɪIi]', - 'j': '[jȷĴĵɈɉʝɟʲ]', - 'k': '[kƘƙꝀꝁḰḱǨǩḲḳḴḵκϰ₭]', - 'l': '[lŁłĽľĻļĹĺḶḷḸḹḼḽḺḻĿŀȽƚⱠⱡⱢɫɬᶅɭȴʟLl]', - 'n': '[nŃńǸǹŇňÑñṄṅŅņṆṇṊṋṈṉN̈n̈ƝɲȠƞᵰᶇɳȵɴNnŊŋ]', - 'o': '[oØøÖöÓóÒòÔôǑǒŐőŎŏȮȯỌọƟɵƠơỎỏŌōÕõǪǫȌȍՕօ]', - 'p': '[pṔṕṖṗⱣᵽƤƥᵱ]', - 'q': '[qꝖꝗʠɊɋꝘꝙq̃]', - 'r': '[rŔŕɌɍŘřŖŗṘṙȐȑȒȓṚṛⱤɽ]', - 's': '[sŚśṠṡṢṣꞨꞩŜŝŠšŞşȘșS̈s̈]', - 't': '[tŤťṪṫŢţṬṭƮʈȚțṰṱṮṯƬƭ]', - 'u': '[uŬŭɄʉỤụÜüÚúÙùÛûǓǔŰűŬŭƯưỦủŪūŨũŲųȔȕ∪]', - 'v': '[vṼṽṾṿƲʋꝞꝟⱱʋ]', - 'w': '[wẂẃẀẁŴŵẄẅẆẇẈẉ]', - 'x': '[xẌẍẊẋχ]', - 'y': '[yÝýỲỳŶŷŸÿỸỹẎẏỴỵɎɏƳƴ]', - 'z': '[zŹźẐẑŽžŻżẒẓẔẕƵƶ]' - }; - - var asciifold = (function() { - var i, n, k, chunk; - var foreignletters = ''; - var lookup = {}; - for (k in DIACRITICS) { - if (DIACRITICS.hasOwnProperty(k)) { - chunk = DIACRITICS[k].substring(2, DIACRITICS[k].length - 1); - foreignletters += chunk; - for (i = 0, n = chunk.length; i < n; i++) { - lookup[chunk.charAt(i)] = k; - } - } - } - var regexp = new RegExp('[' + foreignletters + ']', 'g'); - return function(str) { - return str.replace(regexp, function(foreignletter) { - return lookup[foreignletter]; - }).toLowerCase(); - }; - })(); - - - // export - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - return Sifter; -})); - - - -/** - * microplugin.js - * Copyright (c) 2013 Brian Reavis & contributors - * - * 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. - * - * @author Brian Reavis - */ - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define('microplugin', factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.MicroPlugin = factory(); - } -}(this, function() { - var MicroPlugin = {}; - - MicroPlugin.mixin = function(Interface) { - Interface.plugins = {}; - - /** - * Initializes the listed plugins (with options). - * Acceptable formats: - * - * List (without options): - * ['a', 'b', 'c'] - * - * List (with options): - * [{'name': 'a', options: {}}, {'name': 'b', options: {}}] - * - * Hash (with options): - * {'a': { ... }, 'b': { ... }, 'c': { ... }} - * - * @param {mixed} plugins - */ - Interface.prototype.initializePlugins = function(plugins) { - var i, n, key; - var self = this; - var queue = []; - - self.plugins = { - names : [], - settings : {}, - requested : {}, - loaded : {} - }; - - if (utils.isArray(plugins)) { - for (i = 0, n = plugins.length; i < n; i++) { - if (typeof plugins[i] === 'string') { - queue.push(plugins[i]); - } else { - self.plugins.settings[plugins[i].name] = plugins[i].options; - queue.push(plugins[i].name); - } - } - } else if (plugins) { - for (key in plugins) { - if (plugins.hasOwnProperty(key)) { - self.plugins.settings[key] = plugins[key]; - queue.push(key); - } - } - } - - while (queue.length) { - self.require(queue.shift()); - } - }; - - Interface.prototype.loadPlugin = function(name) { - var self = this; - var plugins = self.plugins; - var plugin = Interface.plugins[name]; - - if (!Interface.plugins.hasOwnProperty(name)) { - throw new Error('Unable to find "' + name + '" plugin'); - } - - plugins.requested[name] = true; - plugins.loaded[name] = plugin.fn.apply(self, [self.plugins.settings[name] || {}]); - plugins.names.push(name); - }; - - /** - * Initializes a plugin. - * - * @param {string} name - */ - Interface.prototype.require = function(name) { - var self = this; - var plugins = self.plugins; - - if (!self.plugins.loaded.hasOwnProperty(name)) { - if (plugins.requested[name]) { - throw new Error('Plugin has circular dependency ("' + name + '")'); - } - self.loadPlugin(name); - } - - return plugins.loaded[name]; - }; - - /** - * Registers a plugin. - * - * @param {string} name - * @param {function} fn - */ - Interface.define = function(name, fn) { - Interface.plugins[name] = { - 'name' : name, - 'fn' : fn - }; - }; - }; - - var utils = { - isArray: Array.isArray || function(vArg) { - return Object.prototype.toString.call(vArg) === '[object Array]'; - } - }; - - return MicroPlugin; -})); - -/** - * selectize.js (v0.12.6) - * Copyright (c) 2013–2015 Brian Reavis & contributors - * - * 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. - * - * @author Brian Reavis - */ - -/*jshint curly:false */ -/*jshint browser:true */ - -(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define('selectize', ['jquery','sifter','microplugin'], factory); - } else if (typeof exports === 'object') { - module.exports = factory(require('jquery'), require('sifter'), require('microplugin')); - } else { - root.Selectize = factory(root.jQuery, root.Sifter, root.MicroPlugin); - } -}(this, function($, Sifter, MicroPlugin) { - 'use strict'; - - var highlight = function($element, pattern) { - if (typeof pattern === 'string' && !pattern.length) return; - var regex = (typeof pattern === 'string') ? new RegExp(pattern, 'i') : pattern; - - var highlight = function(node) { - var skip = 0; - // Wrap matching part of text node with highlighting , e.g. - // Soccer -> Soccer for regex = /soc/i - if (node.nodeType === 3) { - var pos = node.data.search(regex); - if (pos >= 0 && node.data.length > 0) { - var match = node.data.match(regex); - var spannode = document.createElement('span'); - spannode.className = 'highlight'; - var middlebit = node.splitText(pos); - var endbit = middlebit.splitText(match[0].length); - var middleclone = middlebit.cloneNode(true); - spannode.appendChild(middleclone); - middlebit.parentNode.replaceChild(spannode, middlebit); - skip = 1; - } - } - // Recurse element node, looking for child text nodes to highlight, unless element - // is childless,