diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 36759f2f..86a5dd5b 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,54 @@ +## Release 4.0.0 + +* We upgraded the module to Mendix 11.0.0-beta.2 +* We introduced a new View Entity `WorkflowUserTaskView`, for unified access to user tasks regardless of whether these tasks are in progress or completed. For more information, refer to the Workflow Commons module documentation. +* We removed the state change events microflows `OCh_Workflow_State` and `OCh_WorkflowUserTask_State`, since state-change events are removed in Mendix 11. +* We removed the assignee and key migration microflows that were introduced in version 3.0.0 and 3.6.0 respectively and are no longer applicable. See the first note for more details. +* We added migration logic to perform a one-off migration of your existing data. When using Workflow Commons and upgrading your app to Mendix 11, it is required to perform this migration and update your app accordingly. See the second note for more details. +* We added an icon next to targeted/assigned users to indicate when a user is inactive, only visible for administrators. +* We replaced the List View for displaying assignees with a Data Grid 2 reference set supported feature. +* We fixed an issue where the overdue time was displayed incorrectly in the timeline. +* We updated Atlas Core module compatibility to v3.17.0 +* We updated Atlas Web Content module compatibility to v3.8.0 +* We updated Data Widgets module compatibility to v2.31.0 + +Note: When upgrading to v4.0.0 or above, make sure that you are currently using Workflow Commons v3.6.0 or above. If you are using an earlier version, first upgrade to any version between v3.6.0 and (but not including) v4.0.0, using a Mendix 10 version. Perform the required key and/or assignee migrations for all your environments. Any required migration will be shown in the WorkflowAdminCenter page. + +Note: As a result of upgrading to Mendix 11, the microflows and snippets that previously used the `WorkflowCommons.UserTaskView` entity have been replaced with documents that uses `WorkflowCommons.WorkflowUserTaskView` or `System.WorkflowEndedUserTask` as a parameter. If you are using one or more of them in your project, see the list below for replacement. Also, in case you have any logic based on the `WorkflowCommons.UserTaskView` entity, make sure to adapt this accordingly. + +Microflows: +* ACT_UserTaskView_ShowUserTask Page → replace with ACT_WorkflowUserTaskView_ShowUserTaskPage +* ACT_UserTaskView_ShowWorkflowAdminPage → replace with ACT_WorkflowUserTaskView_ShowDefaultAdminPage +* ACT_WorkflowView_ShowWorkflowAdminPage → replace with ACT_Workflow_ShowWorkflowAdminPage + +Snippets: +* Snip_UserTaskView_Assignees → replace with Snip_WorkflowUserTaskView_Assignees +* Snip_UserTaskView_Assignees_Aggregated → replace with Snip_WorkflowUserTaskView_Assignees +* Snip_UserTaskView_Details → replace with Snip_WorkflowUserTaskView_Details +* Snip_UserTaskView_Header → replace with Snip_UserTask_Header or Snip_WorfkflowEndedUserTask_Header +* Snip_UserTaskView_IncompatibleWarning → replace with Snip_WorkflowUserTaskView_IncompatibleWarning +* Snip_UserTaskView_NameColumn → replace with Snip_WorkflowUserTaskView_NameColumn +* Snip_UserTaskView_NameColumnWithIcon → replace with Snip_WorkflowUserTaskView_NameColumnWithIcon +* Snip_UserTaskView_State → replace with Snip_WorkflowUserTaskView_State +* Snip_UserTaskView_TargetUsers → replace with Snip_UserTask_TargetUsers or Snip_WorkflowEndedUserTask_TargetUsers +* Snip_WorkflowView_ActivityTimeline → replace with Snip_Workflow_ActivityTimeline +* Snip_WorkflowView_ActivityTimelineOnly_Full → replace with Snip_Workflow_ActivityTimelineOnly_Full +* Snip_WorkflowView_ActivityTimelineOnly_Tasks → replace with Snip_Workflow_ActivityTimelineOnly_Tasks +* Snip_WorkflowView_AuditTrail → replace with Snip_Workflow_AuditTrail +* Snip_WorkflowView_CommentsAndAttachments → replace with Snip_Workflow_CommentsAndAttachments +* Snip_WorkflowView_CommentsAndAttachments_Admin → replace with Snip_Workflow_CommentsAndAttachments_Admin +* Snip_WorkflowView_CompletedTaskDetails → replace with Snip_Workflow_TaskDetails +* Snip_WorkflowView_Detail → replace with Snip_Workflow_Detail +* Snip_WorkflowView_Header → replace with Snip_Workflow_Header +* Snip_WorkflowView_NotificationArea → replace with Snip_Workflow_NotificationArea +* Snip_WorkflowView_State → replace with Snip_Workflow_State +* Snip_WorkflowView_StateCircleOnly → replace with Snip_Workflow_StateCircleOnly +* Snip_WorkflowView_TaskTimeline → replace with Snip_Workflow_TaskTimeline +* Snip_WorkflowView_TaskTimeline_WithoutNameandDescription → replace with Snip_Workflow_TaskTimeline_WithoutName +* Snip_WorkflowView_TaskTimelineOnly → replace with Snip_Workflow_TaskTimelineOnly + +_______ + ## Release 3.12.1 * We changed the length of the `Reason` attribute in the `WorkflowAuditTrailRecord` entity to unlimited. diff --git a/Releases/WorkflowCommons-4-0-0.mpk b/Releases/WorkflowCommons-4-0-0.mpk new file mode 100644 index 00000000..1e6288df Binary files /dev/null and b/Releases/WorkflowCommons-4-0-0.mpk differ diff --git a/Source/ExpenseRequestStarterApp.mpr b/Source/ExpenseRequestStarterApp.mpr index 9f55297c..1ac5b74c 100644 Binary files a/Source/ExpenseRequestStarterApp.mpr and b/Source/ExpenseRequestStarterApp.mpr differ diff --git a/Source/javascriptsource/datawidgets/actions/Set_Filter.js b/Source/javascriptsource/datawidgets/actions/Set_Filter.js index 2f2518d8..f09e5b68 100644 --- a/Source/javascriptsource/datawidgets/actions/Set_Filter.js +++ b/Source/javascriptsource/datawidgets/actions/Set_Filter.js @@ -15,7 +15,7 @@ import { Big } from "big.js"; * @param {string} targetName - Name of the filter to set. Valid targets are: Number filter, Date filter, Text filter, Drop-down filter. You can find filter name in widget settings in the "Common" group (Properties>Common>Name). * @param {boolean} useDefaultValue - Determine the use of default value provided by the filter component itself. If true, "Value" section will be ignored - * @param {"DataWidgets.Filter_Operators.contains"|"DataWidgets.Filter_Operators.startsWith"|"DataWidgets.Filter_Operators.endsWith"|"DataWidgets.Filter_Operators.between"|"DataWidgets.Filter_Operators.greater"|"DataWidgets.Filter_Operators.greaterEqual"|"DataWidgets.Filter_Operators.equal"|"DataWidgets.Filter_Operators.notEqual"|"DataWidgets.Filter_Operators.smaller"|"DataWidgets.Filter_Operators.smallerEqual"|"DataWidgets.Filter_Operators.empty"|"DataWidgets.Filter_Operators.notEmpty"} operators - Selected operators value. If filter has operators, this value will be applied. + * @param {undefined|"contains"|"startsWith"|"endsWith"|"between"|"greater"|"greaterEqual"|"equal"|"notEqual"|"smaller"|"smallerEqual"|"empty"|"notEmpty"} operators - Selected operators value. If filter has operators, this value will be applied. * @param {string} stringValue - Value set for dropdown filter or text filter. Choose empty if not use. * @param {Big} numberValue - Number value for number filter. Choose empty if not use. * @param {Date} dateTimeValue - Date time value for date filter, can also be use as "start date". Choose empty if not use. diff --git a/Source/javascriptsource/datawidgets/actions/xlsx-export-tools.js b/Source/javascriptsource/datawidgets/actions/xlsx-export-tools.js index c00f335f..95361499 100644 --- a/Source/javascriptsource/datawidgets/actions/xlsx-export-tools.js +++ b/Source/javascriptsource/datawidgets/actions/xlsx-export-tools.js @@ -1,3 +1,3 @@ /*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var e=function(e){return String.fromCharCode(e)},t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";function r(e){for(var r="",n=0,a=0,o=0,i=0,s=0,l=0,c=0,f=0;f>2,s=(3&n)<<4|(a=e.charCodeAt(f++))>>4,l=(15&a)<<2|(o=e.charCodeAt(f++))>>6,c=63&o,isNaN(a)?l=c=64:isNaN(o)&&(c=64),r+=t.charAt(i)+t.charAt(s)+t.charAt(l)+t.charAt(c);return r}function n(e){var r="",n=0,a=0,o=0,i=0,s=0,l=0;e=e.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/,"").replace(/[^\w\+\/\=]/g,"");for(var c=0;c>4,r+=String.fromCharCode(n),a=(15&i)<<4|(s=t.indexOf(e.charAt(c++)))>>2,64!==s&&(r+=String.fromCharCode(a)),o=(3&s)<<6|(l=t.indexOf(e.charAt(c++))),64!==l&&(r+=String.fromCharCode(o));return r}var a=function(){return"undefined"!=typeof Buffer&&"undefined"!=typeof process&&void 0!==process.versions&&!!process.versions.node}(),o=function(){if("undefined"!=typeof Buffer){var e=!Buffer.from;if(!e)try{Buffer.from("foo","utf8")}catch(t){e=!0}return e?function(e,t){return t?new Buffer(e,t):new Buffer(e)}:Buffer.from.bind(Buffer)}return function(){}}(),i=function(){if("undefined"==typeof Buffer)return!1;var e=o([65,0]);return!!e&&1==e.toString("utf16le").length}();function s(e){return a?Buffer.alloc?Buffer.alloc(e):new Buffer(e):"undefined"!=typeof Uint8Array?new Uint8Array(e):new Array(e)}function l(e){return a?Buffer.allocUnsafe?Buffer.allocUnsafe(e):new Buffer(e):"undefined"!=typeof Uint8Array?new Uint8Array(e):new Array(e)}var c=function(e){return a?o(e,"binary"):e.split("").map((function(e){return 255&e.charCodeAt(0)}))};function f(e){if("undefined"==typeof ArrayBuffer)return c(e);for(var t=new ArrayBuffer(e.length),r=new Uint8Array(t),n=0;n!=e.length;++n)r[n]=255&e.charCodeAt(n);return t}var h=a?function(e){return Buffer.concat(e.map((function(e){return Buffer.isBuffer(e)?e:o(e)})))}:function(e){if("undefined"!=typeof Uint8Array){var t=0,r=0;for(t=0;t=0;)t+=e.charAt(r--);return t}function m(e,t){var r=""+e;return r.length>=t?r:ve("0",t-r.length)+r}function g(e,t){var r=""+e;return r.length>=t?r:ve(" ",t-r.length)+r}function v(e,t){var r=""+e;return r.length>=t?r:r+ve(" ",t-r.length)}var b=Math.pow(2,32);function x(e,t){return e>b||e<-b?function(e,t){var r=""+Math.round(e);return r.length>=t?r:ve("0",t-r.length)+r}(e,t):function(e,t){var r=""+e;return r.length>=t?r:ve("0",t-r.length)+r}(Math.round(e),t)}function w(e,t){return t=t||0,e.length>=7+t&&103==(32|e.charCodeAt(t))&&101==(32|e.charCodeAt(t+1))&&110==(32|e.charCodeAt(t+2))&&101==(32|e.charCodeAt(t+3))&&114==(32|e.charCodeAt(t+4))&&97==(32|e.charCodeAt(t+5))&&108==(32|e.charCodeAt(t+6))}var y=[["Sun","Sunday"],["Mon","Monday"],["Tue","Tuesday"],["Wed","Wednesday"],["Thu","Thursday"],["Fri","Friday"],["Sat","Saturday"]],C=[["J","Jan","January"],["F","Feb","February"],["M","Mar","March"],["A","Apr","April"],["M","May","May"],["J","Jun","June"],["J","Jul","July"],["A","Aug","August"],["S","Sep","September"],["O","Oct","October"],["N","Nov","November"],["D","Dec","December"]];var S={0:"General",1:"0",2:"0.00",3:"#,##0",4:"#,##0.00",9:"0%",10:"0.00%",11:"0.00E+00",12:"# ?/?",13:"# ??/??",14:"m/d/yy",15:"d-mmm-yy",16:"d-mmm",17:"mmm-yy",18:"h:mm AM/PM",19:"h:mm:ss AM/PM",20:"h:mm",21:"h:mm:ss",22:"m/d/yy h:mm",37:"#,##0 ;(#,##0)",38:"#,##0 ;[Red](#,##0)",39:"#,##0.00;(#,##0.00)",40:"#,##0.00;[Red](#,##0.00)",45:"mm:ss",46:"[h]:mm:ss",47:"mmss.0",48:"##0.0E+0",49:"@",56:'"上午/下午 "hh"時"mm"分"ss"秒 "'},k={5:37,6:38,7:39,8:40,23:0,24:0,25:0,26:0,27:14,28:14,29:14,30:14,31:14,50:14,51:14,52:14,53:14,54:14,55:14,56:14,57:14,58:14,59:1,60:2,61:3,62:4,67:9,68:10,69:12,70:13,71:14,72:14,73:15,74:16,75:17,76:20,77:21,78:22,79:45,80:46,81:47,82:0},_={5:'"$"#,##0_);\\("$"#,##0\\)',63:'"$"#,##0_);\\("$"#,##0\\)',6:'"$"#,##0_);[Red]\\("$"#,##0\\)',64:'"$"#,##0_);[Red]\\("$"#,##0\\)',7:'"$"#,##0.00_);\\("$"#,##0.00\\)',65:'"$"#,##0.00_);\\("$"#,##0.00\\)',8:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',66:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',41:'_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)',42:'_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)',43:'_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)',44:'_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'};function A(e,t,r){for(var n=e<0?-1:1,a=e*n,o=0,i=1,s=0,l=1,c=0,f=0,h=Math.floor(a);ct&&(c>t?(f=l,s=o):(f=c,s=i)),!r)return[0,n*s,f];var u=Math.floor(n*s/f);return[u,n*s-u*f,f]}function T(e,t,r){if(e>2958465||e<0)return null;var n=0|e,a=Math.floor(86400*(e-n)),o=0,i=[],s={D:n,T:a,u:86400*(e-n)-a,y:0,m:0,d:0,H:0,M:0,S:0,q:0};if(Math.abs(s.u)<1e-6&&(s.u=0),t&&t.date1904&&(n+=1462),s.u>.9999&&(s.u=0,86400==++a&&(s.T=a=0,++n,++s.D)),60===n)i=r?[1317,10,29]:[1900,2,29],o=3;else if(0===n)i=r?[1317,8,29]:[1900,1,0],o=6;else{n>60&&--n;var l=new Date(1900,0,1);l.setDate(l.getDate()+n-1),i=[l.getFullYear(),l.getMonth()+1,l.getDate()],o=l.getDay(),n<60&&(o=(o+6)%7),r&&(o=function(e,t){t[0]-=581;var r=e.getDay();e<60&&(r=(r+6)%7);return r}(l,i))}return s.y=i[0],s.m=i[1],s.d=i[2],s.S=a%60,a=Math.floor(a/60),s.M=a%60,a=Math.floor(a/60),s.H=a,s.q=o,s}function D(e){return-1==e.indexOf(".")?e:e.replace(/(?:\.0*|(\.\d*[1-9])0+)$/,"$1")}function O(e){var t,r=Math.floor(Math.log(Math.abs(e))*Math.LOG10E);return t=r>=-4&&r<=-1?e.toPrecision(10+r):Math.abs(r)<=9?function(e){var t=e<0?12:11,r=D(e.toFixed(12));return r.length<=t||(r=e.toPrecision(10)).length<=t?r:e.toExponential(5)}(e):10===r?e.toFixed(10).substr(0,12):function(e){var t=D(e.toFixed(11));return t.length>(e<0?12:11)||"0"===t||"-0"===t?e.toPrecision(6):t}(e),D(function(e){return-1==e.indexOf("E")?e:e.replace(/(?:\.0*|(\.\d*[1-9])0+)[Ee]/,"$1E").replace(/(E[+-])(\d)$/,"$10$2")}(t.toUpperCase()))}function E(e,t){switch(typeof e){case"string":return e;case"boolean":return e?"TRUE":"FALSE";case"number":return(0|e)===e?e.toString(10):O(e);case"undefined":return"";case"object":if(null==e)return"";if(e instanceof Date)return Z(14,fe(e,t&&t.date1904),t)}throw new Error("unsupported value in General format: "+e)}function F(e,t,r,n){var a,o="",i=0,s=0,l=r.y,c=0;switch(e){case 98:l=r.y+543;case 121:switch(t.length){case 1:case 2:a=l%100,c=2;break;default:a=l%1e4,c=4}break;case 109:switch(t.length){case 1:case 2:a=r.m,c=t.length;break;case 3:return C[r.m-1][1];case 5:return C[r.m-1][0];default:return C[r.m-1][2]}break;case 100:switch(t.length){case 1:case 2:a=r.d,c=t.length;break;case 3:return y[r.q][0];default:return y[r.q][1]}break;case 104:switch(t.length){case 1:case 2:a=1+(r.H+11)%12,c=t.length;break;default:throw"bad hour format: "+t}break;case 72:switch(t.length){case 1:case 2:a=r.H,c=t.length;break;default:throw"bad hour format: "+t}break;case 77:switch(t.length){case 1:case 2:a=r.M,c=t.length;break;default:throw"bad minute format: "+t}break;case 115:if("s"!=t&&"ss"!=t&&".0"!=t&&".00"!=t&&".000"!=t)throw"bad second format: "+t;return 0!==r.u||"s"!=t&&"ss"!=t?(s=n>=2?3===n?1e3:100:1===n?10:1,(i=Math.round(s*(r.S+r.u)))>=60*s&&(i=0),"s"===t?0===i?"0":""+i/s:(o=m(i,2+n),"ss"===t?o.substr(0,2):"."+o.substr(2,t.length-1))):m(r.S,t.length);case 90:switch(t){case"[h]":case"[hh]":a=24*r.D+r.H;break;case"[m]":case"[mm]":a=60*(24*r.D+r.H)+r.M;break;case"[s]":case"[ss]":a=60*(60*(24*r.D+r.H)+r.M)+Math.round(r.S+r.u);break;default:throw"bad abstime format: "+t}c=3===t.length?1:2;break;case 101:a=l,c=1}return c>0?m(a,c):""}function M(e){if(e.length<=3)return e;for(var t=e.length%3,r=e.substr(0,t);t!=e.length;t+=3)r+=(r.length>0?",":"")+e.substr(t,3);return r}var N=/%/g;function P(e,t){var r,n=e.indexOf("E")-e.indexOf(".")-1;if(e.match(/^#+0.0E\+0$/)){if(0==t)return"0.0E+0";if(t<0)return"-"+P(e,-t);var a=e.indexOf(".");-1===a&&(a=e.indexOf("E"));var o=Math.floor(Math.log(t)*Math.LOG10E)%a;if(o<0&&(o+=a),-1===(r=(t/Math.pow(10,o)).toPrecision(n+1+(a+o)%a)).indexOf("e")){var i=Math.floor(Math.log(t)*Math.LOG10E);for(-1===r.indexOf(".")?r=r.charAt(0)+"."+r.substr(1)+"E+"+(i-r.length+o):r+="E+"+(i-o);"0."===r.substr(0,2);)r=(r=r.charAt(0)+r.substr(2,a)+"."+r.substr(2+a)).replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");r=r.replace(/\+-/,"-")}r=r.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,(function(e,t,r,n){return t+r+n.substr(0,(a+o)%a)+"."+n.substr(o)+"E"}))}else r=t.toExponential(n);return e.match(/E\+00$/)&&r.match(/e[+-]\d$/)&&(r=r.substr(0,r.length-1)+"0"+r.charAt(r.length-1)),e.match(/E\-/)&&r.match(/e\+/)&&(r=r.replace(/e\+/,"e")),r.replace("e","E")}var I=/# (\?+)( ?)\/( ?)(\d+)/;var R=/^#*0*\.([0#]+)/,L=/\).*[0#]/,U=/\(###\) ###\\?-####/;function z(e){for(var t,r="",n=0;n!=e.length;++n)switch(t=e.charCodeAt(n)){case 35:break;case 63:r+=" ";break;case 48:r+="0";break;default:r+=String.fromCharCode(t)}return r}function j(e,t){var r=Math.pow(10,t);return""+Math.round(e*r)/r}function B(e,t){var r=e-Math.floor(e),n=Math.pow(10,t);return t<(""+Math.round(r*n)).length?0:Math.round(r*n)}function W(e,t,r){if(40===e.charCodeAt(0)&&!t.match(L)){var n=t.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");return r>=0?W("n",n,r):"("+W("n",n,-r)+")"}if(44===t.charCodeAt(t.length-1))return function(e,t,r){for(var n=t.length-1;44===t.charCodeAt(n-1);)--n;return V(e,t.substr(0,n),r/Math.pow(10,3*(t.length-n)))}(e,t,r);if(-1!==t.indexOf("%"))return function(e,t,r){var n=t.replace(N,""),a=t.length-n.length;return V(e,n,r*Math.pow(10,2*a))+ve("%",a)}(e,t,r);if(-1!==t.indexOf("E"))return P(t,r);if(36===t.charCodeAt(0))return"$"+W(e,t.substr(" "==t.charAt(1)?2:1),r);var a,o,i,s,l=Math.abs(r),c=r<0?"-":"";if(t.match(/^00+$/))return c+x(l,t.length);if(t.match(/^[#?]+$/))return"0"===(a=x(r,0))&&(a=""),a.length>t.length?a:z(t.substr(0,t.length-a.length))+a;if(o=t.match(I))return function(e,t,r){var n=parseInt(e[4],10),a=Math.round(t*n),o=Math.floor(a/n),i=a-o*n,s=n;return r+(0===o?"":""+o)+" "+(0===i?ve(" ",e[1].length+1+e[4].length):g(i,e[1].length)+e[2]+"/"+e[3]+m(s,e[4].length))}(o,l,c);if(t.match(/^#+0+$/))return c+x(l,t.length-t.indexOf("0"));if(o=t.match(R))return a=j(r,o[1].length).replace(/^([^\.]+)$/,"$1."+z(o[1])).replace(/\.$/,"."+z(o[1])).replace(/\.(\d*)$/,(function(e,t){return"."+t+ve("0",z(o[1]).length-t.length)})),-1!==t.indexOf("0.")?a:a.replace(/^0\./,".");if(t=t.replace(/^#+([0.])/,"$1"),o=t.match(/^(0*)\.(#*)$/))return c+j(l,o[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,o[1].length?"0.":".");if(o=t.match(/^#{1,3},##0(\.?)$/))return c+M(x(l,0));if(o=t.match(/^#,##0\.([#0]*0)$/))return r<0?"-"+W(e,t,-r):M(""+(Math.floor(r)+function(e,t){return t<(""+Math.round((e-Math.floor(e))*Math.pow(10,t))).length?1:0}(r,o[1].length)))+"."+m(B(r,o[1].length),o[1].length);if(o=t.match(/^#,#*,#0/))return W(e,t.replace(/^#,#*,/,""),r);if(o=t.match(/^([0#]+)(\\?-([0#]+))+$/))return a=d(W(e,t.replace(/[\\-]/g,""),r)),i=0,d(d(t.replace(/\\/g,"")).replace(/[0#]/g,(function(e){return i-2147483648?""+(e>=0?0|e:e-1|0):""+Math.floor(e)}(r)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,(function(e){return"00,"+(e.length<3?m(0,3-e.length):"")+e}))+"."+m(i,o[1].length);switch(t){case"###,##0.00":return W(e,"#,##0.00",r);case"###,###":case"##,###":case"#,###":var p=M(x(l,0));return"0"!==p?c+p:"";case"###,###.00":return W(e,"###,##0.00",r).replace(/^0\./,".");case"#,###.00":return W(e,"#,##0.00",r).replace(/^0\./,".")}throw new Error("unsupported format |"+t+"|")}function H(e,t){var r,n=e.indexOf("E")-e.indexOf(".")-1;if(e.match(/^#+0.0E\+0$/)){if(0==t)return"0.0E+0";if(t<0)return"-"+H(e,-t);var a=e.indexOf(".");-1===a&&(a=e.indexOf("E"));var o=Math.floor(Math.log(t)*Math.LOG10E)%a;if(o<0&&(o+=a),!(r=(t/Math.pow(10,o)).toPrecision(n+1+(a+o)%a)).match(/[Ee]/)){var i=Math.floor(Math.log(t)*Math.LOG10E);-1===r.indexOf(".")?r=r.charAt(0)+"."+r.substr(1)+"E+"+(i-r.length+o):r+="E+"+(i-o),r=r.replace(/\+-/,"-")}r=r.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,(function(e,t,r,n){return t+r+n.substr(0,(a+o)%a)+"."+n.substr(o)+"E"}))}else r=t.toExponential(n);return e.match(/E\+00$/)&&r.match(/e[+-]\d$/)&&(r=r.substr(0,r.length-1)+"0"+r.charAt(r.length-1)),e.match(/E\-/)&&r.match(/e\+/)&&(r=r.replace(/e\+/,"e")),r.replace("e","E")}function X(e,t,r){if(40===e.charCodeAt(0)&&!t.match(L)){var n=t.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");return r>=0?X("n",n,r):"("+X("n",n,-r)+")"}if(44===t.charCodeAt(t.length-1))return function(e,t,r){for(var n=t.length-1;44===t.charCodeAt(n-1);)--n;return V(e,t.substr(0,n),r/Math.pow(10,3*(t.length-n)))}(e,t,r);if(-1!==t.indexOf("%"))return function(e,t,r){var n=t.replace(N,""),a=t.length-n.length;return V(e,n,r*Math.pow(10,2*a))+ve("%",a)}(e,t,r);if(-1!==t.indexOf("E"))return H(t,r);if(36===t.charCodeAt(0))return"$"+X(e,t.substr(" "==t.charAt(1)?2:1),r);var a,o,i,s,l=Math.abs(r),c=r<0?"-":"";if(t.match(/^00+$/))return c+m(l,t.length);if(t.match(/^[#?]+$/))return a=""+r,0===r&&(a=""),a.length>t.length?a:z(t.substr(0,t.length-a.length))+a;if(o=t.match(I))return function(e,t,r){return r+(0===t?"":""+t)+ve(" ",e[1].length+2+e[4].length)}(o,l,c);if(t.match(/^#+0+$/))return c+m(l,t.length-t.indexOf("0"));if(o=t.match(R))return a=(a=(""+r).replace(/^([^\.]+)$/,"$1."+z(o[1])).replace(/\.$/,"."+z(o[1]))).replace(/\.(\d*)$/,(function(e,t){return"."+t+ve("0",z(o[1]).length-t.length)})),-1!==t.indexOf("0.")?a:a.replace(/^0\./,".");if(t=t.replace(/^#+([0.])/,"$1"),o=t.match(/^(0*)\.(#*)$/))return c+(""+l).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,o[1].length?"0.":".");if(o=t.match(/^#{1,3},##0(\.?)$/))return c+M(""+l);if(o=t.match(/^#,##0\.([#0]*0)$/))return r<0?"-"+X(e,t,-r):M(""+r)+"."+ve("0",o[1].length);if(o=t.match(/^#,#*,#0/))return X(e,t.replace(/^#,#*,/,""),r);if(o=t.match(/^([0#]+)(\\?-([0#]+))+$/))return a=d(X(e,t.replace(/[\\-]/g,""),r)),i=0,d(d(t.replace(/\\/g,"")).replace(/[0#]/g,(function(e){return i-1||"\\"==r&&"-"==e.charAt(t+1)&&"0#".indexOf(e.charAt(t+2))>-1););break;case"?":for(;e.charAt(++t)===r;);break;case"*":++t," "!=e.charAt(t)&&"*"!=e.charAt(t)||++t;break;case"(":case")":++t;break;case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":for(;t-1;);break;default:++t}return!1}var q=/\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;function Y(e,t){if(null==t)return!1;var r=parseFloat(t[2]);switch(t[1]){case"=":if(e==r)return!0;break;case">":if(e>r)return!0;break;case"<":if(e":if(e!=r)return!0;break;case">=":if(e>=r)return!0;break;case"<=":if(e<=r)return!0}return!1}function K(e,t){var r=function(e){for(var t=[],r=!1,n=0,a=0;n-1&&--n,r.length>4)throw new Error("cannot find right format for |"+r.join("|")+"|");if("number"!=typeof t)return[4,4===r.length||a>-1?r[r.length-1]:"@"];switch(r.length){case 1:r=a>-1?["General","General","General",r[0]]:[r[0],r[0],r[0],"@"];break;case 2:r=a>-1?[r[0],r[0],r[0],r[1]]:[r[0],r[1],r[0],"@"];break;case 3:r=a>-1?[r[0],r[1],r[0],r[2]]:[r[0],r[1],r[2],"@"]}var o=t>0?r[0]:t<0?r[1]:r[2];if(-1===r[0].indexOf("[")&&-1===r[1].indexOf("["))return[n,o];if(null!=r[0].match(/\[[=<>]/)||null!=r[1].match(/\[[=<>]/)){var i=r[0].match(q),s=r[1].match(q);return Y(t,i)?[n,r[0]]:Y(t,s)?[n,r[1]]:[n,r[null!=i&&null!=s?2:1]]}return[n,o]}function Z(e,t,r){null==r&&(r={});var n="";switch(typeof e){case"string":n="m/d/yy"==e&&r.dateNF?r.dateNF:e;break;case"number":null==(n=14==e&&r.dateNF?r.dateNF:(null!=r.table?r.table:S)[e])&&(n=r.table&&r.table[k[e]]||S[k[e]]),null==n&&(n=_[e]||"General")}if(w(n,0))return E(t,r);t instanceof Date&&(t=fe(t,r.date1904));var a=K(n,t);if(w(a[1]))return E(t,r);if(!0===t)t="TRUE";else if(!1===t)t="FALSE";else if(""===t||null==t)return"";return function(e,t,r,n){for(var a,o,i,s=[],l="",c=0,f="",h="t",u="H";c=12?e.charAt(c+2):f),m.t="T",u="h",c+=3):"AM/PM"===e.substr(c,5).toUpperCase()?(null!=a&&(m.v=a.H>=12?"PM":"AM"),m.t="T",c+=5,u="h"):"上午/下午"===e.substr(c,5).toUpperCase()?(null!=a&&(m.v=a.H>=12?"下午":"上午"),m.t="T",c+=5,u="h"):(m.t="t",++c),null==a&&"T"===m.t)return"";s[s.length]=m,h=f;break;case"[":for(l=f;"]"!==e.charAt(c++)&&c-1&&(l=(l.match(/\$([^-\[\]]*)/)||[])[1]||"$",J(e)||(s[s.length]={t:"t",v:l}));break;case".":if(null!=a){for(l=f;++c-1;)l+=f;s[s.length]={t:"n",v:l};break;case"?":for(l=f;e.charAt(++c)===f;)l+=f;s[s.length]={t:f,v:l},h=f;break;case"*":++c," "!=e.charAt(c)&&"*"!=e.charAt(c)||++c;break;case"(":case")":s[s.length]={t:1===n?"t":f,v:f},++c;break;case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":for(l=f;c-1;)l+=e.charAt(c);s[s.length]={t:"D",v:l};break;case" ":s[s.length]={t:f,v:f},++c;break;case"$":s[s.length]={t:"t",v:"$"},++c;break;default:if(-1===",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(f))throw new Error("unrecognized character "+f+" in "+e);s[s.length]={t:"t",v:f},++c}var g,v=0,b=0;for(c=s.length-1,h="t";c>=0;--c)switch(s[c].t){case"h":case"H":s[c].t=u,h="h",v<1&&(v=1);break;case"s":(g=s[c].v.match(/\.0+$/))&&(b=Math.max(b,g[0].length-1)),v<3&&(v=3);case"d":case"y":case"M":case"e":h=s[c].t;break;case"m":"s"===h&&(s[c].t="M",v<2&&(v=2));break;case"X":break;case"Z":v<1&&s[c].v.match(/[Hh]/)&&(v=1),v<2&&s[c].v.match(/[Mm]/)&&(v=2),v<3&&s[c].v.match(/[Ss]/)&&(v=3)}switch(v){case 0:break;case 1:a.u>=.5&&(a.u=0,++a.S),a.S>=60&&(a.S=0,++a.M),a.M>=60&&(a.M=0,++a.H);break;case 2:a.u>=.5&&(a.u=0,++a.S),a.S>=60&&(a.S=0,++a.M)}var x,y="";for(c=0;c0){40==y.charCodeAt(0)?(C=t<0&&45===y.charCodeAt(0)?-t:t,S=V("n",y,C)):(S=V("n",y,C=t<0&&n>1?-t:t),C<0&&s[0]&&"t"==s[0].t&&(S=S.substr(1),s[0].v="-"+s[0].v)),x=S.length-1;var _=s.length;for(c=0;c-1){_=c;break}var A=s.length;if(_===s.length&&-1===S.indexOf("E")){for(c=s.length-1;c>=0;--c)null!=s[c]&&-1!=="n?".indexOf(s[c].t)&&(x>=s[c].v.length-1?(x-=s[c].v.length,s[c].v=S.substr(x+1,s[c].v.length)):x<0?s[c].v="":(s[c].v=S.substr(0,x+1),x=-1),s[c].t="t",A=c);x>=0&&A=0;--c)if(null!=s[c]&&-1!=="n?".indexOf(s[c].t)){for(o=s[c].v.indexOf(".")>-1&&c===_?s[c].v.indexOf(".")-1:s[c].v.length-1,k=s[c].v.substr(o+1);o>=0;--o)x>=0&&("0"===s[c].v.charAt(o)||"#"===s[c].v.charAt(o))&&(k=S.charAt(x--)+k);s[c].v=k,s[c].t="t",A=c}for(x>=0&&A-1&&c===_?s[c].v.indexOf(".")+1:0,k=s[c].v.substr(0,o);o-1&&(C=n>1&&t<0&&c>0&&"-"===s[c-1].v?-t:t,s[c].v=V(s[c].t,s[c].v,C),s[c].t="t");var D="";for(c=0;c!==s.length;++c)null!=s[c]&&(D+=s[c].v);return D}(a[1],t,r,a[0])}function Q(e,t){if("number"!=typeof t){t=+t||-1;for(var r=0;r<392;++r)if(null!=S[r]){if(S[r]==e){t=r;break}}else t<0&&(t=r);t<0&&(t=391)}return S[t]=e,t}var ee={"d.m":"d\\.m"};var te=function(){var e={};e.version="1.2.0";var t=function(){for(var e=0,t=new Array(256),r=0;256!=r;++r)e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=r)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1,t[r]=e;return"undefined"!=typeof Int32Array?new Int32Array(t):t}();var r=function(e){var t=0,r=0,n=0,a="undefined"!=typeof Int32Array?new Int32Array(4096):new Array(4096);for(n=0;256!=n;++n)a[n]=e[n];for(n=0;256!=n;++n)for(r=e[n],t=256+n;t<4096;t+=256)r=a[t]=r>>>8^e[255&r];var o=[];for(n=1;16!=n;++n)o[n-1]="undefined"!=typeof Int32Array&&"function"==typeof a.subarray?a.subarray(256*n,256*n+256):a.slice(256*n,256*n+256);return o}(t),n=r[0],a=r[1],o=r[2],i=r[3],s=r[4],l=r[5],c=r[6],f=r[7],h=r[8],u=r[9],p=r[10],d=r[11],m=r[12],g=r[13],v=r[14];return e.table=t,e.bstr=function(e,r){for(var n=~r,a=0,o=e.length;a>>8^t[255&(n^e.charCodeAt(a++))];return~n},e.buf=function(e,r){for(var b=~r,x=e.length-15,w=0;w>8&255]^m[e[w++]^b>>16&255]^d[e[w++]^b>>>24]^p[e[w++]]^u[e[w++]]^h[e[w++]]^f[e[w++]]^c[e[w++]]^l[e[w++]]^s[e[w++]]^i[e[w++]]^o[e[w++]]^a[e[w++]]^n[e[w++]]^t[e[w++]];for(x+=15;w>>8^t[255&(b^e[w++])];return~b},e.str=function(e,r){for(var n=~r,a=0,o=e.length,i=0,s=0;a>>8^t[255&(n^i)]:i<2048?n=(n=n>>>8^t[255&(n^(192|i>>6&31))])>>>8^t[255&(n^(128|63&i))]:i>=55296&&i<57344?(i=64+(1023&i),s=1023&e.charCodeAt(a++),n=(n=(n=(n=n>>>8^t[255&(n^(240|i>>8&7))])>>>8^t[255&(n^(128|i>>2&63))])>>>8^t[255&(n^(128|s>>6&15|(3&i)<<4))])>>>8^t[255&(n^(128|63&s))]):n=(n=(n=n>>>8^t[255&(n^(224|i>>12&15))])>>>8^t[255&(n^(128|i>>6&63))])>>>8^t[255&(n^(128|63&i))];return~n},e}(),re=function(){var e,t={};function i(e){if("/"==e.charAt(e.length-1))return-1===e.slice(0,-1).indexOf("/")?e:i(e.slice(0,-1));var t=e.lastIndexOf("/");return-1===t?e:e.slice(0,t+1)}function f(e){if("/"==e.charAt(e.length-1))return f(e.slice(0,-1));var t=e.lastIndexOf("/");return-1===t?e:e.slice(t+1)}function d(e,t){"string"==typeof t&&(t=new Date(t));var r=t.getHours();r=(r=r<<6|t.getMinutes())<<5|t.getSeconds()>>>1,e.write_shift(2,r);var n=t.getFullYear()-1980;n=(n=n<<4|t.getMonth()+1)<<5|t.getDate(),e.write_shift(2,n)}function m(e){Tt(e,0);for(var t={},r=0;e.l<=e.length-4;){var n=e.read_shift(2),a=e.read_shift(2),o=e.l+a,i={};switch(n){case 21589:1&(r=e.read_shift(1))&&(i.mtime=e.read_shift(4)),a>5&&(2&r&&(i.atime=e.read_shift(4)),4&r&&(i.ctime=e.read_shift(4))),i.mtime&&(i.mt=new Date(1e3*i.mtime));break;case 1:var s=e.read_shift(4),l=e.read_shift(4);i.usz=l*Math.pow(2,32)+s,s=e.read_shift(4),l=e.read_shift(4),i.csz=l*Math.pow(2,32)+s}e.l=o,t[n]=i}return t}function g(){return e||(e=undefined)}function v(e,t){if(80==e[0]&&75==e[1])return ge(e,t);if(109==(32|e[0])&&105==(32|e[1]))return function(e,t){if("mime-version:"!=M(e.slice(0,13)).toLowerCase())throw new Error("Unsupported MAD header");var r=t&&t.root||"",n=(a&&Buffer.isBuffer(e)?e.toString("binary"):M(e)).split("\r\n"),o=0,i="";for(o=0;o0&&(r=(r=r.slice(0,r.length-1)).slice(0,r.lastIndexOf("/")+1),i.slice(0,r.length)!=r););var s=(n[1]||"").match(/boundary="(.*?)"/);if(!s)throw new Error("MAD cannot find boundary");var l="--"+(s[1]||""),c=[],f=[],h={FileIndex:c,FullPaths:f};C(h);var u,p=0;for(o=0;o=a&&(u-=a),!i[u]){l=[];var d=[];for(h=u;h>=0;){d[h]=!0,i[h]=!0,s[s.length]=h,l.push(e[h]);var m=r[Math.floor(4*h/n)];if(n<4+(p=4*h&c))throw new Error("FAT boundary crossed: "+h+" 4 "+n);if(!e[m])break;if(d[h=xt(e[m],p)])break}o[u]={nodes:s,data:Ye([l])}}return o}(v,i,f,c);i0&&s!==T&&(S[s].name="!MiniFAT"),S[f[0]].name="!FAT",S.fat_addrs=f,S.ssz=c;var k=[],_=[],A=[];!function(e,t,r,n,a,o,i,s){for(var l,c=0,f=n.length?2:0,h=t[e].data,u=0,p=0;u0&&c!==T&&(t[c].name="!StreamData")):m.size>=4096?(m.storage="fat",void 0===t[m.start]&&(t[m.start]=w(r,m.start,t.fat_addrs,t.ssz)),t[m.start].name=m.name,m.content=t[m.start].data.slice(0,m.size)):(m.storage="minifat",m.size<0?m.size=0:c!==T&&m.start!==T&&t[c]&&(m.content=b(m,t[c].data,(t[s]||{}).data))),m.content&&Tt(m.content,0),o[l]=m,i.push(m)}}(i,S,v,k,n,{},_,s),function(e,t,r){for(var n=0,a=0,o=0,i=0,s=0,l=r.length,c=[],f=[];n0&&i>=0;)o.push(t.slice(i*A,i*A+A)),a-=A,i=xt(r,4*i);return 0===o.length?Dt(0):h(o).slice(0,e.size)}function x(e,t,r,n,a){var o=T;if(e===T){if(0!==t)throw new Error("DIFAT chain shorter than expected")}else if(-1!==e){var i=r[e],s=(n>>>2)-1;if(!i)return;for(var l=0;l=1&&x(xt(i,n-4),t-1,r,n,a)}}function w(e,t,r,n,a){var o=[],i=[];a||(a=[]);var s=n-1,l=0,c=0;for(l=t;l>=0;){a[l]=!0,o[o.length]=l,i.push(e[l]);var f=r[Math.floor(4*l/n)];if(n<4+(c=4*l&s))throw new Error("FAT boundary crossed: "+l+" 4 "+n);if(!e[f])break;l=xt(e[f],c)}return{nodes:o,data:Ye([i])}}function y(e,t){return new Date(1e3*(bt(e,t+4)/1e7*Math.pow(2,32)+bt(e,t)/1e7-11644473600))}function C(e,t){var r=t||{},n=r.root||"Root Entry";if(e.FullPaths||(e.FullPaths=[]),e.FileIndex||(e.FileIndex=[]),e.FullPaths.length!==e.FileIndex.length)throw new Error("inconsistent CFB structure");0===e.FullPaths.length&&(e.FullPaths[0]=n+"/",e.FileIndex[0]={name:n,type:5}),r.CLSID&&(e.FileIndex[0].clsid=r.CLSID),function(e){var t="Sh33tJ5";if(re.find(e,"/"+t))return;var r=Dt(4);r[0]=55,r[1]=r[3]=50,r[2]=54,e.FileIndex.push({name:t,type:2,content:r,size:4,L:69,R:69,C:69}),e.FullPaths.push(e.FullPaths[0]+t),S(e)}(e)}function S(e,t){C(e);for(var r=!1,n=!1,a=e.FullPaths.length-1;a>=0;--a){var o=e.FileIndex[a];switch(o.type){case 0:n?r=!0:(e.FileIndex.pop(),e.FullPaths.pop());break;case 1:case 2:case 5:n=!0,isNaN(o.R*o.L*o.C)&&(r=!0),o.R>-1&&o.L>-1&&o.R==o.L&&(r=!0);break;default:r=!0}}if(r||t){var s=new Date(1987,1,19),l=0,c=Object.create?Object.create(null):{},h=[];for(a=0;a1?1:-1,p.size=0,p.type=5;else if("/"==d.slice(-1)){for(l=a+1;l=h.length?-1:l,l=a+1;l=h.length?-1:l,p.type=1}else i(e.FullPaths[a+1]||"")==i(d)&&(p.R=a+1),p.type=2}}}function k(e,t){var r=t||{};if("mad"==r.fileType)return function(e,t){for(var r=t||{},n=r.boundary||"SheetJS",o=["MIME-Version: 1.0",'Content-Type: multipart/related; boundary="'+(n="------="+n).slice(2)+'"',"","",""],i=e.FullPaths[0],s=i,l=e.FileIndex[0],c=1;c=32&&d<128&&++u;var g=u>=4*p/5;o.push(n),o.push("Content-Location: "+(r.root||"file:///C:/SheetJS/")+s),o.push("Content-Transfer-Encoding: "+(g?"quoted-printable":"base64")),o.push("Content-Type: "+xe(l,s)),o.push(""),o.push(g?ye(h):we(h))}return o.push(n+"--\r\n"),o.join("\r\n")}(e,r);if(S(e),"zip"===r.fileType)return function(e,t){var r=t||{},n=[],a=[],o=Dt(1),i=r.compression?8:0,s=0,l=0,f=0,u=0,p=0,m=e.FullPaths[0],g=m,v=e.FileIndex[0],b=[],x=0;for(l=1;l0&&(o<4096?t+=o+63>>6:r+=o+511>>9)}}for(var i=e.FullPaths.length+3>>2,s=t+127>>7,l=(t+7>>3)+r+i+s,c=l+127>>7,f=c<=109?0:Math.ceil((c-109)/127);l+c+f+127>>7>c;)f=++c<=109?0:Math.ceil((c-109)/127);var h=[1,f,c,s,i,r,t,0];return e.FileIndex[0].size=t<<6,h[7]=(e.FileIndex[0].start=h[0]+h[1]+h[2]+h[3]+h[4]+h[5])+(h[6]+7>>3),h}(e),o=Dt(n[7]<<9),i=0,s=0;for(i=0;i<8;++i)o.write_shift(1,O[i]);for(i=0;i<8;++i)o.write_shift(2,0);for(o.write_shift(2,62),o.write_shift(2,3),o.write_shift(2,65534),o.write_shift(2,9),o.write_shift(2,6),i=0;i<3;++i)o.write_shift(2,0);for(o.write_shift(4,0),o.write_shift(4,n[2]),o.write_shift(4,n[0]+n[1]+n[2]+n[3]-1),o.write_shift(4,0),o.write_shift(4,4096),o.write_shift(4,n[3]?n[0]+n[1]+n[2]-1:T),o.write_shift(4,n[3]),o.write_shift(-4,n[1]?n[0]-1:T),o.write_shift(4,n[1]),i=0;i<109;++i)o.write_shift(-4,i>9)));for(l(n[6]+7>>3);511&o.l;)o.write_shift(-4,F.ENDOFCHAIN);for(s=i=0,f=0;f=4096||(p.start=s,l(u+63>>6)));for(;511&o.l;)o.write_shift(-4,F.ENDOFCHAIN);for(i=0;i32&&(console.error("Name "+g+" will be truncated to "+g.slice(0,32)),g=g.slice(0,32)),u=2*(g.length+1),o.write_shift(64,g,"utf16le"),o.write_shift(2,u),o.write_shift(1,p.type),o.write_shift(1,p.color),o.write_shift(-4,p.L),o.write_shift(-4,p.R),o.write_shift(-4,p.C),p.clsid)o.write_shift(16,p.clsid,"hex");else for(f=0;f<4;++f)o.write_shift(4,0);o.write_shift(4,p.state||0),o.write_shift(4,0),o.write_shift(4,0),o.write_shift(4,0),o.write_shift(4,0),o.write_shift(4,p.start),o.write_shift(4,p.size),o.write_shift(4,0)}else{for(f=0;f<17;++f)o.write_shift(4,0);for(f=0;f<3;++f)o.write_shift(4,-1);for(f=0;f<12;++f)o.write_shift(4,0)}}for(i=1;i=4096)if(o.l=p.start+1<<9,a&&Buffer.isBuffer(p.content))p.content.copy(o,o.l,0,p.size),o.l+=p.size+511&-512;else{for(f=0;f0&&p.size<4096)if(a&&Buffer.isBuffer(p.content))p.content.copy(o,o.l,0,p.size),o.l+=p.size+63&-64;else{for(f=0;f>16|U>>8|U));function B(e,t){var r=z[255&e];return t<=8?r>>>8-t:(r=r<<8|z[e>>8&255],t<=16?r>>>16-t:(r=r<<8|z[e>>16&255])>>>24-t)}function W(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=6?0:e[n+1]<<8))>>>r&3}function H(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=5?0:e[n+1]<<8))>>>r&7}function X(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=3?0:e[n+1]<<8))>>>r&31}function V(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=1?0:e[n+1]<<8))>>>r&127}function G(e,t,r){var n=7&t,a=t>>>3,o=(1<>>n;return r<8-n?i&o:(i|=e[a+1]<<8-n,r<16-n?i&o:(i|=e[a+2]<<16-n,r<24-n?i&o:(i|=e[a+3]<<24-n)&o))}function J(e,t,r){var n=7&t,a=t>>>3;return n<=5?e[a]|=(7&r)<>8-n),t+3}function q(e,t,r){return r=(1&r)<<(7&t),e[t>>>3]|=r,t+1}function Y(e,t,r){var n=t>>>3;return r<<=7&t,e[n]|=255&r,r>>>=8,e[n+1]=r,t+8}function K(e,t,r){var n=t>>>3;return r<<=7&t,e[n]|=255&r,r>>>=8,e[n+1]=255&r,e[n+2]=r>>>8,t+16}function Z(e,t){var r=e.length,n=2*r>t?2*r:t+5,o=0;if(r>=t)return e;if(a){var i=l(n);if(e.copy)e.copy(i);else for(;o>n-h,i=(1<=0;--i)t[s|i<0;)t[t.l++]=e[r++]}return t.l}(t,r):function(t,r){for(var a=0,o=0,i=$?new Uint16Array(32768):[];o0;)r[r.l++]=t[o++];a=8*r.l}else{a=J(r,a,+!(o+s!=t.length)+2);for(var l=0;s-- >0;){var c=t[o],f=-1,h=0;if((f=i[l=32767&(l<<5^c)])&&((f|=-32768&o)>o&&(f-=32768),f2){(c=n[h])<=22?a=Y(r,a,z[c+1]>>1)-1:(Y(r,a,3),Y(r,a+=5,z[c-23]>>5),a+=3);var u=c<8?0:c-4>>2;u>0&&(K(r,a,h-I[c]),a+=u),c=e[o-f],a=Y(r,a,z[c]>>3),a-=3;var p=c<4?0:c-2>>1;p>0&&(K(r,a,o-f-R[c]),a+=p);for(var d=0;d>>3;return(e[n]|(r<=4?0:e[n+1]<<8))>>>r&15}(e,t+=5)+4;t+=4;for(var o=0,i=$?new Uint8Array(19):Q(19),s=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],l=1,c=$?new Uint8Array(8):Q(8),f=$?new Uint8Array(8):Q(8),h=i.length,u=0;u>8-d;for(var m=(1<<7-d)-1;m>=0;--m)fe[p|m<>>=3){case 16:for(o=3+W(e,t),t+=2,p=g[g.length-1];o-- >0;)g.push(p);break;case 17:for(o=3+H(e,t),t+=3;o-- >0;)g.push(0);break;case 18:for(o=11+V(e,t),t+=7;o-- >0;)g.push(0);break;default:g.push(p),l>>0,c=0,f=0;!(1&n);)if(n=H(e,r),r+=3,n>>>1!=0)for(n>>1==1?(c=9,f=5):(r=pe(e,r),c=he,f=ue);;){!t&&i>>1==1?ne[h]:le[h];if(r+=15&u,(u>>>=4)>>>8&255){if(256==u)break;var p=(u-=257)<8?0:u-4>>2;p>5&&(p=0);var d=o+I[u];p>0&&(d+=G(e,r,p),r+=p),h=G(e,r,f),r+=15&(u=n>>>1==1?ae[h]:ce[h]);var m=(u>>>=4)<4?0:u-2>>1,g=R[u];for(m>0&&(g+=G(e,r,m),r+=m),!t&&i>>3]|e[1+(r>>>3)]<<8;if(r+=32,v>0)for(!t&&i0;)a[o++]=e[r>>>3],r+=8}return t?[a,r+7>>>3]:[a.slice(0,o),r+7>>>3]}(e.slice(e.l||0),t);return e.l+=r[1],r[0]}function me(e,t){if(!e)throw new Error(t);"undefined"!=typeof console&&console.error(t)}function ge(e,t){var r=e;Tt(r,0);var n={FileIndex:[],FullPaths:[]};C(n,{root:t.root});for(var a=r.length-4;(80!=r[a]||75!=r[a+1]||5!=r[a+2]||6!=r[a+3])&&a>=0;)--a;r.l=a+4,r.l+=4;var o=r.read_shift(2);r.l+=6;var i=r.read_shift(4);for(r.l=i,a=0;a>>=5);r>>>=4,n.setMilliseconds(0),n.setFullYear(r+1980),n.setMonth(o-1),n.setDate(a);var i=31&t,s=63&(t>>>=5);return t>>>=6,n.setHours(t),n.setMinutes(s),n.setSeconds(i<<1),n}(e);if(8257&o)throw new Error("Unsupported ZIP encryption");e.read_shift(4);for(var l=e.read_shift(4),c=e.read_shift(4),f=e.read_shift(2),h=e.read_shift(2),u="",p=0;p>2,s=(3&n)<<4|(a=e[f++])>>4,l=(15&a)<<2|(o=e[f++])>>6,c=63&o,isNaN(a)?l=c=64:isNaN(o)&&(c=64),r+=t.charAt(i)+t.charAt(s)+t.charAt(l)+t.charAt(c);return r}(new Uint8Array(ne(a)));return chrome.downloads.download({url:l,filename:e,saveAs:!0})}}if("undefined"!=typeof $&&"undefined"!=typeof File&&"undefined"!=typeof Folder)try{var c=File(e);return c.open("w"),c.encoding="binary",Array.isArray(r)&&(r=function(e){if(Array.isArray(e))return e.map((function(e){return String.fromCharCode(e)})).join("");for(var t=[],r=0;r=60&&e<61)return e;var t=new Date;return t.setTime(24*(e>60?e:e+1)*60*60*1e3+se),t}var ue=/^(\d+):(\d+)(:\d+)?(\.\d+)?$/,pe=/^(\d+)-(\d+)-(\d+)$/,de=/^(\d+)-(\d+)-(\d+)[T ](\d+):(\d+)(:\d+)?(\.\d+)?$/;function me(e,t){if(e instanceof Date)return e;var r=e.match(ue);return r?new Date((t?ce:le)+1e3*(60*(60*parseInt(r[1],10)+parseInt(r[2],10))+(r[3]?parseInt(r[3].slice(1),10):0))+(r[4]?parseInt((r[4]+"000").slice(1,4),10):0)):(r=e.match(pe))?new Date(Date.UTC(+r[1],+r[2]-1,+r[3],0,0,0,0)):(r=e.match(de))?new Date(Date.UTC(+r[1],+r[2]-1,+r[3],+r[4],+r[5],r[6]&&parseInt(r[6].slice(1),10)||0,r[7]&&parseInt(r[7].slice(1),10)||0)):new Date(e)}function ge(e){if("undefined"!=typeof JSON&&!Array.isArray(e))return JSON.parse(JSON.stringify(e));if("object"!=typeof e||null==e)return e;if(e instanceof Date)return new Date(e.getTime());var t={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=ge(e[r]));return t}function ve(e,t){for(var r="";r.length3&&-1==Se.indexOf(t))return o}else if(t.replace(/[ap]m?/,"").match(/[a-z]/))return o;return i<0||i>8099||e.match(/[^-0-9:,\/\\\ ]/)?o:a}function _e(e){return new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds()))}function Ae(e,t,r){if(e.FullPaths){var n;if("string"==typeof r)return n=a?o(r):function(e){for(var t=[],r=0,n=e.length+250,a=s(e.length+255),o=0;o>6&31,a[r++]=128|63&i;else if(i>=55296&&i<57344){i=64+(1023&i);var l=1023&e.charCodeAt(++o);a[r++]=240|i>>8&7,a[r++]=128|i>>2&63,a[r++]=128|l>>6&15|(3&i)<<4,a[r++]=128|63&l}else a[r++]=224|i>>12&15,a[r++]=128|i>>6&63,a[r++]=128|63&i;r>n&&(t.push(a.slice(0,r)),r=0,a=s(65535),n=65530)}return t.push(a.slice(0,r)),h(t)}(r),re.utils.cfb_add(e,t,n);re.utils.cfb_add(e,t,r)}else e.file(t,r)}var Te='\r\n',De=ie({""":'"',"'":"'",">":">","<":"<","&":"&"}),Oe=/[&<>'"]/g,Ee=/[\u0000-\u0008\u000b-\u001f\uFFFE-\uFFFF]/g;function Fe(e){return(e+"").replace(Oe,(function(e){return De[e]})).replace(Ee,(function(e){return"_x"+("000"+e.charCodeAt(0).toString(16)).slice(-4)+"_"}))}var Me=/[\u0000-\u001f]/g;function Ne(e){return(e+"").replace(Oe,(function(e){return De[e]})).replace(/\n/g,"
").replace(Me,(function(e){return"&#x"+("000"+e.charCodeAt(0).toString(16)).slice(-4)+";"}))}function Pe(e){for(var t="",r=0,n=0,a=0,o=0,i=0,s=0;r191&&n<224?(i=(31&n)<<6,i|=63&a,t+=String.fromCharCode(i)):(o=e.charCodeAt(r++),n<240?t+=String.fromCharCode((15&n)<<12|(63&a)<<6|63&o):(s=((7&n)<<18|(63&a)<<12|(63&o)<<6|63&(i=e.charCodeAt(r++)))-65536,t+=String.fromCharCode(55296+(s>>>10&1023)),t+=String.fromCharCode(56320+(1023&s)))));return t}function Ie(e){var t,r,n,a=s(2*e.length),o=1,i=0,l=0;for(r=0;r>>10&1023),t=56320+(1023&t)),0!==l&&(a[i++]=255&l,a[i++]=l>>>8,l=0),a[i++]=t%256,a[i++]=t>>>8;return a.slice(0,i).toString("ucs2")}function Re(e){return o(e,"binary").toString("utf8")}var Le="foo bar baz☃🍣",Ue=a&&(Re(Le)==Pe(Le)&&Re||Ie(Le)==Pe(Le)&&Ie)||Pe,$e=a?function(e){return o(e,"utf8").toString("binary")}:function(e){for(var t=[],r=0,n=0,a=0;r>6))),t.push(String.fromCharCode(128+(63&n)));break;case n>=55296&&n<57344:n-=55296,a=e.charCodeAt(r++)-56320+(n<<10),t.push(String.fromCharCode(240+(a>>18&7))),t.push(String.fromCharCode(144+(a>>12&63))),t.push(String.fromCharCode(128+(a>>6&63))),t.push(String.fromCharCode(128+(63&a)));break;default:t.push(String.fromCharCode(224+(n>>12))),t.push(String.fromCharCode(128+(n>>6&63))),t.push(String.fromCharCode(128+(63&n)))}return t.join("")},ze=function(){var e=[["nbsp"," "],["middot","·"],["quot",'"'],["apos","'"],["gt",">"],["lt","<"],["amp","&"]].map((function(e){return[new RegExp("&"+e[0]+";","ig"),e[1]]}));return function(t){for(var r=t.replace(/^[\t\n\r ]+/,"").replace(/[\t\n\r ]+$/,"").replace(/>\s+/g,">").replace(/\s+/g,"\n").replace(/<[^>]*>/g,""),n=0;n"+t+""}function We(e){return oe(e).map((function(t){return" "+t+'="'+e[t]+'"'})).join("")}function He(e,t,r){return"<"+e+(null!=r?We(r):"")+(null!=t?(t.match(je)?' xml:space="preserve"':"")+">"+t+""}function Xe(e,t){try{return e.toISOString().replace(/\.\d*/,"")}catch(e){if(t)throw e}return""}var Ve={CORE_PROPS:"http://schemas.openxmlformats.org/package/2006/metadata/core-properties",CUST_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/custom-properties",EXT_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",CT:"http://schemas.openxmlformats.org/package/2006/content-types",RELS:"http://schemas.openxmlformats.org/package/2006/relationships",TCMNT:"http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments",dc:"http://purl.org/dc/elements/1.1/",dcterms:"http://purl.org/dc/terms/",dcmitype:"http://purl.org/dc/dcmitype/",mx:"http://schemas.microsoft.com/office/mac/excel/2008/main",r:"http://schemas.openxmlformats.org/officeDocument/2006/relationships",sjs:"http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties",vt:"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",xsi:"http://www.w3.org/2001/XMLSchema-instance",xsd:"http://www.w3.org/2001/XMLSchema"},Ge=["http://schemas.openxmlformats.org/spreadsheetml/2006/main","http://purl.oclc.org/ooxml/spreadsheetml/main","http://schemas.microsoft.com/office/excel/2006/main","http://schemas.microsoft.com/office/excel/2006/2"],Je={o:"urn:schemas-microsoft-com:office:office",x:"urn:schemas-microsoft-com:office:excel",ss:"urn:schemas-microsoft-com:office:spreadsheet",dt:"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882",mv:"http://macVmlSchemaUri",v:"urn:schemas-microsoft-com:vml",html:"http://www.w3.org/TR/REC-html40"};var qe=function(e){for(var t=[],r=0;r0&&Buffer.isBuffer(e[0][0])?Buffer.concat(e[0].map((function(e){return Buffer.isBuffer(e)?e:o(e)}))):qe(e)}:qe,Ke=function(e,t,r){for(var n=[],a=t;a0?rt(e,t+4,t+4+r-1):""},at=nt,ot=function(e,t){var r=bt(e,t);return r>0?rt(e,t+4,t+4+r-1):""},it=ot,st=function(e,t){var r=2*bt(e,t);return r>0?rt(e,t+4,t+4+r-1):""},lt=st,ct=function(e,t){var r=bt(e,t);return r>0?Ze(e,t+4,t+4+r):""},ft=ct,ht=function(e,t){var r=bt(e,t);return r>0?rt(e,t+4,t+4+r):""},ut=ht,pt=function(e,t){return function(e,t){for(var r=1-2*(e[t+7]>>>7),n=((127&e[t+7])<<4)+(e[t+6]>>>4&15),a=15&e[t+6],o=5;o>=0;--o)a=256*a+e[t+o];return 2047==n?0==a?r*(1/0):NaN:(0==n?n=-1022:(n-=1023,a+=Math.pow(2,52)),r*Math.pow(2,n-52)*a)}(e,t)},dt=pt;a&&(at=function(e,t){if(!Buffer.isBuffer(e))return nt(e,t);var r=e.readUInt32LE(t);return r>0?e.toString("utf8",t+4,t+4+r-1):""},it=function(e,t){if(!Buffer.isBuffer(e))return ot(e,t);var r=e.readUInt32LE(t);return r>0?e.toString("utf8",t+4,t+4+r-1):""},lt=function(e,t){if(!Buffer.isBuffer(e)||!i)return st(e,t);var r=2*e.readUInt32LE(t);return e.toString("utf16le",t+4,t+4+r-1)},ft=function(e,t){if(!Buffer.isBuffer(e)||!i)return ct(e,t);var r=e.readUInt32LE(t);return e.toString("utf16le",t+4,t+4+r)},ut=function(e,t){if(!Buffer.isBuffer(e))return ht(e,t);var r=e.readUInt32LE(t);return e.toString("utf8",t+4,t+4+r)},dt=function(e,t){return Buffer.isBuffer(e)?e.readDoubleLE(t):pt(e,t)});var mt=function(e,t){return e[t]},gt=function(e,t){return 256*e[t+1]+e[t]},vt=function(e,t){var r=256*e[t+1]+e[t];return r<32768?r:-1*(65535-r+1)},bt=function(e,t){return e[t+3]*(1<<24)+(e[t+2]<<16)+(e[t+1]<<8)+e[t]},xt=function(e,t){return e[t+3]<<24|e[t+2]<<16|e[t+1]<<8|e[t]},wt=function(e,t){return e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3]};function yt(t,r){var n,o,s,l,c,f,h="",u=[];switch(r){case"dbcs":if(f=this.l,a&&Buffer.isBuffer(this)&&i)h=this.slice(this.l,this.l+2*t).toString("utf16le");else for(c=0;c0?xt:wt)(this,this.l),this.l+=4,n);case 8:case-8:if("f"===r)return o=8==t?dt(this,this.l):dt([this[this.l+7],this[this.l+6],this[this.l+5],this[this.l+4],this[this.l+3],this[this.l+2],this[this.l+1],this[this.l+0]],0),this.l+=8,o;t=8;case 16:h=et(this,this.l,t)}}return this.l+=t,h}var Ct=function(e,t,r){e[r]=255&t,e[r+1]=t>>>8&255,e[r+2]=t>>>16&255,e[r+3]=t>>>24&255},St=function(e,t,r){e[r]=255&t,e[r+1]=t>>8&255,e[r+2]=t>>16&255,e[r+3]=t>>24&255},kt=function(e,t,r){e[r]=255&t,e[r+1]=t>>>8&255};function _t(e,t,r){var n=0,a=0;if("dbcs"===r){for(a=0;a!=t.length;++a)kt(this,t.charCodeAt(a),this.l+2*a);n=2*t.length}else if("sbcs"===r||"cpstr"==r){for(t=t.replace(/[^\x00-\x7F]/g,"_"),a=0;a!=t.length;++a)this[this.l+a]=255&t.charCodeAt(a);n=t.length}else{if("hex"===r){for(;a>8}for(;this.l>>=8,this[this.l+1]=255&t;break;case 3:n=3,this[this.l]=255&t,t>>>=8,this[this.l+1]=255&t,t>>>=8,this[this.l+2]=255&t;break;case 4:n=4,Ct(this,t,this.l);break;case 8:if(n=8,"f"===r){!function(e,t,r){var n=(t<0||1/t==-1/0?1:0)<<7,a=0,o=0,i=n?-t:t;isFinite(i)?0==i?a=o=0:(a=Math.floor(Math.log(i)/Math.LN2),o=i*Math.pow(2,52-a),a<=-1023&&(!isFinite(o)||o>4|n}(this,t,this.l);break}case 16:break;case-4:n=4,St(this,t,this.l)}}return this.l+=n,this}function At(e,t){var r=et(this,this.l,e.length>>1);if(r!==e)throw new Error(t+"Expected "+e+" saw "+r);this.l+=e.length>>1}function Tt(e,t){e.l=t,e.read_shift=yt,e.chk=At,e.write_shift=_t}function Dt(e){var t=s(e);return Tt(t,0),t}function Ot(e){return""+(e+1)}function Et(e){if(e<0)throw new Error("invalid column "+e);var t="";for(++e;e;e=Math.floor((e-1)/26))t=String.fromCharCode((e-1)%26+65)+t;return t}function Ft(e){for(var t=0,r=0,n=0;n=48&&a<=57?t=10*t+(a-48):a>=65&&a<=90&&(r=26*r+(a-64))}return{c:r-1,r:t-1}}function Mt(e){for(var t=e.c+1,r="";t;t=(t-1)/26|0)r=String.fromCharCode((t-1)%26+65)+r;return r+(e.r+1)}function Nt(e){var t=e.indexOf(":");return-1==t?{s:Ft(e),e:Ft(e)}:{s:Ft(e.slice(0,t)),e:Ft(e.slice(t+1))}}function Pt(e,t){return void 0===t||"number"==typeof t?Pt(e.s,e.e):("string"!=typeof e&&(e=Mt(e)),"string"!=typeof t&&(t=Mt(t)),e==t?e:e+":"+t)}function It(e){var t=Nt(e);return"$"+Et(t.s.c)+"$"+Ot(t.s.r)+":$"+Et(t.e.c)+"$"+Ot(t.e.r)}function Rt(e,t){if(!(e||t&&t.biff<=5&&t.biff>=2))throw new Error("empty sheet name");return/[^\w\u4E00-\u9FFF\u3040-\u30FF]/.test(e)?"'"+e.replace(/'/g,"''")+"'":e}function Lt(e){var t={s:{c:0,r:0},e:{c:0,r:0}},r=0,n=0,a=0,o=e.length;for(r=0;n26);++n)r=26*r+a;for(t.s.c=--r,r=0;n9);++n)r=10*r+a;if(t.s.r=--r,n===o||10!=a)return t.e.c=t.s.c,t.e.r=t.s.r,t;for(++n,r=0;n!=o&&!((a=e.charCodeAt(n)-64)<1||a>26);++n)r=26*r+a;for(t.e.c=--r,r=0;n!=o&&!((a=e.charCodeAt(n)-48)<0||a>9);++n)r=10*r+a;return t.e.r=--r,t}function Ut(e,t){var r="d"==e.t&&t instanceof Date;if(null!=e.z)try{return e.w=Z(e.z,r?fe(t):t)}catch(e){}try{return e.w=Z((e.XF||{}).numFmtId||(r?14:0),r?fe(t):t)}catch(e){return""+t}}function $t(e,t,r){return null==e||null==e.t||"z"==e.t?"":void 0!==e.w?e.w:("d"==e.t&&!e.z&&r&&r.dateNF&&(e.z=r.dateNF),"e"==e.t?jt[e.v]||e.v:Ut(e,null==t?e.v:t))}function zt(e,t,r){var n=r||{},a=e?null!=e["!data"]:n.dense,o=e||{};a&&!o["!data"]&&(o["!data"]=[]);var i=0,s=0;if(o&&null!=n.origin){if("number"==typeof n.origin)i=n.origin;else{var l="string"==typeof n.origin?Ft(n.origin):n.origin;i=l.r,s=l.c}o["!ref"]||(o["!ref"]="A1:A1")}var c={s:{c:1e7,r:1e7},e:{c:0,r:0}};if(o["!ref"]){var f=Lt(o["!ref"]);c.s.c=f.s.c,c.s.r=f.s.r,c.e.c=Math.max(c.e.c,f.e.c),c.e.r=Math.max(c.e.r,f.e.r),-1==i&&(c.e.r=i=f.e.r+1)}for(var h=[],u=0;u!=t.length;++u)if(t[u]){if(!Array.isArray(t[u]))throw new Error("aoa_to_sheet expects an array of arrays");var p=i+u,d=""+(p+1);a&&(o["!data"][p]||(o["!data"][p]=[]),h=o["!data"][p]);for(var m=0;m!=t[u].length;++m)if(void 0!==t[u][m]){var g={v:t[u][m]},v=s+m;if(c.s.r>p&&(c.s.r=p),c.s.c>v&&(c.s.c=v),c.e.r0&&(n=e[r][0],o[o.length]=He("Override",null,{PartName:("/"==n[0]?"":"/")+n,ContentType:Wt[r][t.bookType]||Wt[r].xlsx}))},s=function(r){(e[r]||[]).forEach((function(e){o[o.length]=He("Override",null,{PartName:("/"==e[0]?"":"/")+e,ContentType:Wt[r][t.bookType]||Wt[r].xlsx})}))},l=function(t){(e[t]||[]).forEach((function(e){o[o.length]=He("Override",null,{PartName:("/"==e[0]?"":"/")+e,ContentType:a[t][0]})}))};return i("workbooks"),s("sheets"),s("charts"),l("themes"),["strs","styles"].forEach(i),["coreprops","extprops","custprops"].forEach(l),l("vba"),l("comments"),l("threadedcomments"),l("drawings"),s("metadata"),l("people"),!r&&o.length>2&&(o[o.length]="",o[1]=o[1].replace("/>",">")),o.join("")}var Xt={WB:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",SHEET:"http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",HLINK:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",VML:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",XPATH:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",XMISS:"http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",XLINK:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",CXML:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml",CXMLP:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",CMNT:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",CORE_PROPS:"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",EXT_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",CUST_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties",SST:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",STY:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",THEME:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",CHART:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",CHARTEX:"http://schemas.microsoft.com/office/2014/relationships/chartEx",CS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet",WS:["http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet","http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"],DS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet",MS:"http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet",IMG:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",DRAW:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",XLMETA:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata",TCMNT:"http://schemas.microsoft.com/office/2017/10/relationships/threadedComment",PEOPLE:"http://schemas.microsoft.com/office/2017/10/relationships/person",CONN:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/connections",VBA:"http://schemas.microsoft.com/office/2006/relationships/vbaProject"};function Vt(e){var t=[Te,He("Relationships",null,{xmlns:Ve.RELS})];return oe(e["!id"]).forEach((function(r){t[t.length]=He("Relationship",null,e["!id"][r])})),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}function Gt(e,t,r,n,a,o){if(a||(a={}),e["!id"]||(e["!id"]={}),e["!idx"]||(e["!idx"]=1),t<0)for(t=e["!idx"];e["!id"]["rId"+t];++t);if(e["!idx"]=t+1,a.Id="rId"+t,a.Type=n,a.Target=r,o?a.TargetMode=o:[Xt.HLINK,Xt.XPATH,Xt.XMISS].indexOf(a.Type)>-1&&(a.TargetMode="External"),e["!id"][a.Id])throw new Error("Cannot rewrite rId "+t);return e["!id"][a.Id]=a,e[("/"+a.Target).replace("//","/")]=a,t}var Jt=[["cp:category","Category"],["cp:contentStatus","ContentStatus"],["cp:keywords","Keywords"],["cp:lastModifiedBy","LastAuthor"],["cp:lastPrinted","LastPrinted"],["cp:revision","RevNumber"],["cp:version","Version"],["dc:creator","Author"],["dc:description","Comments"],["dc:identifier","Identifier"],["dc:language","Language"],["dc:subject","Subject"],["dc:title","Title"],["dcterms:created","CreatedDate","date"],["dcterms:modified","ModifiedDate","date"]];function qt(e,t,r,n,a){null==a[e]&&null!=t&&""!==t&&(a[e]=t,t=Fe(t),n[n.length]=r?He(e,t,r):Be(e,t))}var Yt=[["Application","Application","string"],["AppVersion","AppVersion","string"],["Company","Company","string"],["DocSecurity","DocSecurity","string"],["Manager","Manager","string"],["HyperlinksChanged","HyperlinksChanged","bool"],["SharedDoc","SharedDoc","bool"],["LinksUpToDate","LinksUpToDate","bool"],["ScaleCrop","ScaleCrop","bool"],["HeadingPairs","HeadingPairs","raw"],["TitlesOfParts","TitlesOfParts","raw"]];function Kt(e){var t=[Te,He("Properties",null,{xmlns:Ve.CUST_PROPS,"xmlns:vt":Ve.vt})];if(!e)return t.join("");var r=1;return oe(e).forEach((function(n){++r,t[t.length]=He("property",function(e,t){switch(typeof e){case"string":var r=He("vt:lpwstr",Fe(e));return t&&(r=r.replace(/"/g,"_x0022_")),r;case"number":return He((0|e)==e?"vt:i4":"vt:r8",Fe(String(e)));case"boolean":return He("vt:bool",e?"true":"false")}if(e instanceof Date)return He("vt:filetime",Xe(e));throw new Error("Unable to serialize "+e)}(e[n],!0),{fmtid:"{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",pid:r,name:Fe(n)})})),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}var Zt=/^\s|\s$|[\t\n\r]/;var Qt=6;var er=96;function tr(e){return 96*e/er}function rr(e,t){var r,n=[Te,He("styleSheet",null,{xmlns:Ge[0],"xmlns:vt":Ve.vt})];return e.SSF&&null!=(r=function(e){var t=[""];return[[5,8],[23,26],[41,44],[50,392]].forEach((function(r){for(var n=r[0];n<=r[1];++n)null!=e[n]&&(t[t.length]=He("numFmt",null,{numFmtId:n,formatCode:Fe(e[n])}))})),1===t.length?"":(t[t.length]="",t[0]=He("numFmts",null,{count:t.length-2}).replace("/>",">"),t.join(""))}(e.SSF))&&(n[n.length]=r),n[n.length]='',n[n.length]='',n[n.length]='',n[n.length]='',(r=function(e){var t=[];return t[t.length]=He("cellXfs",null),e.forEach((function(e){t[t.length]=He("xf",null,e)})),t[t.length]="",2===t.length?"":(t[0]=He("cellXfs",null,{count:t.length-2}).replace("/>",">"),t.join(""))}(t.cellXfs))&&(n[n.length]=r),n[n.length]='',n[n.length]='',n[n.length]='',n.length>2&&(n[n.length]="",n[1]=n[1].replace("/>",">")),n.join("")}function nr(e,t,r){var n=[21600,21600],a=["m0,0l0",n[1],n[0],n[1],n[0],"0xe"].join(","),o=[He("xml",null,{"xmlns:v":Je.v,"xmlns:o":Je.o,"xmlns:x":Je.x,"xmlns:mv":Je.mv}).replace(/\/>/,">"),He("o:shapelayout",He("o:idmap",null,{"v:ext":"edit",data:e}),{"v:ext":"edit"})],i=65536*e,s=t||[];return s.length>0&&o.push(He("v:shapetype",[He("v:stroke",null,{joinstyle:"miter"}),He("v:path",null,{gradientshapeok:"t","o:connecttype":"rect"})].join(""),{id:"_x0000_t202",coordsize:n.join(","),"o:spt":202,path:a})),s.forEach((function(e){++i,o.push(function(e,t,r){var n=Ft(e[0]),a={color2:"#BEFF82",type:"gradient"};"gradient"==a.type&&(a.angle="-180");var o="gradient"==a.type?He("o:fill",null,{type:"gradientUnscaled","v:ext":"view"}):null,i=He("v:fill",o,a),s={on:"t",obscured:"t"};return["",i,He("v:shadow",null,s),He("v:path",null,{"o:connecttype":"none"}),'
','',"","",Be("x:Anchor",[n.c+1,0,n.r+1,0,n.c+3,20,n.r+5,20].join(",")),Be("x:AutoFill","False"),Be("x:Row",String(n.r)),Be("x:Column",String(n.c)),e[1].hidden?"":"","",""].join("")}(e,i))})),o.push(""),o.join("")}function ar(e){var t=[Te,He("comments",null,{xmlns:Ge[0]})],r=[];return t.push(""),e.forEach((function(e){e[1].forEach((function(e){var n=Fe(e.a);-1==r.indexOf(n)&&(r.push(n),t.push(""+n+"")),e.T&&e.ID&&-1==r.indexOf("tc="+e.ID)&&(r.push("tc="+e.ID),t.push("tc="+e.ID+""))}))})),0==r.length&&(r.push("SheetJ5"),t.push("SheetJ5")),t.push(""),t.push(""),e.forEach((function(e){var n=0,a=[],o=0;if(e[1][0]&&e[1][0].T&&e[1][0].ID&&(n=r.indexOf("tc="+e[1][0].ID)),e[1].forEach((function(e){e.a&&(n=r.indexOf(Fe(e.a))),e.T&&++o,a.push(null==e.t?"":Fe(e.t))})),0===o)e[1].forEach((function(n){t.push(''),t.push(Be("t",null==n.t?"":Fe(n.t))),t.push("")}));else{e[1][0]&&e[1][0].T&&e[1][0].ID&&(n=r.indexOf("tc="+e[1][0].ID)),t.push('');for(var i="Comment:\n "+a[0]+"\n",s=1;s")}})),t.push(""),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}function or(e,t,r){var n=[Te,He("ThreadedComments",null,{xmlns:Ve.TCMNT}).replace(/[\/]>/,">")];return e.forEach((function(e){var a="";(e[1]||[]).forEach((function(o,i){if(o.T){o.a&&-1==t.indexOf(o.a)&&t.push(o.a);var s={ref:e[0],id:"{54EE7951-7262-4200-6969-"+("000000000000"+r.tcid++).slice(-12)+"}"};0==i?a=s.id:s.parentId=a,o.ID=s.id,o.a&&(s.personId="{54EE7950-7262-4200-6969-"+("000000000000"+t.indexOf(o.a)).slice(-12)+"}"),n.push(He("threadedComment",Be("text",o.t||""),s))}else delete o.ID}))})),n.push(""),n.join("")}var ir=["xlsb","xlsm","xlam","biff8","xla"],sr="undefined"!=typeof Map;function lr(e,t){var r,n,a={min:e+1,max:e+1},o=-1;return t.MDW&&(Qt=t.MDW),null!=t.width?a.customWidth=1:null!=t.wpx?(r=t.wpx,o=Math.floor((r-5)/Qt*100+.5)/100):null!=t.wch&&(o=t.wch),o>-1?(a.width=(n=o,Math.round((n*Qt+5)/Qt*256)/256),a.customWidth=1):null!=t.width&&(a.width=t.width),t.hidden&&(a.hidden=!0),null!=t.level&&(a.outlineLevel=a.level=t.level),a}function cr(e,t,r){var n,a,o=r.revssf[null!=t.z?t.z:"General"],i=60,s=e.length;if(null==o&&r.ssf)for(;i<392;++i)if(null==r.ssf[i]){n=t.z,a=i,Q(ee[n]||n,a),r.ssf[i]=t.z,r.revssf[t.z]=o=i;break}for(i=0;i!=s;++i)if(e[i].numFmtId===o)return i;return e[s]={numFmtId:o,fontId:0,fillId:0,borderId:0,xfId:0,applyNumberFormat:1},s}function fr(e,t,r){if(e&&e["!ref"]){var n=Lt(e["!ref"]);if(n.e.c=0;--r)n=((16384&n?1:0)|n<<1&32767)^t[r];return 52811^n}(e.password).toString(16).toUpperCase()),He("sheetProtection",null,t)}function dr(e,t,r,n,a,o,i){if(e.c&&r["!comments"].push([t,e.c]),(void 0===e.v||"z"===e.t&&!(n||{}).sheetStubs)&&"string"!=typeof e.f&&void 0===e.z)return"";var s="",l=e.t,c=e.v;if("z"!==e.t)switch(e.t){case"b":s=e.v?"1":"0";break;case"n":isNaN(e.v)?(e.t="e",s=jt[e.v=36]):isFinite(e.v)?s=""+e.v:(e.t="e",s=jt[e.v=7]);break;case"e":s=jt[e.v];break;case"d":if(n&&n.cellDates){var f=me(e.v,i);s=f.toISOString(),f.getUTCFullYear()<1900&&(s=s.slice(s.indexOf("T")+1).replace("Z",""))}else(e=ge(e)).t="n",s=""+(e.v=fe(me(e.v,i),i));void 0===e.z&&(e.z=S[14]);break;default:s=e.v}var h="z"==e.t||null==e.v?"":Be("v",Fe(s)),u={r:t},p=cr(n.cellXfs,e,n);switch(0!==p&&(u.s=p),e.t){case"n":case"z":break;case"d":u.t="d";break;case"b":u.t="b";break;case"e":u.t="e";break;default:if(null==e.v){delete e.t;break}if(e.v.length>32767)throw new Error("Text length must not exceed 32767 characters");if(n&&n.bookSST){h=Be("v",""+function(e,t,r){var n=0,a=e.length;if(r){if(sr?r.has(t):Object.prototype.hasOwnProperty.call(r,t))for(var o=sr?r.get(t):r[t];n16383||f.e.r>1048575){if(t.WTF)throw new Error("Range "+c+" exceeds format limit A1:XFD1048576");f.e.c=Math.min(f.e.c,16383),f.e.r=Math.min(f.e.c,1048575),c=Pt(f)}n||(n={}),l["!comments"]=[];var h=[];!function(e,t,r,n,a){var o=!1,i={},s=null;if("xlsx"!==n.bookType&&t.vbaraw){var l=t.SheetNames[r];try{t.Workbook&&(l=t.Workbook.Sheets[r].CodeName||l)}catch(e){}o=!0,i.codeName=$e(Fe(l))}if(e&&e["!outline"]){var c={summaryBelow:1,summaryRight:1};e["!outline"].above&&(c.summaryBelow=0),e["!outline"].left&&(c.summaryRight=0),s=(s||"")+He("outlinePr",null,c)}(o||s)&&(a[a.length]=He("sheetPr",s,i))}(l,r,e,t,o),o[o.length]=He("dimension",null,{ref:c}),o[o.length]=function(e,t,r,n){var a={workbookViewId:"0"};return(((n||{}).Workbook||{}).Views||[])[0]&&(a.rightToLeft=n.Workbook.Views[0].RTL?"1":"0"),He("sheetViews",He("sheetView",null,a),{})}(0,0,0,r),t.sheetFormat&&(o[o.length]=He("sheetFormatPr",null,{defaultRowHeight:t.sheetFormat.defaultRowHeight||"16",baseColWidth:t.sheetFormat.baseColWidth||"10",outlineLevelRow:t.sheetFormat.outlineLevelRow||"7"})),null!=l["!cols"]&&l["!cols"].length>0&&(o[o.length]=function(e,t){for(var r,n=[""],a=0;a!=t.length;++a)(r=t[a])&&(n[n.length]=He("col",null,lr(a,r)));return n[n.length]="",n.join("")}(0,l["!cols"])),o[a=o.length]="",l["!links"]=[],null!=l["!ref"]&&(s=function(e,t,r,n){var a,o,i=[],s=[],l=Lt(e["!ref"]),c="",f="",h=[],u=0,p=0,d=e["!rows"],m=null!=e["!data"],g={r:f},v=-1,b=(((n||{}).Workbook||{}).WBProps||{}).date1904;for(p=l.s.c;p<=l.e.c;++p)h[p]=Et(p);for(u=l.s.r;u<=l.e.r;++u){for(s=[],f=Ot(u),p=l.s.c;p<=l.e.c;++p){a=h[p]+f;var x=m?(e["!data"][u]||[])[p]:e[a];void 0!==x&&null!=(c=dr(x,a,e,t,0,0,b))&&s.push(c)}(s.length>0||d&&d[u])&&(g={r:f},d&&d[u]&&((o=d[u]).hidden&&(g.hidden=1),v=-1,o.hpx?v=tr(o.hpx):o.hpt&&(v=o.hpt),v>-1&&(g.ht=v,g.customHeight=1),o.level&&(g.outlineLevel=o.level)),i[i.length]=He("row",s.join(""),g))}if(d)for(;u-1&&(g.ht=v,g.customHeight=1),o.level&&(g.outlineLevel=o.level),i[i.length]=He("row","",g));return i.join("")}(l,t,0,r),s.length>0&&(o[o.length]=s)),o.length>a+1&&(o[o.length]="",o[a]=o[a].replace("/>",">")),l["!protect"]&&(o[o.length]=pr(l["!protect"])),null!=l["!autofilter"]&&(o[o.length]=function(e,t,r,n){var a="string"==typeof e.ref?e.ref:Pt(e.ref);r.Workbook||(r.Workbook={Sheets:[]}),r.Workbook.Names||(r.Workbook.Names=[]);var o=r.Workbook.Names,i=Nt(a);i.s.r==i.e.r&&(i.e.r=Nt(t["!ref"]).e.r,a=Pt(i));for(var s=0;s0&&(o[o.length]=function(e){if(0===e.length)return"";for(var t='',r=0;r!=e.length;++r)t+='';return t+""}(l["!merges"]));var u,p,d=-1,m=-1;return l["!links"].length>0&&(o[o.length]="",l["!links"].forEach((function(e){e[1].Target&&(u={ref:e[0]},"#"!=e[1].Target.charAt(0)&&(m=Gt(n,-1,Fe(e[1].Target).replace(/#.*$/,""),Xt.HLINK),u["r:id"]="rId"+m),(d=e[1].Target.indexOf("#"))>-1&&(u.location=Fe(e[1].Target.slice(d+1))),e[1].Tooltip&&(u.tooltip=Fe(e[1].Tooltip)),u.display=e[1].display,o[o.length]=He("hyperlink",null,u))})),o[o.length]=""),delete l["!links"],null!=l["!margins"]&&(o[o.length]=(function(e,t){if(e){var r=[.7,.7,.75,.75,.3,.3];null==e.left&&(e.left=r[0]),null==e.right&&(e.right=r[1]),null==e.top&&(e.top=r[2]),null==e.bottom&&(e.bottom=r[3]),null==e.header&&(e.header=r[4]),null==e.footer&&(e.footer=r[5])}}(p=l["!margins"]),He("pageMargins",null,p))),t&&!t.ignoreEC&&null!=t.ignoreEC||(o[o.length]=Be("ignoredErrors",He("ignoredError",null,{numberStoredAsText:1,sqref:c}))),h.length>0&&(m=Gt(n,-1,"../drawings/drawing"+(e+1)+".xml",Xt.DRAW),o[o.length]=He("drawing",null,{"r:id":"rId"+m}),l["!drawing"]=h),l["!comments"].length>0&&(m=Gt(n,-1,"../drawings/vmlDrawing"+(e+1)+".vml",Xt.VML),o[o.length]=He("legacyDrawing",null,{"r:id":"rId"+m}),l["!legacy"]=m),o.length>1&&(o[o.length]="",o[1]=o[1].replace("/>",">")),o.join("")}var gr=[["allowRefreshQuery",!1,"bool"],["autoCompressPictures",!0,"bool"],["backupFile",!1,"bool"],["checkCompatibility",!1,"bool"],["CodeName",""],["date1904",!1,"bool"],["defaultThemeVersion",0,"int"],["filterPrivacy",!1,"bool"],["hidePivotFieldList",!1,"bool"],["promptedSolutions",!1,"bool"],["publishItems",!1,"bool"],["refreshAllConnections",!1,"bool"],["saveExternalLinkValues",!0,"bool"],["showBorderUnselectedTables",!0,"bool"],["showInkAnnotation",!0,"bool"],["showObjects","all"],["showPivotChartFilter",!1,"bool"],["updateLinks","userSet"]],vr=":][*?/\\".split("");function br(e,t){try{if(""==e)throw new Error("Sheet name cannot be blank");if(e.length>31)throw new Error("Sheet name cannot exceed 31 chars");if(39==e.charCodeAt(0)||39==e.charCodeAt(e.length-1))throw new Error("Sheet name cannot start or end with apostrophe (')");if("history"==e.toLowerCase())throw new Error("Sheet name cannot be 'History'");vr.forEach((function(t){if(-1!=e.indexOf(t))throw new Error("Sheet name cannot contain : \\ / ? * [ ]")}))}catch(e){if(t)return!1;throw e}return!0}function xr(e){if(!e||!e.SheetNames||!e.Sheets)throw new Error("Invalid Workbook");if(!e.SheetNames.length)throw new Error("Workbook is empty");var t,r,n,a=e.Workbook&&e.Workbook.Sheets||[];t=e.SheetNames,r=a,n=!!e.vbaraw,t.forEach((function(e,a){br(e);for(var o=0;o22)throw new Error("Bad Code Name: Worksheet"+i)}}));for(var o=0;or||a[h].s.c>l||a[h].e.r1&&(i.rowspan=c),f>1&&(i.colspan=f),n.editable?d=''+d+"":p&&(i["data-t"]=p&&p.t||"z",null!=p.v&&(i["data-v"]=p.v instanceof Date?p.v.toISOString():p.v),null!=p.z&&(i["data-z"]=p.z),p.l&&"#"!=(p.l.Target||"#").charAt(0)&&(d=''+d+"")),i.id=(n.id||"sjs")+"-"+u,o.push(He("td",d,i))}}return""+o.join("")+""}function yr(e,t,r){var n=t.rows;if(!n)throw"Unsupported origin when "+t.tagName+" is not a TABLE";var a=r||{},o=null!=e["!data"],i=0,s=0;if(null!=a.origin)if("number"==typeof a.origin)i=a.origin;else{var l="string"==typeof a.origin?Ft(a.origin):a.origin;i=l.r,s=l.c}var c=Math.min(a.sheetRows||1e7,n.length),f={s:{r:0,c:0},e:{r:i,c:s}};if(e["!ref"]){var h=Nt(e["!ref"]);f.s.r=Math.min(f.s.r,h.s.r),f.s.c=Math.min(f.s.c,h.s.c),f.e.r=Math.max(f.e.r,h.e.r),f.e.c=Math.max(f.e.c,h.e.c),-1==i&&(f.e.r=i=h.e.r+1)}var u=[],p=0,d=e["!rows"]||(e["!rows"]=[]),m=0,g=0,v=0,b=0,x=0,w=0;for(e["!cols"]||(e["!cols"]=[]);m1||w>1)&&u.push({s:{r:g+i,c:b+s},e:{r:g+i+(x||1)-1,c:b+s+(w||1)-1}});var D={t:"s",v:_},O=k.getAttribute("data-t")||k.getAttribute("t")||"";null!=_&&(0==_.length?D.t=O||"z":a.raw||0==_.trim().length||"s"==O||("TRUE"===_?D={t:"b",v:!0}:"FALSE"===_?D={t:"b",v:!1}:isNaN(be(_))?isNaN(ke(_).getDate())||(D={t:"d",v:me(_)},a.UTC&&(D.v=_e(D.v)),a.cellDates||(D={t:"n",v:fe(D.v)}),D.z=a.dateNF||S[14]):D={t:"n",v:be(_)})),void 0===D.z&&null!=A&&(D.z=A);var E="",F=k.getElementsByTagName("A");if(F&&F.length)for(var M=0;M=c&&(e["!fullref"]=Pt((f.e.r=n.length-m+g-1+i,f))),e}function Cr(e,t){var r={};return(t||{}).dense&&(r["!data"]=[]),yr(r,e,t)}function Sr(e){var t="",r=function(e){return e.ownerDocument.defaultView&&"function"==typeof e.ownerDocument.defaultView.getComputedStyle?e.ownerDocument.defaultView.getComputedStyle:"function"==typeof getComputedStyle?getComputedStyle:null} -/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */(e);return r&&(t=r(e).getPropertyValue("display")),t||(t=e.style&&e.style.display),"none"===t}function kr(e){var t;(t=[["cellDates",!1],["bookSST",!1],["bookType","xlsx"],["compression",!1],["WTF",!1]],function(e){for(var r=0;r!=t.length;++r){var n=t[r];void 0===e[n[0]]&&(e[n[0]]=n[1]),"n"===n[2]&&(e[n[0]]=Number(e[n[0]]))}})(e)}function _r(e,t){var r;e&&!e.SSF&&(e.SSF=ge(S)),e&&e.SSF&&(r||(r={}),r[0]="General",r[1]="0",r[2]="0.00",r[3]="#,##0",r[4]="#,##0.00",r[9]="0%",r[10]="0.00%",r[11]="0.00E+00",r[12]="# ?/?",r[13]="# ??/??",r[14]="m/d/yy",r[15]="d-mmm-yy",r[16]="d-mmm",r[17]="mmm-yy",r[18]="h:mm AM/PM",r[19]="h:mm:ss AM/PM",r[20]="h:mm",r[21]="h:mm:ss",r[22]="m/d/yy h:mm",r[37]="#,##0 ;(#,##0)",r[38]="#,##0 ;[Red](#,##0)",r[39]="#,##0.00;(#,##0.00)",r[40]="#,##0.00;[Red](#,##0.00)",r[45]="mm:ss",r[46]="[h]:mm:ss",r[47]="mmss.0",r[48]="##0.0E+0",r[49]="@",r[56]='"上午/下午 "hh"時"mm"分"ss"秒 "',S=r,function(e){for(var t=0;392!=t;++t)void 0!==e[t]&&Q(e[t],t)}(e.SSF),t.revssf=function(e){for(var t=[],r=oe(e),n=0;n!==r.length;++n)t[e[r[n]]]=parseInt(r[n],10);return t}(e.SSF),t.revssf[e.SSF[65535]]=0,t.ssf=e.SSF),t.rels={},t.wbrels={},t.Strings=[],t.Strings.Count=0,t.Strings.Unique=0,sr?t.revStrings=new Map:(t.revStrings={},t.revStrings.foo=[],delete t.revStrings.foo);var n="xml",a=ir.indexOf(t.bookType)>-1,o={workbooks:[],sheets:[],charts:[],dialogs:[],macros:[],rels:[],strs:[],comments:[],threadedcomments:[],links:[],coreprops:[],extprops:[],custprops:[],themes:[],styles:[],calcchains:[],vba:[],drawings:[],metadata:[],people:[],TODO:[],xmlns:""};kr(t=t||{});var i,s,l,c=re.utils.cfb_new(),f="",h=0;if(t.cellXfs=[],cr(t.cellXfs,{},{revssf:{General:0}}),e.Props||(e.Props={}),Ae(c,f="docProps/core.xml",function(e,t){var r=t||{},n=[Te,He("cp:coreProperties",null,{"xmlns:cp":Ve.CORE_PROPS,"xmlns:dc":Ve.dc,"xmlns:dcterms":Ve.dcterms,"xmlns:dcmitype":Ve.dcmitype,"xmlns:xsi":Ve.xsi})],a={};if(!e&&!r.Props)return n.join("");e&&(null!=e.CreatedDate&&qt("dcterms:created","string"==typeof e.CreatedDate?e.CreatedDate:Xe(e.CreatedDate,r.WTF),{"xsi:type":"dcterms:W3CDTF"},n,a),null!=e.ModifiedDate&&qt("dcterms:modified","string"==typeof e.ModifiedDate?e.ModifiedDate:Xe(e.ModifiedDate,r.WTF),{"xsi:type":"dcterms:W3CDTF"},n,a));for(var o=0;o!=Jt.length;++o){var i=Jt[o],s=r.Props&&null!=r.Props[i[1]]?r.Props[i[1]]:e?e[i[1]]:null;!0===s?s="1":!1===s?s="0":"number"==typeof s&&(s=String(s)),null!=s&&qt(i[0],s,null,n,a)}return n.length>2&&(n[n.length]="",n[1]=n[1].replace("/>",">")),n.join("")}(e.Props,t)),o.coreprops.push(f),Gt(t.rels,2,f,Xt.CORE_PROPS),f="docProps/app.xml",e.Props&&e.Props.SheetNames);else if(e.Workbook&&e.Workbook.Sheets){for(var u=[],p=0;pWorksheets")+l("vt:variant",l("vt:i4",String(i.Worksheets))),{size:2,baseType:"variant"})),s[s.length]=l("TitlesOfParts",l("vt:vector",i.SheetNames.map((function(e){return""+Fe(e)+""})).join(""),{size:i.Worksheets,baseType:"lpstr"})),s.length>2&&(s[s.length]="",s[1]=s[1].replace("/>",">")),s.join(""))),o.extprops.push(f),Gt(t.rels,3,f,Xt.EXT_PROPS),e.Custprops!==e.Props&&oe(e.Custprops||{}).length>0&&(Ae(c,f="docProps/custom.xml",Kt(e.Custprops)),o.custprops.push(f),Gt(t.rels,4,f,Xt.CUST_PROPS));var d,m,g=["SheetJ5"];for(t.tcid=0,h=1;h<=e.SheetNames.length;++h){var v={"!id":{}},b=e.Sheets[e.SheetNames[h-1]];(b||{})["!type"];if(Ae(c,f="xl/worksheets/sheet"+h+"."+n,mr(h-1,t,e,v)),o.sheets.push(f),Gt(t.wbrels,-1,"worksheets/sheet"+h+"."+n,Xt.WS[0]),b){var x=b["!comments"],w=!1,y="";if(x&&x.length>0){var C=!1;x.forEach((function(e){e[1].forEach((function(e){1==e.T&&(C=!0)}))})),C&&(Ae(c,y="xl/threadedComments/threadedComment"+h+".xml",or(x,g,t)),o.threadedcomments.push(y),Gt(v,-1,"../threadedComments/threadedComment"+h+".xml",Xt.TCMNT)),Ae(c,y="xl/comments"+h+"."+n,ar(x)),o.comments.push(y),Gt(v,-1,"../comments"+h+"."+n,Xt.CMNT),w=!0}b["!legacy"]&&w&&Ae(c,"xl/drawings/vmlDrawing"+h+".vml",nr(h,b["!comments"])),delete b["!comments"],delete b["!legacy"]}v["!id"].rId1&&Ae(c,(m=void 0,m=(d=f).lastIndexOf("/"),d.slice(0,m+1)+"_rels/"+d.slice(m+1)+".rels"),Vt(v))}return null!=t.Strings&&t.Strings.length>0&&(Ae(c,f="xl/sharedStrings."+n,function(e,t){if(!t.bookSST)return"";var r=[Te];r[r.length]=He("sst",null,{xmlns:Ge[0],count:e.Count,uniqueCount:e.Unique});for(var n=0;n!=e.length;++n)if(null!=e[n]){var a=e[n],o="";a.r?o+=a.r:(o+=""),o+="",r[r.length]=o}return r.length>2&&(r[r.length]="",r[1]=r[1].replace("/>",">")),r.join("")}(t.Strings,t)),o.strs.push(f),Gt(t.wbrels,-1,"sharedStrings."+n,Xt.SST)),Ae(c,f="xl/workbook."+n,function(e){var t=[Te];t[t.length]=He("workbook",null,{xmlns:Ge[0],"xmlns:r":Ve.r});var r=e.Workbook&&(e.Workbook.Names||[]).length>0,n={codeName:"ThisWorkbook"};e.Workbook&&e.Workbook.WBProps&&(gr.forEach((function(t){null!=e.Workbook.WBProps[t[0]]&&e.Workbook.WBProps[t[0]]!=t[1]&&(n[t[0]]=e.Workbook.WBProps[t[0]])})),e.Workbook.WBProps.CodeName&&(n.codeName=e.Workbook.WBProps.CodeName,delete n.CodeName)),t[t.length]=He("workbookPr",null,n);var a=e.Workbook&&e.Workbook.Sheets||[],o=0;if(a&&a[0]&&a[0].Hidden){for(t[t.length]="",o=0;o!=e.SheetNames.length&&a[o]&&a[o].Hidden;++o);o==e.SheetNames.length&&(o=0),t[t.length]='',t[t.length]=""}for(t[t.length]="",o=0;o!=e.SheetNames.length;++o){var i={name:Fe(e.SheetNames[o].slice(0,31))};if(i.sheetId=""+(o+1),i["r:id"]="rId"+(o+1),a[o])switch(a[o].Hidden){case 1:i.state="hidden";break;case 2:i.state="veryHidden"}t[t.length]=He("sheet",null,i)}return t[t.length]="",r&&(t[t.length]="",e.Workbook&&e.Workbook.Names&&e.Workbook.Names.forEach((function(e){var r={name:e.Name};e.Comment&&(r.comment=e.Comment),null!=e.Sheet&&(r.localSheetId=""+e.Sheet),e.Hidden&&(r.hidden="1"),e.Ref&&(t[t.length]=He("definedName",Fe(e.Ref),r))})),t[t.length]=""),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}(e)),o.workbooks.push(f),Gt(t.rels,1,f,Xt.WB),Ae(c,f="xl/theme/theme1.xml",function(e,t){if(t&&t.themeXLSX)return t.themeXLSX;if(e&&"string"==typeof e.raw)return e.raw;var r=[Te];return r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r.join("")}(e.Themes,t)),o.themes.push(f),Gt(t.wbrels,-1,"theme/theme1.xml",Xt.THEME),Ae(c,f="xl/styles."+n,rr(e,t)),o.styles.push(f),Gt(t.wbrels,-1,"styles."+n,Xt.STY),e.vbaraw&&a&&(Ae(c,f="xl/vbaProject.bin",e.vbaraw),o.vba.push(f),Gt(t.wbrels,-1,"vbaProject.bin",Xt.VBA)),Ae(c,f="xl/metadata."+n,function(){var e=[Te];return e.push('\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n'),e.join("")}()),o.metadata.push(f),Gt(t.wbrels,-1,"metadata."+n,Xt.XLMETA),g.length>1&&(Ae(c,f="xl/persons/person.xml",function(e){var t=[Te,He("personList",null,{xmlns:Ve.TCMNT,"xmlns:x":Ge[0]}).replace(/[\/]>/,">")];return e.forEach((function(e,r){t.push(He("person",null,{displayName:e,id:"{54EE7950-7262-4200-6969-"+("000000000000"+r).slice(-12)+"}",userId:e,providerId:"None"}))})),t.push(""),t.join("")}(g)),o.people.push(f),Gt(t.wbrels,-1,"persons/person.xml",Xt.PEOPLE)),Ae(c,"[Content_Types].xml",Ht(o,t)),Ae(c,"_rels/.rels",Vt(t.rels)),Ae(c,"xl/_rels/workbook.xml.rels",Vt(t.wbrels)),delete t.revssf,delete t.ssf,c}function Ar(e,t){var r=ge(t||{});return function(e,t){var r={},n=a?"nodebuffer":"undefined"!=typeof Uint8Array?"array":"string";t.compression&&(r.compression="DEFLATE");if(t.password)r.type=n;else switch(t.type){case"base64":r.type="base64";break;case"binary":r.type="string";break;case"string":throw new Error("'string' output type invalid for '"+t.bookType+"' files");case"buffer":case"file":r.type=n;break;default:throw new Error("Unrecognized type "+t.type)}var o=e.FullPaths?re.write(e,{fileType:"zip",type:{nodebuffer:"buffer",string:"binary"}[r.type]||r.type,compression:!!t.compression}):e.generate(r);if("undefined"!=typeof Deno&&"string"==typeof o){if("binary"==t.type||"base64"==t.type)return o;o=new Uint8Array(f(o))}return t.password&&"undefined"!=typeof encrypt_agile?function(e,t){switch(t.type){case"base64":case"binary":break;case"buffer":case"array":t.type="";break;case"file":return ae(t.file,re.write(e,{type:a?"buffer":""}));case"string":throw new Error("'string' output type invalid for '"+t.bookType+"' files");default:throw new Error("Unrecognized type "+t.type)}return re.write(e,t)}(encrypt_agile(o,t.password),t):"file"===t.type?ae(t.file,o):"string"==t.type?Ue(o):o}(_r(e,r),r)}function Tr(e,t){xr(e);var r=ge(t||{});if(r.cellStyles&&(r.cellNF=!0,r.sheetStubs=!0),"array"==r.type){r.type="binary";var n=Tr(e,r);return r.type="array",f(n)}return Ar(e,r)}function Dr(e,t,r){var n=r||{};return n.type="file",n.file=t,function(e){if(!e.bookType){var t=e.file.slice(e.file.lastIndexOf(".")).toLowerCase();t.match(/^\.[a-z]+$/)&&(e.bookType=t.slice(1)),e.bookType={xls:"biff8",htm:"html",slk:"sylk",socialcalc:"eth",Sh33tJS:"WTF"}[e.bookType]||e.bookType}}(n),Tr(e,n)}function Or(e,t,r,n,a,o,i){var s,l=Ot(r),c=i.defval,f=i.raw||!Object.prototype.hasOwnProperty.call(i,"raw"),h=!0,u=null!=e["!data"],p=1===a?[]:{};if(1!==a)if(Object.defineProperty)try{Object.defineProperty(p,"__rowNum__",{value:r,enumerable:!1})}catch(e){p.__rowNum__=r}else p.__rowNum__=r;if(!u||e["!data"][r])for(var d=t.s.c;d<=t.e.c;++d){var m=u?(e["!data"][r]||[])[d]:e[n[d]+l];if(null!=m&&void 0!==m.t){var g=m.v;switch(m.t){case"z":if(null==g)break;continue;case"e":g=0==g?null:void 0;break;case"s":case"b":case"n":if(!m.z||!J(m.z))break;if("number"==typeof(g=he(g)))break;case"d":i&&i.UTC||(s=g,g=new Date(s.getUTCFullYear(),s.getUTCMonth(),s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds(),s.getUTCMilliseconds()));break;default:throw new Error("unrecognized type "+m.t)}if(null!=o[d]){if(null==g)if("e"==m.t&&null===g)p[o[d]]=null;else if(void 0!==c)p[o[d]]=c;else{if(!f||null!==g)continue;p[o[d]]=null}else p[o[d]]=f&&("n"!==m.t||"n"===m.t&&!1!==i.rawNumbers)?g:$t(m,g,i);null!=g&&(h=!1)}}else{if(void 0===c)continue;null!=o[d]&&(p[o[d]]=c)}}return{row:p,isempty:h}}function Er(e,t){if(null==e||null==e["!ref"])return[];var r={t:"n",v:0},n=0,a=1,o=[],i=0,s="",l={s:{r:0,c:0},e:{r:0,c:0}},c=t||{},f=null!=c.range?c.range:e["!ref"];switch(1===c.header?n=1:"A"===c.header?n=2:Array.isArray(c.header)?n=3:null==c.header&&(n=0),typeof f){case"string":l=Lt(f);break;case"number":(l=Lt(e["!ref"])).s.r=f;break;default:l=f}n>0&&(a=0);var h=Ot(l.s.r),u=[],p=[],d=0,m=0,g=null!=e["!data"],v=l.s.r,b=0,x={};g&&!e["!data"][v]&&(e["!data"][v]=[]);var w=c.skipHidden&&e["!cols"]||[],y=c.skipHidden&&e["!rows"]||[];for(b=l.s.c;b<=l.e.c;++b)if(!(w[b]||{}).hidden)switch(u[b]=Et(b),r=g?e["!data"][v][b]:e[u[b]+h],n){case 1:o[b]=b-l.s.c;break;case 2:o[b]=u[b];break;case 3:o[b]=c.header[b-l.s.c];break;default:if(null==r&&(r={w:"__EMPTY",t:"s"}),s=i=$t(r,null,c),m=x[i]||0){do{s=i+"_"+m++}while(x[s]);x[i]=m,x[s]=1}else x[i]=1;o[b]=s}for(v=l.s.r+a;v<=l.e.r;++v)if(!(y[v]||{}).hidden){var C=Or(e,l,v,u,n,o,c);(!1===C.isempty||(1===n?!1!==c.blankrows:c.blankrows))&&(p[d++]=C.row)}return p.length=d,p}!function(){try{return"undefined"==typeof Uint8Array||void 0===Uint8Array.prototype.subarray?"slice":"undefined"!=typeof Buffer?void 0===Buffer.prototype.subarray?"slice":("function"==typeof Buffer.from?Buffer.from([72,62]):new Buffer([72,62]))instanceof Uint8Array?"subarray":"slice":"subarray"}catch(e){return"slice"}}();var Fr=/"/g;function Mr(e,t,r,n,a,o,i,s){for(var l=!0,c=[],f="",h=Ot(r),u=null!=e["!data"],p=u&&e["!data"][r]||[],d=t.s.c;d<=t.e.c;++d)if(n[d]){var m=u?p[d]:e[n[d]+h];if(null==m)f="";else if(null!=m.v){l=!1,f=""+(s.rawNumbers&&"n"==m.t?m.v:$t(m,null,s));for(var g=0,v=0;g!==f.length;++g)if((v=f.charCodeAt(g))===a||v===o||34===v||s.forceQuotes){f='"'+f.replace(Fr,'""')+'"';break}"ID"==f&&(f='"ID"')}else null==m.f||m.F?f="":(l=!1,(f="="+m.f).indexOf(",")>=0&&(f='"'+f.replace(Fr,'""')+'"'));c.push(f)}return!1===s.blankrows&&l?null:c.join(i)}function Nr(e,t){var r=[],n=null==t?{}:t;if(null==e||null==e["!ref"])return"";for(var a=Lt(e["!ref"]),o=void 0!==n.FS?n.FS:",",i=o.charCodeAt(0),s=void 0!==n.RS?n.RS:"\n",l=s.charCodeAt(0),c=new RegExp(("|"==o?"\\|":o)+"+$"),f="",h=[],u=n.skipHidden&&e["!cols"]||[],p=n.skipHidden&&e["!rows"]||[],d=a.s.c;d<=a.e.c;++d)(u[d]||{}).hidden||(h[d]=Et(d));for(var m=0,g=a.s.r;g<=a.e.r;++g)(p[g]||{}).hidden||null!=(f=Mr(e,a,g,h,i,l,o,n))&&(n.strip&&(f=f.replace(c,"")),(f||!1!==n.blankrows)&&r.push((m++?s:"")+f));return r.join("")}function Pr(e,t,r){var n=r||{},a=e?null!=e["!data"]:n.dense,o=+!n.skipHeader,i=e||{};!e&&a&&(i["!data"]=[]);var s=0,l=0;if(i&&null!=n.origin)if("number"==typeof n.origin)s=n.origin;else{var c="string"==typeof n.origin?Ft(n.origin):n.origin;s=c.r,l=c.c}var f={s:{c:0,r:0},e:{c:l,r:s+t.length-1+o}};if(i["!ref"]){var h=Lt(i["!ref"]);f.e.c=Math.max(f.e.c,h.e.c),f.e.r=Math.max(f.e.r,h.e.r),-1==s&&(s=h.e.r+1,f.e.r=s+t.length-1+o)}else-1==s&&(s=0,f.e.r=t.length-1+o);var u=n.header||[],p=0,d=[];t.forEach((function(e,t){a&&!i["!data"][s+t+o]&&(i["!data"][s+t+o]=[]),a&&(d=i["!data"][s+t+o]),oe(e).forEach((function(r){-1==(p=u.indexOf(r))&&(u[p=u.length]=r);var c=e[r],f="z",h="",m=a?"":Et(l+p)+Ot(s+t+o),g=a?d[l+p]:i[m];!c||"object"!=typeof c||c instanceof Date?("number"==typeof c?f="n":"boolean"==typeof c?f="b":"string"==typeof c?f="s":c instanceof Date?(f="d",n.UTC||(c=_e(c)),n.cellDates||(f="n",c=fe(c)),h=null!=g&&g.z&&J(g.z)?g.z:n.dateNF||S[14]):null===c&&n.nullError&&(f="e",c=0),g?(g.t=f,g.v=c,delete g.w,delete g.R,h&&(g.z=h)):a?d[l+p]=g={t:f,v:c}:i[m]=g={t:f,v:c},h&&(g.z=h)):a?d[l+p]=c:i[m]=c}))})),f.e.c=Math.max(f.e.c,l+u.length-1);var m=Ot(s);if(a&&!i["!data"][s]&&(i["!data"][s]=[]),o)for(p=0;pSheetJS Table Export',a=null!=r.footer?r.footer:"",o=[n],i=Nt(e["!ref"]);o.push(function(e,t,r){return[].join("")+""}(0,0,r));for(var s=i.s.r;s<=i.e.r;++s)o.push(wr(e,i,s,r));return o.push(""+a),o.join("")},sheet_to_formulae:function(e){var t,r="",n="";if(null==e||null==e["!ref"])return[];var a,o=Lt(e["!ref"]),i="",s=[],l=[],c=null!=e["!data"];for(a=o.s.c;a<=o.e.c;++a)s[a]=Et(a);for(var f=o.s.r;f<=o.e.r;++f)for(i=Ot(f),a=o.s.c;a<=o.e.c;++a)if(r=s[a]+i,n="",void 0!==(t=c?(e["!data"][f]||[])[a]:e[r])){if(null!=t.F){if(r=t.F,!t.f)continue;n=t.f,-1==r.indexOf(":")&&(r=r+":"+r)}if(null!=t.f)n=t.f;else{if("z"==t.t)continue;if("n"==t.t&&null!=t.v)n=""+t.v;else if("b"==t.t)n=t.v?"TRUE":"FALSE";else if(void 0!==t.w)n="'"+t.w;else{if(void 0===t.v)continue;n="s"==t.t?"'"+t.v:""+t.v}}l[l.length]=r+"="+n}return l},sheet_to_row_object_array:Er,sheet_get_cell:Ir,book_new:function(){return{SheetNames:[],Sheets:{}}},book_append_sheet:function(e,t,r,n){var a=1;if(!r)for(;a<=65535&&-1!=e.SheetNames.indexOf(r="Sheet"+a);++a,r=void 0);if(!r||e.SheetNames.length>=65535)throw new Error("Too many worksheets");if(n&&e.SheetNames.indexOf(r)>=0){var o=r.match(/(^.*?)(\d+)$/);a=o&&+o[2]||0;var i=o&&o[1]||r;for(++a;a<=65535&&-1!=e.SheetNames.indexOf(r=i+a);++a);}if(br(r),e.SheetNames.indexOf(r)>=0)throw new Error("Worksheet with name |"+r+"| already exists!");return e.SheetNames.push(r),e.Sheets[r]=t,r},book_set_sheet_visibility:function(e,t,r){e.Workbook||(e.Workbook={}),e.Workbook.Sheets||(e.Workbook.Sheets=[]);var n=function(e,t){if("number"==typeof t){if(t>=0&&e.SheetNames.length>t)return t;throw new Error("Cannot find sheet # "+t)}if("string"==typeof t){var r=e.SheetNames.indexOf(t);if(r>-1)return r;throw new Error("Cannot find sheet name |"+t+"|")}throw new Error("Cannot find sheet |"+t+"|")}(e,t);switch(e.Workbook.Sheets[n]||(e.Workbook.Sheets[n]={}),r){case 0:case 1:case 2:break;default:throw new Error("Bad sheet visibility setting "+r)}e.Workbook.Sheets[n].Hidden=r},cell_set_number_format:function(e,t){return e.z=t,e},cell_set_hyperlink:Rr,cell_set_internal_link:function(e,t,r){return Rr(e,"#"+t,r)},cell_add_comment:function(e,t,r){e.c||(e.c=[]),e.c.push({t,a:r||"SheetJS"})},sheet_set_array_formula:function(e,t,r,n){for(var a="string"!=typeof t?t:Lt(t),o="string"==typeof t?t:Pt(t),i=a.s.r;i<=a.e.r;++i)for(var s=a.s.c;s<=a.e.c;++s){var l=Ir(e,i,s);l.t="n",l.F=o,delete l.v,i==a.s.r&&s==a.s.c&&(l.f=r,n&&(l.D=!0))}var c=Nt(e["!ref"]);return c.s.r>a.s.r&&(c.s.r=a.s.r),c.s.c>a.s.c&&(c.s.c=a.s.c),c.e.r>2,s=(3&n)<<4|(a=e.charCodeAt(f++))>>4,l=(15&a)<<2|(i=e.charCodeAt(f++))>>6,c=63&i,isNaN(a)?l=c=64:isNaN(i)&&(c=64),r+=t.charAt(o)+t.charAt(s)+t.charAt(l)+t.charAt(c);return r}function n(e){var r="",n=0,a=0,i=0,o=0,s=0,l=0;"data:"==e.slice(0,5)&&((c=e.slice(0,1024).indexOf(";base64,"))>-1&&(e=e.slice(c+8)));e=e.replace(/[^\w\+\/\=]/g,"");for(var c=0;c>4,r+=String.fromCharCode(n),a=(15&o)<<4|(s=t.indexOf(e.charAt(c++)))>>2,64!==s&&(r+=String.fromCharCode(a)),i=(3&s)<<6|(l=t.indexOf(e.charAt(c++))),64!==l&&(r+=String.fromCharCode(i));return r}var a=function(){return"undefined"!=typeof Buffer&&"undefined"!=typeof process&&void 0!==process.versions&&!!process.versions.node}(),i=function(){if("undefined"!=typeof Buffer){var e=!Buffer.from;if(!e)try{Buffer.from("foo","utf8")}catch(t){e=!0}return e?function(e,t){return t?new Buffer(e,t):new Buffer(e)}:Buffer.from.bind(Buffer)}return function(){}}(),o=function(){if("undefined"==typeof Buffer)return!1;var e=i([65,0]);return!!e&&1==e.toString("utf16le").length}();function s(e){return a?Buffer.alloc?Buffer.alloc(e):new Buffer(e):"undefined"!=typeof Uint8Array?new Uint8Array(e):new Array(e)}function l(e){return a?Buffer.allocUnsafe?Buffer.allocUnsafe(e):new Buffer(e):"undefined"!=typeof Uint8Array?new Uint8Array(e):new Array(e)}var c=function(e){return a?i(e,"binary"):e.split("").map((function(e){return 255&e.charCodeAt(0)}))};function f(e){if("undefined"==typeof ArrayBuffer)return c(e);for(var t=new ArrayBuffer(e.length),r=new Uint8Array(t),n=0;n!=e.length;++n)r[n]=255&e.charCodeAt(n);return t}var h=a?function(e){return Buffer.concat(e.map((function(e){return Buffer.isBuffer(e)?e:i(e)})))}:function(e){if("undefined"!=typeof Uint8Array){var t=0,r=0;for(t=0;t=0;)t+=e.charAt(r--);return t}function m(e,t){var r=""+e;return r.length>=t?r:ve("0",t-r.length)+r}function g(e,t){var r=""+e;return r.length>=t?r:ve(" ",t-r.length)+r}function v(e,t){var r=""+e;return r.length>=t?r:r+ve(" ",t-r.length)}var b=Math.pow(2,32);function x(e,t){return e>b||e<-b?function(e,t){var r=""+Math.round(e);return r.length>=t?r:ve("0",t-r.length)+r}(e,t):function(e,t){var r=""+e;return r.length>=t?r:ve("0",t-r.length)+r}(Math.round(e),t)}function w(e,t){return t=t||0,e.length>=7+t&&103==(32|e.charCodeAt(t))&&101==(32|e.charCodeAt(t+1))&&110==(32|e.charCodeAt(t+2))&&101==(32|e.charCodeAt(t+3))&&114==(32|e.charCodeAt(t+4))&&97==(32|e.charCodeAt(t+5))&&108==(32|e.charCodeAt(t+6))}var y=[["Sun","Sunday"],["Mon","Monday"],["Tue","Tuesday"],["Wed","Wednesday"],["Thu","Thursday"],["Fri","Friday"],["Sat","Saturday"]],C=[["J","Jan","January"],["F","Feb","February"],["M","Mar","March"],["A","Apr","April"],["M","May","May"],["J","Jun","June"],["J","Jul","July"],["A","Aug","August"],["S","Sep","September"],["O","Oct","October"],["N","Nov","November"],["D","Dec","December"]];var S={0:"General",1:"0",2:"0.00",3:"#,##0",4:"#,##0.00",9:"0%",10:"0.00%",11:"0.00E+00",12:"# ?/?",13:"# ??/??",14:"m/d/yy",15:"d-mmm-yy",16:"d-mmm",17:"mmm-yy",18:"h:mm AM/PM",19:"h:mm:ss AM/PM",20:"h:mm",21:"h:mm:ss",22:"m/d/yy h:mm",37:"#,##0 ;(#,##0)",38:"#,##0 ;[Red](#,##0)",39:"#,##0.00;(#,##0.00)",40:"#,##0.00;[Red](#,##0.00)",45:"mm:ss",46:"[h]:mm:ss",47:"mmss.0",48:"##0.0E+0",49:"@",56:'"上午/下午 "hh"時"mm"分"ss"秒 "'},k={5:37,6:38,7:39,8:40,23:0,24:0,25:0,26:0,27:14,28:14,29:14,30:14,31:14,50:14,51:14,52:14,53:14,54:14,55:14,56:14,57:14,58:14,59:1,60:2,61:3,62:4,67:9,68:10,69:12,70:13,71:14,72:14,73:15,74:16,75:17,76:20,77:21,78:22,79:45,80:46,81:47,82:0},_={5:'"$"#,##0_);\\("$"#,##0\\)',63:'"$"#,##0_);\\("$"#,##0\\)',6:'"$"#,##0_);[Red]\\("$"#,##0\\)',64:'"$"#,##0_);[Red]\\("$"#,##0\\)',7:'"$"#,##0.00_);\\("$"#,##0.00\\)',65:'"$"#,##0.00_);\\("$"#,##0.00\\)',8:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',66:'"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',41:'_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)',42:'_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)',43:'_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)',44:'_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'};function A(e,t,r){for(var n=e<0?-1:1,a=e*n,i=0,o=1,s=0,l=1,c=0,f=0,h=Math.floor(a);ct&&(c>t?(f=l,s=i):(f=c,s=o)),!r)return[0,n*s,f];var u=Math.floor(n*s/f);return[u,n*s-u*f,f]}function T(e,t,r){if(e>2958465||e<0)return null;var n=0|(e=function(e){var t=e.toPrecision(16);if(t.indexOf("e")>-1){var r=t.slice(0,t.indexOf("e"));return(r=r.indexOf(".")>-1?r.slice(0,"0."==r.slice(0,2)?17:16):r.slice(0,15)+ve("0",r.length-15))+t.slice(t.indexOf("e"))}var n=t.indexOf(".")>-1?t.slice(0,"0."==t.slice(0,2)?17:16):t.slice(0,15)+ve("0",t.length-15);return Number(n)}(e)),a=Math.floor(86400*(e-n)),i=0,o=[],s={D:n,T:a,u:86400*(e-n)-a,y:0,m:0,d:0,H:0,M:0,S:0,q:0};if(Math.abs(s.u)<1e-6&&(s.u=0),t&&t.date1904&&(n+=1462),s.u>.9999&&(s.u=0,86400==++a&&(s.T=a=0,++n,++s.D)),60===n)o=r?[1317,10,29]:[1900,2,29],i=3;else if(0===n)o=r?[1317,8,29]:[1900,1,0],i=6;else{n>60&&--n;var l=new Date(1900,0,1);l.setDate(l.getDate()+n-1),o=[l.getFullYear(),l.getMonth()+1,l.getDate()],i=l.getDay(),n<60&&(i=(i+6)%7),r&&(i=function(e,t){t[0]-=581;var r=e.getDay();e<60&&(r=(r+6)%7);return r}(l,o))}return s.y=o[0],s.m=o[1],s.d=o[2],s.S=a%60,a=Math.floor(a/60),s.M=a%60,a=Math.floor(a/60),s.H=a,s.q=i,s}function D(e){return-1==e.indexOf(".")?e:e.replace(/(?:\.0*|(\.\d*[1-9])0+)$/,"$1")}function O(e){if(!isFinite(e))return isNaN(e)?"#NUM!":"#DIV/0!";var t,r=Math.floor(Math.log(Math.abs(e))*Math.LOG10E);return t=r>=-4&&r<=-1?e.toPrecision(10+r):Math.abs(r)<=9?function(e){var t=e<0?12:11,r=D(e.toFixed(12));return r.length<=t||(r=e.toPrecision(10)).length<=t?r:e.toExponential(5)}(e):10===r?e.toFixed(10).substr(0,12):function(e){var t=D(e.toFixed(11));return t.length>(e<0?12:11)||"0"===t||"-0"===t?e.toPrecision(6):t}(e),D(function(e){return-1==e.indexOf("E")?e:e.replace(/(?:\.0*|(\.\d*[1-9])0+)[Ee]/,"$1E").replace(/(E[+-])(\d)$/,"$10$2")}(t.toUpperCase()))}function F(e,t){switch(typeof e){case"string":return e;case"boolean":return e?"TRUE":"FALSE";case"number":return(0|e)===e?e.toString(10):O(e);case"undefined":return"";case"object":if(null==e)return"";if(e instanceof Date)return K(14,fe(e,t&&t.date1904),t)}throw new Error("unsupported value in General format: "+e)}function E(e,t,r,n){var a,i="",o=0,s=0,l=r.y,c=0;switch(e){case 98:l=r.y+543;case 121:switch(t.length){case 1:case 2:a=l%100,c=2;break;default:a=l%1e4,c=4}break;case 109:switch(t.length){case 1:case 2:a=r.m,c=t.length;break;case 3:return C[r.m-1][1];case 5:return C[r.m-1][0];default:return C[r.m-1][2]}break;case 100:switch(t.length){case 1:case 2:a=r.d,c=t.length;break;case 3:return y[r.q][0];default:return y[r.q][1]}break;case 104:switch(t.length){case 1:case 2:a=1+(r.H+11)%12,c=t.length;break;default:throw"bad hour format: "+t}break;case 72:switch(t.length){case 1:case 2:a=r.H,c=t.length;break;default:throw"bad hour format: "+t}break;case 77:switch(t.length){case 1:case 2:a=r.M,c=t.length;break;default:throw"bad minute format: "+t}break;case 115:if("s"!=t&&"ss"!=t&&".0"!=t&&".00"!=t&&".000"!=t)throw"bad second format: "+t;return 0!==r.u||"s"!=t&&"ss"!=t?(s=n>=2?3===n?1e3:100:1===n?10:1,(o=Math.round(s*(r.S+r.u)))>=60*s&&(o=0),"s"===t?0===o?"0":""+o/s:(i=m(o,2+n),"ss"===t?i.substr(0,2):"."+i.substr(2,t.length-1))):m(r.S,t.length);case 90:switch(t){case"[h]":case"[hh]":a=24*r.D+r.H;break;case"[m]":case"[mm]":a=60*(24*r.D+r.H)+r.M;break;case"[s]":case"[ss]":a=60*(60*(24*r.D+r.H)+r.M)+(0==n?Math.round(r.S+r.u):r.S);break;default:throw"bad abstime format: "+t}c=3===t.length?1:2;break;case 101:a=l,c=1}return c>0?m(a,c):""}function M(e){if(e.length<=3)return e;for(var t=e.length%3,r=e.substr(0,t);t!=e.length;t+=3)r+=(r.length>0?",":"")+e.substr(t,3);return r}var N=/%/g;function I(e,t){var r,n=e.indexOf("E")-e.indexOf(".")-1;if(e.match(/^#+0.0E\+0$/)){if(0==t)return"0.0E+0";if(t<0)return"-"+I(e,-t);var a=e.indexOf(".");-1===a&&(a=e.indexOf("E"));var i=Math.floor(Math.log(t)*Math.LOG10E)%a;if(i<0&&(i+=a),-1===(r=(t/Math.pow(10,i)).toPrecision(n+1+(a+i)%a)).indexOf("e")){var o=Math.floor(Math.log(t)*Math.LOG10E);for(-1===r.indexOf(".")?r=r.charAt(0)+"."+r.substr(1)+"E+"+(o-r.length+i):r+="E+"+(o-i);"0."===r.substr(0,2);)r=(r=r.charAt(0)+r.substr(2,a)+"."+r.substr(2+a)).replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");r=r.replace(/\+-/,"-")}r=r.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,(function(e,t,r,n){return t+r+n.substr(0,(a+i)%a)+"."+n.substr(i)+"E"}))}else r=t.toExponential(n);return e.match(/E\+00$/)&&r.match(/e[+-]\d$/)&&(r=r.substr(0,r.length-1)+"0"+r.charAt(r.length-1)),e.match(/E\-/)&&r.match(/e\+/)&&(r=r.replace(/e\+/,"e")),r.replace("e","E")}var P=/# (\?+)( ?)\/( ?)(\d+)/;var R=/^#*0*\.([0#]+)/,L=/\)[^)]*[0#]/,U=/\(###\) ###\\?-####/;function z(e){for(var t,r="",n=0;n!=e.length;++n)switch(t=e.charCodeAt(n)){case 35:break;case 63:r+=" ";break;case 48:r+="0";break;default:r+=String.fromCharCode(t)}return r}function j(e,t){var r=Math.pow(10,t);return""+Math.round(e*r)/r}function B(e,t){var r=e-Math.floor(e),n=Math.pow(10,t);return t<(""+Math.round(r*n)).length?0:Math.round(r*n)}function W(e,t,r){if(40===e.charCodeAt(0)&&!t.match(L)){var n=t.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");return r>=0?W("n",n,r):"("+W("n",n,-r)+")"}if(44===t.charCodeAt(t.length-1))return function(e,t,r){for(var n=t.length-1;44===t.charCodeAt(n-1);)--n;return V(e,t.substr(0,n),r/Math.pow(10,3*(t.length-n)))}(e,t,r);if(-1!==t.indexOf("%"))return function(e,t,r){var n=t.replace(N,""),a=t.length-n.length;return V(e,n,r*Math.pow(10,2*a))+ve("%",a)}(e,t,r);if(-1!==t.indexOf("E"))return I(t,r);if(36===t.charCodeAt(0))return"$"+W(e,t.substr(" "==t.charAt(1)?2:1),r);var a,i,o,s,l=Math.abs(r),c=r<0?"-":"";if(t.match(/^00+$/))return c+x(l,t.length);if(t.match(/^[#?]+$/))return"0"===(a=x(r,0))&&(a=""),a.length>t.length?a:z(t.substr(0,t.length-a.length))+a;if(i=t.match(P))return function(e,t,r){var n=parseInt(e[4],10),a=Math.round(t*n),i=Math.floor(a/n),o=a-i*n,s=n;return r+(0===i?"":""+i)+" "+(0===o?ve(" ",e[1].length+1+e[4].length):g(o,e[1].length)+e[2]+"/"+e[3]+m(s,e[4].length))}(i,l,c);if(t.match(/^#+0+$/))return c+x(l,t.length-t.indexOf("0"));if(i=t.match(R))return a=j(r,i[1].length).replace(/^([^\.]+)$/,"$1."+z(i[1])).replace(/\.$/,"."+z(i[1])).replace(/\.(\d*)$/,(function(e,t){return"."+t+ve("0",z(i[1]).length-t.length)})),-1!==t.indexOf("0.")?a:a.replace(/^0\./,".");if(t=t.replace(/^#+([0.])/,"$1"),i=t.match(/^(0*)\.(#*)$/))return c+j(l,i[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,i[1].length?"0.":".");if(i=t.match(/^#{1,3},##0(\.?)$/))return c+M(x(l,0));if(i=t.match(/^#,##0\.([#0]*0)$/))return r<0?"-"+W(e,t,-r):M(""+(Math.floor(r)+function(e,t){return t<(""+Math.round((e-Math.floor(e))*Math.pow(10,t))).length?1:0}(r,i[1].length)))+"."+m(B(r,i[1].length),i[1].length);if(i=t.match(/^#,#*,#0/))return W(e,t.replace(/^#,#*,/,""),r);if(i=t.match(/^([0#]+)(\\?-([0#]+))+$/))return a=d(W(e,t.replace(/[\\-]/g,""),r)),o=0,d(d(t.replace(/\\/g,"")).replace(/[0#]/g,(function(e){return o-2147483648?""+(e>=0?0|e:e-1|0):""+Math.floor(e)}(r)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,(function(e){return"00,"+(e.length<3?m(0,3-e.length):"")+e}))+"."+m(o,i[1].length);switch(t){case"###,##0.00":return W(e,"#,##0.00",r);case"###,###":case"##,###":case"#,###":var p=M(x(l,0));return"0"!==p?c+p:"";case"###,###.00":return W(e,"###,##0.00",r).replace(/^0\./,".");case"#,###.00":return W(e,"#,##0.00",r).replace(/^0\./,".")}throw new Error("unsupported format |"+t+"|")}function H(e,t){var r,n=e.indexOf("E")-e.indexOf(".")-1;if(e.match(/^#+0.0E\+0$/)){if(0==t)return"0.0E+0";if(t<0)return"-"+H(e,-t);var a=e.indexOf(".");-1===a&&(a=e.indexOf("E"));var i=Math.floor(Math.log(t)*Math.LOG10E)%a;if(i<0&&(i+=a),!(r=(t/Math.pow(10,i)).toPrecision(n+1+(a+i)%a)).match(/[Ee]/)){var o=Math.floor(Math.log(t)*Math.LOG10E);-1===r.indexOf(".")?r=r.charAt(0)+"."+r.substr(1)+"E+"+(o-r.length+i):r+="E+"+(o-i),r=r.replace(/\+-/,"-")}r=r.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,(function(e,t,r,n){return t+r+n.substr(0,(a+i)%a)+"."+n.substr(i)+"E"}))}else r=t.toExponential(n);return e.match(/E\+00$/)&&r.match(/e[+-]\d$/)&&(r=r.substr(0,r.length-1)+"0"+r.charAt(r.length-1)),e.match(/E\-/)&&r.match(/e\+/)&&(r=r.replace(/e\+/,"e")),r.replace("e","E")}function X(e,t,r){if(40===e.charCodeAt(0)&&!t.match(L)){var n=t.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");return r>=0?X("n",n,r):"("+X("n",n,-r)+")"}if(44===t.charCodeAt(t.length-1))return function(e,t,r){for(var n=t.length-1;44===t.charCodeAt(n-1);)--n;return V(e,t.substr(0,n),r/Math.pow(10,3*(t.length-n)))}(e,t,r);if(-1!==t.indexOf("%"))return function(e,t,r){var n=t.replace(N,""),a=t.length-n.length;return V(e,n,r*Math.pow(10,2*a))+ve("%",a)}(e,t,r);if(-1!==t.indexOf("E"))return H(t,r);if(36===t.charCodeAt(0))return"$"+X(e,t.substr(" "==t.charAt(1)?2:1),r);var a,i,o,s,l=Math.abs(r),c=r<0?"-":"";if(t.match(/^00+$/))return c+m(l,t.length);if(t.match(/^[#?]+$/))return a=""+r,0===r&&(a=""),a.length>t.length?a:z(t.substr(0,t.length-a.length))+a;if(i=t.match(P))return function(e,t,r){return r+(0===t?"":""+t)+ve(" ",e[1].length+2+e[4].length)}(i,l,c);if(t.match(/^#+0+$/))return c+m(l,t.length-t.indexOf("0"));if(i=t.match(R))return a=(a=(""+r).replace(/^([^\.]+)$/,"$1."+z(i[1])).replace(/\.$/,"."+z(i[1]))).replace(/\.(\d*)$/,(function(e,t){return"."+t+ve("0",z(i[1]).length-t.length)})),-1!==t.indexOf("0.")?a:a.replace(/^0\./,".");if(t=t.replace(/^#+([0.])/,"$1"),i=t.match(/^(0*)\.(#*)$/))return c+(""+l).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,i[1].length?"0.":".");if(i=t.match(/^#{1,3},##0(\.?)$/))return c+M(""+l);if(i=t.match(/^#,##0\.([#0]*0)$/))return r<0?"-"+X(e,t,-r):M(""+r)+"."+ve("0",i[1].length);if(i=t.match(/^#,#*,#0/))return X(e,t.replace(/^#,#*,/,""),r);if(i=t.match(/^([0#]+)(\\?-([0#]+))+$/))return a=d(X(e,t.replace(/[\\-]/g,""),r)),o=0,d(d(t.replace(/\\/g,"")).replace(/[0#]/g,(function(e){return o-1||"\\"==r&&"-"==e.charAt(t+1)&&"0#".indexOf(e.charAt(t+2))>-1););break;case"?":for(;e.charAt(++t)===r;);break;case"*":++t," "!=e.charAt(t)&&"*"!=e.charAt(t)||++t;break;case"(":case")":++t;break;case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":for(;t-1;);break;default:++t}return!1}var q=/\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;function Y(e,t){if(null==t)return!1;var r=parseFloat(t[2]);switch(t[1]){case"=":if(e==r)return!0;break;case">":if(e>r)return!0;break;case"<":if(e":if(e!=r)return!0;break;case">=":if(e>=r)return!0;break;case"<=":if(e<=r)return!0}return!1}function Z(e,t){var r=function(e){for(var t=[],r=!1,n=0,a=0;n-1&&--n,r.length>4)throw new Error("cannot find right format for |"+r.join("|")+"|");if("number"!=typeof t)return[4,4===r.length||a>-1?r[r.length-1]:"@"];switch("number"!=typeof t||isFinite(t)||(t=0),r.length){case 1:r=a>-1?["General","General","General",r[0]]:[r[0],r[0],r[0],"@"];break;case 2:r=a>-1?[r[0],r[0],r[0],r[1]]:[r[0],r[1],r[0],"@"];break;case 3:r=a>-1?[r[0],r[1],r[0],r[2]]:[r[0],r[1],r[2],"@"]}var i=t>0?r[0]:t<0?r[1]:r[2];if(-1===r[0].indexOf("[")&&-1===r[1].indexOf("["))return[n,i];if(null!=r[0].match(/\[[=<>]/)||null!=r[1].match(/\[[=<>]/)){var o=r[0].match(q),s=r[1].match(q);return Y(t,o)?[n,r[0]]:Y(t,s)?[n,r[1]]:[n,r[null!=o&&null!=s?2:1]]}return[n,i]}function K(e,t,r){null==r&&(r={});var n="";switch(typeof e){case"string":n="m/d/yy"==e&&r.dateNF?r.dateNF:e;break;case"number":null==(n=14==e&&r.dateNF?r.dateNF:(null!=r.table?r.table:S)[e])&&(n=r.table&&r.table[k[e]]||S[k[e]]),null==n&&(n=_[e]||"General")}if(w(n,0))return F(t,r);t instanceof Date&&(t=fe(t,r.date1904));var a=Z(n,t);if(w(a[1]))return F(t,r);if(!0===t)t="TRUE";else if(!1===t)t="FALSE";else{if(""===t||null==t)return"";if(isNaN(t)&&a[1].indexOf("0")>-1)return"#NUM!";if(!isFinite(t)&&a[1].indexOf("0")>-1)return"#DIV/0!"}return function(e,t,r,n){for(var a,i,o,s=[],l="",c=0,f="",h="t",u="H";c=12?e.charAt(c+2):f),m.t="T",u="h",c+=3):"AM/PM"===e.substr(c,5).toUpperCase()?(null!=a&&(m.v=a.H>=12?"PM":"AM"),m.t="T",c+=5,u="h"):"上午/下午"===e.substr(c,5).toUpperCase()?(null!=a&&(m.v=a.H>=12?"下午":"上午"),m.t="T",c+=5,u="h"):(m.t="t",++c),null==a&&"T"===m.t)return"";s[s.length]=m,h=f;break;case"[":for(l=f;"]"!==e.charAt(c++)&&c-1&&(l=(l.match(/\$([^-\[\]]*)/)||[])[1]||"$",J(e)||(s[s.length]={t:"t",v:l}));break;case".":if(null!=a){for(l=f;++c-1;)l+=f;s[s.length]={t:"n",v:l};break;case"?":for(l=f;e.charAt(++c)===f;)l+=f;s[s.length]={t:f,v:l},h=f;break;case"*":++c," "!=e.charAt(c)&&"*"!=e.charAt(c)||++c;break;case"(":case")":s[s.length]={t:1===n?"t":f,v:f},++c;break;case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":for(l=f;c-1;)l+=e.charAt(c);s[s.length]={t:"D",v:l};break;case" ":s[s.length]={t:f,v:f},++c;break;case"$":s[s.length]={t:"t",v:"$"},++c;break;default:if(-1===",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(f))throw new Error("unrecognized character "+f+" in "+e);s[s.length]={t:"t",v:f},++c}var g,v,b=0,x=0;for(c=s.length-1,h="t";c>=0;--c)switch(s[c].t){case"h":case"H":s[c].t=u,h="h",b<1&&(b=1);break;case"s":(g=s[c].v.match(/\.0+$/))&&(x=Math.max(x,g[0].length-1),b=4),b<3&&(b=3);case"d":case"y":case"e":h=s[c].t;break;case"M":h=s[c].t,b<2&&(b=2);break;case"m":"s"===h&&(s[c].t="M",b<2&&(b=2));break;case"X":break;case"Z":b<1&&s[c].v.match(/[Hh]/)&&(b=1),b<2&&s[c].v.match(/[Mm]/)&&(b=2),b<3&&s[c].v.match(/[Ss]/)&&(b=3)}switch(b){case 0:break;case 1:case 2:case 3:a.u>=.5&&(a.u=0,++a.S),a.S>=60&&(a.S=0,++a.M),a.M>=60&&(a.M=0,++a.H),a.H>=24&&(a.H=0,++a.D,(v=T(a.D)).u=a.u,v.S=a.S,v.M=a.M,v.H=a.H,a=v);break;case 4:switch(x){case 1:a.u=Math.round(10*a.u)/10;break;case 2:a.u=Math.round(100*a.u)/100;break;case 3:a.u=Math.round(1e3*a.u)/1e3}a.u>=1&&(a.u=0,++a.S),a.S>=60&&(a.S=0,++a.M),a.M>=60&&(a.M=0,++a.H),a.H>=24&&(a.H=0,++a.D,(v=T(a.D)).u=a.u,v.S=a.S,v.M=a.M,v.H=a.H,a=v)}var y,C="";for(c=0;c0){40==C.charCodeAt(0)?(S=t<0&&45===C.charCodeAt(0)?-t:t,k=V("n",C,S)):(k=V("n",C,S=t<0&&n>1?-t:t),S<0&&s[0]&&"t"==s[0].t&&(k=k.substr(1),s[0].v="-"+s[0].v)),y=k.length-1;var A=s.length;for(c=0;c-1){A=c;break}var D=s.length;if(A===s.length&&-1===k.indexOf("E")){for(c=s.length-1;c>=0;--c)null!=s[c]&&-1!=="n?".indexOf(s[c].t)&&(y>=s[c].v.length-1?(y-=s[c].v.length,s[c].v=k.substr(y+1,s[c].v.length)):y<0?s[c].v="":(s[c].v=k.substr(0,y+1),y=-1),s[c].t="t",D=c);y>=0&&D=0;--c)if(null!=s[c]&&-1!=="n?".indexOf(s[c].t)){for(i=s[c].v.indexOf(".")>-1&&c===A?s[c].v.indexOf(".")-1:s[c].v.length-1,_=s[c].v.substr(i+1);i>=0;--i)y>=0&&("0"===s[c].v.charAt(i)||"#"===s[c].v.charAt(i))&&(_=k.charAt(y--)+_);s[c].v=_,s[c].t="t",D=c}for(y>=0&&D-1&&c===A?s[c].v.indexOf(".")+1:0,_=s[c].v.substr(0,i);i-1&&(S=n>1&&t<0&&c>0&&"-"===s[c-1].v?-t:t,s[c].v=V(s[c].t,s[c].v,S),s[c].t="t");var O="";for(c=0;c!==s.length;++c)null!=s[c]&&(O+=s[c].v);return O}(a[1],t,r,a[0])}function Q(e,t){if("number"!=typeof t){t=+t||-1;for(var r=0;r<392;++r)if(null!=S[r]){if(S[r]==e){t=r;break}}else t<0&&(t=r);t<0&&(t=391)}return S[t]=e,t}var ee={"d.m":"d\\.m"};var te=function(){var e={};e.version="1.2.0";var t=function(){for(var e=0,t=new Array(256),r=0;256!=r;++r)e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=1&(e=r)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1)?-306674912^e>>>1:e>>>1,t[r]=e;return"undefined"!=typeof Int32Array?new Int32Array(t):t}();var r=function(e){var t=0,r=0,n=0,a="undefined"!=typeof Int32Array?new Int32Array(4096):new Array(4096);for(n=0;256!=n;++n)a[n]=e[n];for(n=0;256!=n;++n)for(r=e[n],t=256+n;t<4096;t+=256)r=a[t]=r>>>8^e[255&r];var i=[];for(n=1;16!=n;++n)i[n-1]="undefined"!=typeof Int32Array&&"function"==typeof a.subarray?a.subarray(256*n,256*n+256):a.slice(256*n,256*n+256);return i}(t),n=r[0],a=r[1],i=r[2],o=r[3],s=r[4],l=r[5],c=r[6],f=r[7],h=r[8],u=r[9],p=r[10],d=r[11],m=r[12],g=r[13],v=r[14];return e.table=t,e.bstr=function(e,r){for(var n=~r,a=0,i=e.length;a>>8^t[255&(n^e.charCodeAt(a++))];return~n},e.buf=function(e,r){for(var b=~r,x=e.length-15,w=0;w>8&255]^m[e[w++]^b>>16&255]^d[e[w++]^b>>>24]^p[e[w++]]^u[e[w++]]^h[e[w++]]^f[e[w++]]^c[e[w++]]^l[e[w++]]^s[e[w++]]^o[e[w++]]^i[e[w++]]^a[e[w++]]^n[e[w++]]^t[e[w++]];for(x+=15;w>>8^t[255&(b^e[w++])];return~b},e.str=function(e,r){for(var n=~r,a=0,i=e.length,o=0,s=0;a>>8^t[255&(n^o)]:o<2048?n=(n=n>>>8^t[255&(n^(192|o>>6&31))])>>>8^t[255&(n^(128|63&o))]:o>=55296&&o<57344?(o=64+(1023&o),s=1023&e.charCodeAt(a++),n=(n=(n=(n=n>>>8^t[255&(n^(240|o>>8&7))])>>>8^t[255&(n^(128|o>>2&63))])>>>8^t[255&(n^(128|s>>6&15|(3&o)<<4))])>>>8^t[255&(n^(128|63&s))]):n=(n=(n=n>>>8^t[255&(n^(224|o>>12&15))])>>>8^t[255&(n^(128|o>>6&63))])>>>8^t[255&(n^(128|63&o))];return~n},e}(),re=function(){var e,t={};function o(e){if("/"==e.charAt(e.length-1))return-1===e.slice(0,-1).indexOf("/")?e:o(e.slice(0,-1));var t=e.lastIndexOf("/");return-1===t?e:e.slice(0,t+1)}function f(e){if("/"==e.charAt(e.length-1))return f(e.slice(0,-1));var t=e.lastIndexOf("/");return-1===t?e:e.slice(t+1)}function d(e,t){"string"==typeof t&&(t=new Date(t));var r=t.getHours();r=(r=r<<6|t.getMinutes())<<5|t.getSeconds()>>>1,e.write_shift(2,r);var n=t.getFullYear()-1980;n=(n=n<<4|t.getMonth()+1)<<5|t.getDate(),e.write_shift(2,n)}function m(e){Tt(e,0);for(var t={},r=0;e.l<=e.length-4;){var n=e.read_shift(2),a=e.read_shift(2),i=e.l+a,o={};switch(n){case 21589:1&(r=e.read_shift(1))&&(o.mtime=e.read_shift(4)),a>5&&(2&r&&(o.atime=e.read_shift(4)),4&r&&(o.ctime=e.read_shift(4))),o.mtime&&(o.mt=new Date(1e3*o.mtime));break;case 1:var s=e.read_shift(4),l=e.read_shift(4);o.usz=l*Math.pow(2,32)+s,s=e.read_shift(4),l=e.read_shift(4),o.csz=l*Math.pow(2,32)+s}e.l=i,t[n]=o}return t}function g(){return e||(e=undefined)}function v(e,t){if(80==e[0]&&75==e[1])return ge(e,t);if(109==(32|e[0])&&105==(32|e[1]))return function(e,t){if("mime-version:"!=M(e.slice(0,13)).toLowerCase())throw new Error("Unsupported MAD header");var r=t&&t.root||"",n=(a&&Buffer.isBuffer(e)?e.toString("binary"):M(e)).split("\r\n"),i=0,o="";for(i=0;i0&&(r=(r=r.slice(0,r.length-1)).slice(0,r.lastIndexOf("/")+1),o.slice(0,r.length)!=r););var s=(n[1]||"").match(/boundary="(.*?)"/);if(!s)throw new Error("MAD cannot find boundary");var l="--"+(s[1]||""),c=[],f=[],h={FileIndex:c,FullPaths:f};C(h);var u,p=0;for(i=0;i=a&&(u-=a),!o[u]){l=[];var d=[];for(h=u;h>=0;){d[h]=!0,o[h]=!0,s[s.length]=h,l.push(e[h]);var m=r[Math.floor(4*h/n)];if(n<4+(p=4*h&c))throw new Error("FAT boundary crossed: "+h+" 4 "+n);if(!e[m])break;if(d[h=xt(e[m],p)])break}i[u]={nodes:s,data:Ye([l])}}return i}(v,o,f,c);o0&&s!==T&&(S[s].name="!MiniFAT"),S[f[0]].name="!FAT",S.fat_addrs=f,S.ssz=c;var k=[],_=[],A=[];!function(e,t,r,n,a,i,o,s){for(var l,c=0,f=n.length?2:0,h=t[e].data,u=0,p=0;u0&&c!==T&&(t[c].name="!StreamData")):m.size>=4096?(m.storage="fat",void 0===t[m.start]&&(t[m.start]=w(r,m.start,t.fat_addrs,t.ssz)),t[m.start].name=m.name,m.content=t[m.start].data.slice(0,m.size)):(m.storage="minifat",m.size<0?m.size=0:c!==T&&m.start!==T&&t[c]&&(m.content=b(m,t[c].data,(t[s]||{}).data))),m.content&&Tt(m.content,0),i[l]=m,o.push(m)}}(o,S,v,k,n,{},_,s),function(e,t,r){for(var n=0,a=0,i=0,o=0,s=0,l=r.length,c=[],f=[];n0&&o>=0;)i.push(t.slice(o*A,o*A+A)),a-=A,o=xt(r,4*o);return 0===i.length?Dt(0):h(i).slice(0,e.size)}function x(e,t,r,n,a){var i=T;if(e===T){if(0!==t)throw new Error("DIFAT chain shorter than expected")}else if(-1!==e){var o=r[e],s=(n>>>2)-1;if(!o)return;for(var l=0;l=1&&x(xt(o,n-4),t-1,r,n,a)}}function w(e,t,r,n,a){var i=[],o=[];a||(a=[]);var s=n-1,l=0,c=0;for(l=t;l>=0;){a[l]=!0,i[i.length]=l,o.push(e[l]);var f=r[Math.floor(4*l/n)];if(n<4+(c=4*l&s))throw new Error("FAT boundary crossed: "+l+" 4 "+n);if(!e[f])break;l=xt(e[f],c)}return{nodes:i,data:Ye([o])}}function y(e,t){return new Date(1e3*(bt(e,t+4)/1e7*Math.pow(2,32)+bt(e,t)/1e7-11644473600))}function C(e,t){var r=t||{},n=r.root||"Root Entry";if(e.FullPaths||(e.FullPaths=[]),e.FileIndex||(e.FileIndex=[]),e.FullPaths.length!==e.FileIndex.length)throw new Error("inconsistent CFB structure");0===e.FullPaths.length&&(e.FullPaths[0]=n+"/",e.FileIndex[0]={name:n,type:5}),r.CLSID&&(e.FileIndex[0].clsid=r.CLSID),function(e){var t="Sh33tJ5";if(re.find(e,"/"+t))return;var r=Dt(4);r[0]=55,r[1]=r[3]=50,r[2]=54,e.FileIndex.push({name:t,type:2,content:r,size:4,L:69,R:69,C:69}),e.FullPaths.push(e.FullPaths[0]+t),S(e)}(e)}function S(e,t){C(e);for(var r=!1,n=!1,a=e.FullPaths.length-1;a>=0;--a){var i=e.FileIndex[a];switch(i.type){case 0:n?r=!0:(e.FileIndex.pop(),e.FullPaths.pop());break;case 1:case 2:case 5:n=!0,isNaN(i.R*i.L*i.C)&&(r=!0),i.R>-1&&i.L>-1&&i.R==i.L&&(r=!0);break;default:r=!0}}if(r||t){var s=new Date(1987,1,19),l=0,c=Object.create?Object.create(null):{},h=[];for(a=0;a1?1:-1,p.size=0,p.type=5;else if("/"==d.slice(-1)){for(l=a+1;l=h.length?-1:l,l=a+1;l=h.length?-1:l,p.type=1}else o(e.FullPaths[a+1]||"")==o(d)&&(p.R=a+1),p.type=2}}}function k(e,t){var r=t||{};if("mad"==r.fileType)return function(e,t){for(var r=t||{},n=r.boundary||"SheetJS",i=["MIME-Version: 1.0",'Content-Type: multipart/related; boundary="'+(n="------="+n).slice(2)+'"',"","",""],o=e.FullPaths[0],s=o,l=e.FileIndex[0],c=1;c=32&&d<128&&++u;var g=u>=4*p/5;i.push(n),i.push("Content-Location: "+(r.root||"file:///C:/SheetJS/")+s),i.push("Content-Transfer-Encoding: "+(g?"quoted-printable":"base64")),i.push("Content-Type: "+xe(l,s)),i.push(""),i.push(g?ye(h):we(h))}return i.push(n+"--\r\n"),i.join("\r\n")}(e,r);if(S(e),"zip"===r.fileType)return function(e,t){var r=t||{},n=[],a=[],i=Dt(1),o=r.compression?8:0,s=0,l=0,f=0,u=0,p=0,m=e.FullPaths[0],g=m,v=e.FileIndex[0],b=[],x=0;for(l=1;l0&&(i<4096?t+=i+63>>6:r+=i+511>>9)}}for(var o=e.FullPaths.length+3>>2,s=t+127>>7,l=(t+7>>3)+r+o+s,c=l+127>>7,f=c<=109?0:Math.ceil((c-109)/127);l+c+f+127>>7>c;)f=++c<=109?0:Math.ceil((c-109)/127);var h=[1,f,c,s,o,r,t,0];return e.FileIndex[0].size=t<<6,h[7]=(e.FileIndex[0].start=h[0]+h[1]+h[2]+h[3]+h[4]+h[5])+(h[6]+7>>3),h}(e),i=Dt(n[7]<<9),o=0,s=0;for(o=0;o<8;++o)i.write_shift(1,O[o]);for(o=0;o<8;++o)i.write_shift(2,0);for(i.write_shift(2,62),i.write_shift(2,3),i.write_shift(2,65534),i.write_shift(2,9),i.write_shift(2,6),o=0;o<3;++o)i.write_shift(2,0);for(i.write_shift(4,0),i.write_shift(4,n[2]),i.write_shift(4,n[0]+n[1]+n[2]+n[3]-1),i.write_shift(4,0),i.write_shift(4,4096),i.write_shift(4,n[3]?n[0]+n[1]+n[2]-1:T),i.write_shift(4,n[3]),i.write_shift(-4,n[1]?n[0]-1:T),i.write_shift(4,n[1]),o=0;o<109;++o)i.write_shift(-4,o>9)));for(l(n[6]+7>>3);511&i.l;)i.write_shift(-4,E.ENDOFCHAIN);for(s=o=0,f=0;f=4096||(p.start=s,l(u+63>>6)));for(;511&i.l;)i.write_shift(-4,E.ENDOFCHAIN);for(o=0;o31&&(console.error("Name "+g+" will be truncated to "+g.slice(0,31)),g=g.slice(0,31)),u=2*(g.length+1),i.write_shift(64,g,"utf16le"),i.write_shift(2,u),i.write_shift(1,p.type),i.write_shift(1,p.color),i.write_shift(-4,p.L),i.write_shift(-4,p.R),i.write_shift(-4,p.C),p.clsid)i.write_shift(16,p.clsid,"hex");else for(f=0;f<4;++f)i.write_shift(4,0);i.write_shift(4,p.state||0),i.write_shift(4,0),i.write_shift(4,0),i.write_shift(4,0),i.write_shift(4,0),i.write_shift(4,p.start),i.write_shift(4,p.size),i.write_shift(4,0)}else{for(f=0;f<17;++f)i.write_shift(4,0);for(f=0;f<3;++f)i.write_shift(4,-1);for(f=0;f<12;++f)i.write_shift(4,0)}}for(o=1;o=4096)if(i.l=p.start+1<<9,a&&Buffer.isBuffer(p.content))p.content.copy(i,i.l,0,p.size),i.l+=p.size+511&-512;else{for(f=0;f0&&p.size<4096)if(a&&Buffer.isBuffer(p.content))p.content.copy(i,i.l,0,p.size),i.l+=p.size+63&-64;else{for(f=0;f>16|U>>8|U));function B(e,t){var r=z[255&e];return t<=8?r>>>8-t:(r=r<<8|z[e>>8&255],t<=16?r>>>16-t:(r=r<<8|z[e>>16&255])>>>24-t)}function W(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=6?0:e[n+1]<<8))>>>r&3}function H(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=5?0:e[n+1]<<8))>>>r&7}function X(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=3?0:e[n+1]<<8))>>>r&31}function V(e,t){var r=7&t,n=t>>>3;return(e[n]|(r<=1?0:e[n+1]<<8))>>>r&127}function G(e,t,r){var n=7&t,a=t>>>3,i=(1<>>n;return r<8-n?o&i:(o|=e[a+1]<<8-n,r<16-n?o&i:(o|=e[a+2]<<16-n,r<24-n?o&i:(o|=e[a+3]<<24-n)&i))}function J(e,t,r){var n=7&t,a=t>>>3;return n<=5?e[a]|=(7&r)<>8-n),t+3}function q(e,t,r){return r=(1&r)<<(7&t),e[t>>>3]|=r,t+1}function Y(e,t,r){var n=t>>>3;return r<<=7&t,e[n]|=255&r,r>>>=8,e[n+1]=r,t+8}function Z(e,t,r){var n=t>>>3;return r<<=7&t,e[n]|=255&r,r>>>=8,e[n+1]=255&r,e[n+2]=r>>>8,t+16}function K(e,t){var r=e.length,n=2*r>t?2*r:t+5,i=0;if(r>=t)return e;if(a){var o=l(n);if(e.copy)e.copy(o);else for(;i>n-h,o=(1<=0;--o)t[s|o<0;)t[t.l++]=e[r++]}return t.l}(t,r):function(t,r){for(var a=0,i=0,o=$?new Uint16Array(32768):[];i0;)r[r.l++]=t[i++];a=8*r.l}else{a=J(r,a,+!(i+s!=t.length)+2);for(var l=0;s-- >0;){var c=t[i],f=-1,h=0;if((f=o[l=32767&(l<<5^c)])&&((f|=-32768&i)>i&&(f-=32768),f2){(c=n[h])<=22?a=Y(r,a,z[c+1]>>1)-1:(Y(r,a,3),Y(r,a+=5,z[c-23]>>5),a+=3);var u=c<8?0:c-4>>2;u>0&&(Z(r,a,h-P[c]),a+=u),c=e[i-f],a=Y(r,a,z[c]>>3),a-=3;var p=c<4?0:c-2>>1;p>0&&(Z(r,a,i-f-R[c]),a+=p);for(var d=0;d>>3;return(e[n]|(r<=4?0:e[n+1]<<8))>>>r&15}(e,t+=5)+4;t+=4;for(var i=0,o=$?new Uint8Array(19):Q(19),s=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],l=1,c=$?new Uint8Array(8):Q(8),f=$?new Uint8Array(8):Q(8),h=o.length,u=0;u>8-d;for(var m=(1<<7-d)-1;m>=0;--m)fe[p|m<>>=3){case 16:for(i=3+W(e,t),t+=2,p=g[g.length-1];i-- >0;)g.push(p);break;case 17:for(i=3+H(e,t),t+=3;i-- >0;)g.push(0);break;case 18:for(i=11+V(e,t),t+=7;i-- >0;)g.push(0);break;default:g.push(p),l>>0,c=0,f=0;!(1&n);)if(n=H(e,r),r+=3,n>>>1!=0)for(n>>1==1?(c=9,f=5):(r=pe(e,r),c=he,f=ue);;){!t&&o>>1==1?ne[h]:le[h];if(r+=15&u,(u>>>=4)>>>8&255){if(256==u)break;var p=(u-=257)<8?0:u-4>>2;p>5&&(p=0);var d=i+P[u];p>0&&(d+=G(e,r,p),r+=p),h=G(e,r,f),r+=15&(u=n>>>1==1?ae[h]:ce[h]);var m=(u>>>=4)<4?0:u-2>>1,g=R[u];for(m>0&&(g+=G(e,r,m),r+=m),!t&&o>>3]|e[1+(r>>>3)]<<8;if(r+=32,v>0)for(!t&&o0;)a[i++]=e[r>>>3],r+=8}return t?[a,r+7>>>3]:[a.slice(0,i),r+7>>>3]}(e.slice(e.l||0),t);return e.l+=r[1],r[0]}function me(e,t){if(!e)throw new Error(t);"undefined"!=typeof console&&console.error(t)}function ge(e,t){var r=e;Tt(r,0);var n={FileIndex:[],FullPaths:[]};C(n,{root:t.root});for(var a=r.length-4;(80!=r[a]||75!=r[a+1]||5!=r[a+2]||6!=r[a+3])&&a>=0;)--a;r.l=a+4,r.l+=4;var i=r.read_shift(2);r.l+=6;var o=r.read_shift(4);for(r.l=o,a=0;a>>=5);r>>>=4,n.setMilliseconds(0),n.setFullYear(r+1980),n.setMonth(i-1),n.setDate(a);var o=31&t,s=63&(t>>>=5);return t>>>=6,n.setHours(t),n.setMinutes(s),n.setSeconds(o<<1),n}(e);if(8257&i)throw new Error("Unsupported ZIP encryption");e.read_shift(4);for(var l=e.read_shift(4),c=e.read_shift(4),f=e.read_shift(2),h=e.read_shift(2),u="",p=0;p>2,s=(3&n)<<4|(a=e[f++])>>4,l=(15&a)<<2|(i=e[f++])>>6,c=63&i,isNaN(a)?l=c=64:isNaN(i)&&(c=64),r+=t.charAt(o)+t.charAt(s)+t.charAt(l)+t.charAt(c);return r}(new Uint8Array(ne(a)));return chrome.downloads.download({url:l,filename:e,saveAs:!0})}}if("undefined"!=typeof $&&"undefined"!=typeof File&&"undefined"!=typeof Folder)try{var c=File(e);return c.open("w"),c.encoding="binary",Array.isArray(r)&&(r=function(e){if(Array.isArray(e))return e.map((function(e){return String.fromCharCode(e)})).join("");for(var t=[],r=0;r=60&&e<61)return e;var t=new Date;return t.setTime(24*(e>60?e:e+1)*60*60*1e3+se),t}var ue=/^(\d+):(\d+)(:\d+)?(\.\d+)?$/,pe=/^(\d+)-(\d+)-(\d+)$/,de=/^(\d+)-(\d+)-(\d+)[T ](\d+):(\d+)(:\d+)?(\.\d+)?$/;function me(e,t){if(e instanceof Date)return e;var r=e.match(ue);return r?new Date((t?ce:le)+1e3*(60*(60*parseInt(r[1],10)+parseInt(r[2],10))+(r[3]?parseInt(r[3].slice(1),10):0))+(r[4]?parseInt((r[4]+"000").slice(1,4),10):0)):(r=e.match(pe))?new Date(Date.UTC(+r[1],+r[2]-1,+r[3],0,0,0,0)):(r=e.match(de))?new Date(Date.UTC(+r[1],+r[2]-1,+r[3],+r[4],+r[5],r[6]&&parseInt(r[6].slice(1),10)||0,r[7]&&parseInt((r[7]+"0000").slice(1,4),10)||0)):new Date(e)}function ge(e){if("undefined"!=typeof JSON&&!Array.isArray(e))return JSON.parse(JSON.stringify(e));if("object"!=typeof e||null==e)return e;if(e instanceof Date)return new Date(e.getTime());var t={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=ge(e[r]));return t}function ve(e,t){for(var r="";r.length3&&-1==Se.indexOf(t))return i}else if(t.replace(/[ap]m?/,"").match(/[a-z]/))return i;return o<0||o>8099||e.match(/[^-0-9:,\/\\\ ]/)?i:a}function _e(e){return new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds()))}function Ae(e,t,r){if(e.FullPaths){var n;if(Array.isArray(r)&&"string"==typeof r[0]&&(r=r.join("")),"string"==typeof r)return n=a?i(r):function(e){for(var t=[],r=0,n=e.length+250,a=s(e.length+255),i=0;i>6&31,a[r++]=128|63&o;else if(o>=55296&&o<57344){o=64+(1023&o);var l=1023&e.charCodeAt(++i);a[r++]=240|o>>8&7,a[r++]=128|o>>2&63,a[r++]=128|l>>6&15|(3&o)<<4,a[r++]=128|63&l}else a[r++]=224|o>>12&15,a[r++]=128|o>>6&63,a[r++]=128|63&o;r>n&&(t.push(a.slice(0,r)),r=0,a=s(65535),n=65530)}return t.push(a.slice(0,r)),h(t)}(r),re.utils.cfb_add(e,t,n);re.utils.cfb_add(e,t,r)}else e.file(t,r)}var Te='\r\n',De=oe({""":'"',"'":"'",">":">","<":"<","&":"&"}),Oe=/[&<>'"]/g,Fe=/[\u0000-\u0008\u000b-\u001f\uFFFE-\uFFFF]/g;function Ee(e){return(e+"").replace(Oe,(function(e){return De[e]})).replace(Fe,(function(e){return"_x"+("000"+e.charCodeAt(0).toString(16)).slice(-4)+"_"}))}var Me=/[\u0000-\u001f]/g;function Ne(e){return(e+"").replace(Oe,(function(e){return De[e]})).replace(/\n/g,"
").replace(Me,(function(e){return"&#x"+("000"+e.charCodeAt(0).toString(16)).slice(-4)+";"}))}function Ie(e){for(var t="",r=0,n=0,a=0,i=0,o=0,s=0;r191&&n<224?(o=(31&n)<<6,o|=63&a,t+=String.fromCharCode(o)):(i=e.charCodeAt(r++),n<240?t+=String.fromCharCode((15&n)<<12|(63&a)<<6|63&i):(s=((7&n)<<18|(63&a)<<12|(63&i)<<6|63&(o=e.charCodeAt(r++)))-65536,t+=String.fromCharCode(55296+(s>>>10&1023)),t+=String.fromCharCode(56320+(1023&s)))));return t}function Pe(e){var t,r,n,a=s(2*e.length),i=1,o=0,l=0;for(r=0;r>>10&1023),t=56320+(1023&t)),0!==l&&(a[o++]=255&l,a[o++]=l>>>8,l=0),a[o++]=t%256,a[o++]=t>>>8;return a.slice(0,o).toString("ucs2")}function Re(e){return i(e,"binary").toString("utf8")}var Le="foo bar baz☃🍣",Ue=a&&(Re(Le)==Ie(Le)&&Re||Pe(Le)==Ie(Le)&&Pe)||Ie,$e=a?function(e){return i(e,"utf8").toString("binary")}:function(e){for(var t=[],r=0,n=0,a=0;r>6))),t.push(String.fromCharCode(128+(63&n)));break;case n>=55296&&n<57344:n-=55296,a=e.charCodeAt(r++)-56320+(n<<10),t.push(String.fromCharCode(240+(a>>18&7))),t.push(String.fromCharCode(144+(a>>12&63))),t.push(String.fromCharCode(128+(a>>6&63))),t.push(String.fromCharCode(128+(63&a)));break;default:t.push(String.fromCharCode(224+(n>>12))),t.push(String.fromCharCode(128+(n>>6&63))),t.push(String.fromCharCode(128+(63&n)))}return t.join("")},ze=function(){var e=[["nbsp"," "],["middot","·"],["quot",'"'],["apos","'"],["gt",">"],["lt","<"],["amp","&"]].map((function(e){return[new RegExp("&"+e[0]+";","ig"),e[1]]}));return function(t){for(var r=t.replace(/^[\t\n\r ]+/,"").replace(/(^|[^\t\n\r ])[\t\n\r ]+$/,"$1").replace(/>\s+/g,">").replace(/\b\s+/g,"\n").replace(/<[^<>]*>/g,""),n=0;n"+t+""}function We(e){return ie(e).map((function(t){return" "+t+'="'+e[t]+'"'})).join("")}function He(e,t,r){return"<"+e+(null!=r?We(r):"")+(null!=t?(t.match(je)?' xml:space="preserve"':"")+">"+t+""}function Xe(e,t){try{return e.toISOString().replace(/\.\d*/,"")}catch(e){if(t)throw e}return""}var Ve={CORE_PROPS:"http://schemas.openxmlformats.org/package/2006/metadata/core-properties",CUST_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/custom-properties",EXT_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",CT:"http://schemas.openxmlformats.org/package/2006/content-types",RELS:"http://schemas.openxmlformats.org/package/2006/relationships",TCMNT:"http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments",dc:"http://purl.org/dc/elements/1.1/",dcterms:"http://purl.org/dc/terms/",dcmitype:"http://purl.org/dc/dcmitype/",mx:"http://schemas.microsoft.com/office/mac/excel/2008/main",r:"http://schemas.openxmlformats.org/officeDocument/2006/relationships",sjs:"http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties",vt:"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",xsi:"http://www.w3.org/2001/XMLSchema-instance",xsd:"http://www.w3.org/2001/XMLSchema"},Ge=["http://schemas.openxmlformats.org/spreadsheetml/2006/main","http://purl.oclc.org/ooxml/spreadsheetml/main","http://schemas.microsoft.com/office/excel/2006/main","http://schemas.microsoft.com/office/excel/2006/2"],Je={o:"urn:schemas-microsoft-com:office:office",x:"urn:schemas-microsoft-com:office:excel",ss:"urn:schemas-microsoft-com:office:spreadsheet",dt:"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882",mv:"http://macVmlSchemaUri",v:"urn:schemas-microsoft-com:vml",html:"http://www.w3.org/TR/REC-html40"};var qe=function(e){for(var t=[],r=0;r0&&Buffer.isBuffer(e[0][0])?Buffer.concat(e[0].map((function(e){return Buffer.isBuffer(e)?e:i(e)}))):qe(e)}:qe,Ze=function(e,t,r){for(var n=[],a=t;a0?rt(e,t+4,t+4+r-1):""},at=nt,it=function(e,t){var r=bt(e,t);return r>0?rt(e,t+4,t+4+r-1):""},ot=it,st=function(e,t){var r=2*bt(e,t);return r>0?rt(e,t+4,t+4+r-1):""},lt=st,ct=function(e,t){var r=bt(e,t);return r>0?Ke(e,t+4,t+4+r):""},ft=ct,ht=function(e,t){var r=bt(e,t);return r>0?rt(e,t+4,t+4+r):""},ut=ht,pt=function(e,t){return function(e,t){for(var r=1-2*(e[t+7]>>>7),n=((127&e[t+7])<<4)+(e[t+6]>>>4&15),a=15&e[t+6],i=5;i>=0;--i)a=256*a+e[t+i];return 2047==n?0==a?r*(1/0):NaN:(0==n?n=-1022:(n-=1023,a+=Math.pow(2,52)),r*Math.pow(2,n-52)*a)}(e,t)},dt=pt;a&&(at=function(e,t){if(!Buffer.isBuffer(e))return nt(e,t);var r=e.readUInt32LE(t);return r>0?e.toString("utf8",t+4,t+4+r-1):""},ot=function(e,t){if(!Buffer.isBuffer(e))return it(e,t);var r=e.readUInt32LE(t);return r>0?e.toString("utf8",t+4,t+4+r-1):""},lt=function(e,t){if(!Buffer.isBuffer(e)||!o)return st(e,t);var r=2*e.readUInt32LE(t);return e.toString("utf16le",t+4,t+4+r-1)},ft=function(e,t){if(!Buffer.isBuffer(e)||!o)return ct(e,t);var r=e.readUInt32LE(t);return e.toString("utf16le",t+4,t+4+r)},ut=function(e,t){if(!Buffer.isBuffer(e))return ht(e,t);var r=e.readUInt32LE(t);return e.toString("utf8",t+4,t+4+r)},dt=function(e,t){return Buffer.isBuffer(e)?e.readDoubleLE(t):pt(e,t)});var mt=function(e,t){return e[t]},gt=function(e,t){return 256*e[t+1]+e[t]},vt=function(e,t){var r=256*e[t+1]+e[t];return r<32768?r:-1*(65535-r+1)},bt=function(e,t){return e[t+3]*(1<<24)+(e[t+2]<<16)+(e[t+1]<<8)+e[t]},xt=function(e,t){return e[t+3]<<24|e[t+2]<<16|e[t+1]<<8|e[t]},wt=function(e,t){return e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3]};function yt(t,r){var n,i,s,l,c,f,h="",u=[];switch(r){case"dbcs":if(f=this.l,a&&Buffer.isBuffer(this)&&o)h=this.slice(this.l,this.l+2*t).toString("utf16le");else for(c=0;c0?xt:wt)(this,this.l),this.l+=4,n);case 8:case-8:if("f"===r)return i=8==t?dt(this,this.l):dt([this[this.l+7],this[this.l+6],this[this.l+5],this[this.l+4],this[this.l+3],this[this.l+2],this[this.l+1],this[this.l+0]],0),this.l+=8,i;t=8;case 16:h=et(this,this.l,t)}}return this.l+=t,h}var Ct=function(e,t,r){e[r]=255&t,e[r+1]=t>>>8&255,e[r+2]=t>>>16&255,e[r+3]=t>>>24&255},St=function(e,t,r){e[r]=255&t,e[r+1]=t>>8&255,e[r+2]=t>>16&255,e[r+3]=t>>24&255},kt=function(e,t,r){e[r]=255&t,e[r+1]=t>>>8&255};function _t(e,t,r){var n=0,a=0;if("dbcs"===r){for(a=0;a!=t.length;++a)kt(this,t.charCodeAt(a),this.l+2*a);n=2*t.length}else if("sbcs"===r||"cpstr"==r){for(t=t.replace(/[^\x00-\x7F]/g,"_"),a=0;a!=t.length;++a)this[this.l+a]=255&t.charCodeAt(a);n=t.length}else{if("hex"===r){for(;a>8}for(;this.l>>=8,this[this.l+1]=255&t;break;case 3:n=3,this[this.l]=255&t,t>>>=8,this[this.l+1]=255&t,t>>>=8,this[this.l+2]=255&t;break;case 4:n=4,Ct(this,t,this.l);break;case 8:if(n=8,"f"===r){!function(e,t,r){var n=(t<0||1/t==-1/0?1:0)<<7,a=0,i=0,o=n?-t:t;isFinite(o)?0==o?a=i=0:(a=Math.floor(Math.log(o)/Math.LN2),i=o*Math.pow(2,52-a),a<=-1023&&(!isFinite(i)||i>4|n}(this,t,this.l);break}case 16:break;case-4:n=4,St(this,t,this.l)}}return this.l+=n,this}function At(e,t){var r=et(this,this.l,e.length>>1);if(r!==e)throw new Error(t+"Expected "+e+" saw "+r);this.l+=e.length>>1}function Tt(e,t){e.l=t,e.read_shift=yt,e.chk=At,e.write_shift=_t}function Dt(e){var t=s(e);return Tt(t,0),t}function Ot(e){return""+(e+1)}function Ft(e){if(e<0)throw new Error("invalid column "+e);var t="";for(++e;e;e=Math.floor((e-1)/26))t=String.fromCharCode((e-1)%26+65)+t;return t}function Et(e){for(var t=0,r=0,n=0;n=48&&a<=57?t=10*t+(a-48):a>=65&&a<=90&&(r=26*r+(a-64))}return{c:r-1,r:t-1}}function Mt(e){for(var t=e.c+1,r="";t;t=(t-1)/26|0)r=String.fromCharCode((t-1)%26+65)+r;return r+(e.r+1)}function Nt(e){var t=e.indexOf(":");return-1==t?{s:Et(e),e:Et(e)}:{s:Et(e.slice(0,t)),e:Et(e.slice(t+1))}}function It(e,t){return void 0===t||"number"==typeof t?It(e.s,e.e):("string"!=typeof e&&(e=Mt(e)),"string"!=typeof t&&(t=Mt(t)),e==t?e:e+":"+t)}function Pt(e){var t=Nt(e);return"$"+Ft(t.s.c)+"$"+Ot(t.s.r)+":$"+Ft(t.e.c)+"$"+Ot(t.e.r)}function Rt(e,t){if(!(e||t&&t.biff<=5&&t.biff>=2))throw new Error("empty sheet name");return/[^\w\u4E00-\u9FFF\u3040-\u30FF]/.test(e)?"'"+e.replace(/'/g,"''")+"'":e}function Lt(e){var t={s:{c:0,r:0},e:{c:0,r:0}},r=0,n=0,a=0,i=e.length;for(r=0;n26);++n)r=26*r+a;for(t.s.c=--r,r=0;n9);++n)r=10*r+a;if(t.s.r=--r,n===i||10!=a)return t.e.c=t.s.c,t.e.r=t.s.r,t;for(++n,r=0;n!=i&&!((a=e.charCodeAt(n)-64)<1||a>26);++n)r=26*r+a;for(t.e.c=--r,r=0;n!=i&&!((a=e.charCodeAt(n)-48)<0||a>9);++n)r=10*r+a;return t.e.r=--r,t}function Ut(e,t){var r="d"==e.t&&t instanceof Date;if(null!=e.z)try{return e.w=K(e.z,r?fe(t):t)}catch(e){}try{return e.w=K((e.XF||{}).numFmtId||(r?14:0),r?fe(t):t)}catch(e){return""+t}}function $t(e,t,r){return null==e||null==e.t||"z"==e.t?"":void 0!==e.w?e.w:("d"==e.t&&!e.z&&r&&r.dateNF&&(e.z=r.dateNF),"e"==e.t?jt[e.v]||e.v:Ut(e,null==t?e.v:t))}function zt(e,t,r){var n=r||{},a=e?null!=e["!data"]:n.dense,i=e||(a?{"!data":[]}:{});a&&!i["!data"]&&(i["!data"]=[]);var o=0,s=0;if(i&&null!=n.origin)if("number"==typeof n.origin)o=n.origin;else{var l="string"==typeof n.origin?Et(n.origin):n.origin;o=l.r,s=l.c}var c={s:{c:1e7,r:1e7},e:{c:0,r:0}};if(i["!ref"]){var f=Lt(i["!ref"]);c.s.c=f.s.c,c.s.r=f.s.r,c.e.c=Math.max(c.e.c,f.e.c),c.e.r=Math.max(c.e.r,f.e.r),-1==o&&(c.e.r=o=i["!ref"]?f.e.r+1:0)}else c.s.c=c.e.c=c.s.r=c.e.r=0;for(var h=[],u=!1,p=0;p!=t.length;++p)if(t[p]){if(!Array.isArray(t[p]))throw new Error("aoa_to_sheet expects an array of arrays");var d=o+p;a&&(i["!data"][d]||(i["!data"][d]=[]),h=i["!data"][d]);for(var m=t[p],g=0;g!=m.length;++g)if(void 0!==m[g]){var v={v:m[g],t:""},b=s+g;if(c.s.r>d&&(c.s.r=d),c.s.c>b&&(c.s.c=b),c.e.r0&&(n=e[r][0],i[i.length]=He("Override",null,{PartName:("/"==n[0]?"":"/")+n,ContentType:Ht[r][t.bookType]||Ht[r].xlsx}))},s=function(r){(e[r]||[]).forEach((function(e){i[i.length]=He("Override",null,{PartName:("/"==e[0]?"":"/")+e,ContentType:Ht[r][t.bookType]||Ht[r].xlsx})}))},l=function(t){(e[t]||[]).forEach((function(e){i[i.length]=He("Override",null,{PartName:("/"==e[0]?"":"/")+e,ContentType:a[t][0]})}))};return o("workbooks"),s("sheets"),s("charts"),l("themes"),["strs","styles"].forEach(o),["coreprops","extprops","custprops"].forEach(l),l("vba"),l("comments"),l("threadedcomments"),l("drawings"),s("metadata"),l("people"),!r&&i.length>2&&(i[i.length]="",i[1]=i[1].replace("/>",">")),i.join("")}var Vt={WB:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",SHEET:"http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",HLINK:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",VML:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",XPATH:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",XMISS:"http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",XLINK:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",CXML:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml",CXMLP:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",CMNT:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",CORE_PROPS:"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",EXT_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",CUST_PROPS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties",SST:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",STY:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",THEME:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",CHART:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",CHARTEX:"http://schemas.microsoft.com/office/2014/relationships/chartEx",CS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet",WS:["http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet","http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"],DS:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet",MS:"http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet",IMG:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",DRAW:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",XLMETA:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata",TCMNT:"http://schemas.microsoft.com/office/2017/10/relationships/threadedComment",PEOPLE:"http://schemas.microsoft.com/office/2017/10/relationships/person",CONN:"http://schemas.openxmlformats.org/officeDocument/2006/relationships/connections",VBA:"http://schemas.microsoft.com/office/2006/relationships/vbaProject"};function Gt(e){var t=[Te,He("Relationships",null,{xmlns:Ve.RELS})];return ie(e["!id"]).forEach((function(r){t[t.length]=He("Relationship",null,e["!id"][r])})),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}function Jt(e,t,r,n,a,i){if(a||(a={}),e["!id"]||(e["!id"]={}),e["!idx"]||(e["!idx"]=1),t<0)for(t=e["!idx"];e["!id"]["rId"+t];++t);if(e["!idx"]=t+1,a.Id="rId"+t,a.Type=n,a.Target=r,i?a.TargetMode=i:[Vt.HLINK,Vt.XPATH,Vt.XMISS].indexOf(a.Type)>-1&&(a.TargetMode="External"),e["!id"][a.Id])throw new Error("Cannot rewrite rId "+t);return e["!id"][a.Id]=a,e[("/"+a.Target).replace("//","/")]=a,t}var qt=[["cp:category","Category"],["cp:contentStatus","ContentStatus"],["cp:keywords","Keywords"],["cp:lastModifiedBy","LastAuthor"],["cp:lastPrinted","LastPrinted"],["cp:revision","RevNumber"],["cp:version","Version"],["dc:creator","Author"],["dc:description","Comments"],["dc:identifier","Identifier"],["dc:language","Language"],["dc:subject","Subject"],["dc:title","Title"],["dcterms:created","CreatedDate","date"],["dcterms:modified","ModifiedDate","date"]];function Yt(e,t,r,n,a){null==a[e]&&null!=t&&""!==t&&(a[e]=t,t=Ee(t),n[n.length]=r?He(e,t,r):Be(e,t))}var Zt=[["Application","Application","string"],["AppVersion","AppVersion","string"],["Company","Company","string"],["DocSecurity","DocSecurity","string"],["Manager","Manager","string"],["HyperlinksChanged","HyperlinksChanged","bool"],["SharedDoc","SharedDoc","bool"],["LinksUpToDate","LinksUpToDate","bool"],["ScaleCrop","ScaleCrop","bool"],["HeadingPairs","HeadingPairs","raw"],["TitlesOfParts","TitlesOfParts","raw"]];function Kt(e){var t=[Te,He("Properties",null,{xmlns:Ve.CUST_PROPS,"xmlns:vt":Ve.vt})];if(!e)return t.join("");var r=1;return ie(e).forEach((function(n){++r,t[t.length]=He("property",function(e,t){switch(typeof e){case"string":var r=He("vt:lpwstr",Ee(e));return t&&(r=r.replace(/"/g,"_x0022_")),r;case"number":return He((0|e)==e?"vt:i4":"vt:r8",Ee(String(e)));case"boolean":return He("vt:bool",e?"true":"false")}if(e instanceof Date)return He("vt:filetime",Xe(e));throw new Error("Unable to serialize "+e)}(e[n],!0),{fmtid:"{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",pid:r,name:Ee(n)})})),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}var Qt=/^\s|\s$|[\t\n\r]/;var er=6;var tr=96;function rr(e){return 96*e/tr}function nr(e,t){var r,n=[Te,He("styleSheet",null,{xmlns:Ge[0],"xmlns:vt":Ve.vt})];return e.SSF&&null!=(r=function(e){var t=[""];return[[5,8],[23,26],[41,44],[50,392]].forEach((function(r){for(var n=r[0];n<=r[1];++n)null!=e[n]&&(t[t.length]=He("numFmt",null,{numFmtId:n,formatCode:Ee(e[n])}))})),1===t.length?"":(t[t.length]="",t[0]=He("numFmts",null,{count:t.length-2}).replace("/>",">"),t.join(""))}(e.SSF))&&(n[n.length]=r),n[n.length]='',n[n.length]='',n[n.length]='',n[n.length]='',(r=function(e){var t=[];return t[t.length]=He("cellXfs",null),e.forEach((function(e){t[t.length]=He("xf",null,e)})),t[t.length]="",2===t.length?"":(t[0]=He("cellXfs",null,{count:t.length-2}).replace("/>",">"),t.join(""))}(t.cellXfs))&&(n[n.length]=r),n[n.length]='',n[n.length]='',n[n.length]='',n.length>2&&(n[n.length]="",n[1]=n[1].replace("/>",">")),n.join("")}function ar(e,t,r){var n=[21600,21600],a=["m0,0l0",n[1],n[0],n[1],n[0],"0xe"].join(","),i=[He("xml",null,{"xmlns:v":Je.v,"xmlns:o":Je.o,"xmlns:x":Je.x,"xmlns:mv":Je.mv}).replace(/\/>/,">"),He("o:shapelayout",He("o:idmap",null,{"v:ext":"edit",data:e}),{"v:ext":"edit"})],o=65536*e,s=t||[];return s.length>0&&i.push(He("v:shapetype",[He("v:stroke",null,{joinstyle:"miter"}),He("v:path",null,{gradientshapeok:"t","o:connecttype":"rect"})].join(""),{id:"_x0000_t202",coordsize:n.join(","),"o:spt":202,path:a})),s.forEach((function(e){++o,i.push(function(e,t,r){var n=Et(e[0]),a={color2:"#BEFF82",type:"gradient"};"gradient"==a.type&&(a.angle="-180");var i="gradient"==a.type?He("o:fill",null,{type:"gradientUnscaled","v:ext":"view"}):null,o=He("v:fill",i,a),s={on:"t",obscured:"t"};return["",o,He("v:shadow",null,s),He("v:path",null,{"o:connecttype":"none"}),'
','',"","",Be("x:Anchor",[n.c+1,0,n.r+1,0,n.c+3,20,n.r+5,20].join(",")),Be("x:AutoFill","False"),Be("x:Row",String(n.r)),Be("x:Column",String(n.c)),e[1].hidden?"":"","",""].join("")}(e,o))})),i.push(""),i.join("")}function ir(e){var t=[Te,He("comments",null,{xmlns:Ge[0]})],r=[];return t.push(""),e.forEach((function(e){e[1].forEach((function(e){var n=Ee(e.a);-1==r.indexOf(n)&&(r.push(n),t.push(""+n+"")),e.T&&e.ID&&-1==r.indexOf("tc="+e.ID)&&(r.push("tc="+e.ID),t.push("tc="+e.ID+""))}))})),0==r.length&&(r.push("SheetJ5"),t.push("SheetJ5")),t.push(""),t.push(""),e.forEach((function(e){var n=0,a=[],i=0;if(e[1][0]&&e[1][0].T&&e[1][0].ID&&(n=r.indexOf("tc="+e[1][0].ID)),e[1].forEach((function(e){e.a&&(n=r.indexOf(Ee(e.a))),e.T&&++i,a.push(null==e.t?"":Ee(e.t))})),0===i)e[1].forEach((function(n){t.push(''),t.push(Be("t",null==n.t?"":Ee(n.t))),t.push("")}));else{e[1][0]&&e[1][0].T&&e[1][0].ID&&(n=r.indexOf("tc="+e[1][0].ID)),t.push('');for(var o="Comment:\n "+a[0]+"\n",s=1;s")}})),t.push(""),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}function or(e,t,r){var n=[Te,He("ThreadedComments",null,{xmlns:Ve.TCMNT}).replace(/[\/]>/,">")];return e.forEach((function(e){var a="";(e[1]||[]).forEach((function(i,o){if(i.T){i.a&&-1==t.indexOf(i.a)&&t.push(i.a);var s={ref:e[0],id:"{54EE7951-7262-4200-6969-"+("000000000000"+r.tcid++).slice(-12)+"}"};0==o?a=s.id:s.parentId=a,i.ID=s.id,i.a&&(s.personId="{54EE7950-7262-4200-6969-"+("000000000000"+t.indexOf(i.a)).slice(-12)+"}"),n.push(He("threadedComment",Be("text",i.t||""),s))}else delete i.ID}))})),n.push(""),n.join("")}var sr=["xlsb","xlsm","xlam","biff8","xla"];try{/(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g}catch(e){}var lr="undefined"!=typeof Map;function cr(e,t){var r,n,a={min:e+1,max:e+1},i=-1;return t.MDW&&(er=t.MDW),null!=t.width?a.customWidth=1:null!=t.wpx?(r=t.wpx,i=Math.floor((r-5)/er*100+.5)/100):null!=t.wch&&(i=t.wch),i>-1?(a.width=(n=i,Math.round((n*er+5)/er*256)/256),a.customWidth=1):null!=t.width&&(a.width=t.width),t.hidden&&(a.hidden=!0),null!=t.level&&(a.outlineLevel=a.level=t.level),a}function fr(e,t,r){var n,a,i=r.revssf[null!=t.z?t.z:"General"],o=60,s=e.length;if(null==i&&r.ssf)for(;o<392;++o)if(null==r.ssf[o]){n=t.z,a=o,Q(ee[n]||n,a),r.ssf[o]=t.z,r.revssf[t.z]=i=o;break}for(o=0;o!=s;++o)if(e[o].numFmtId===i)return o;return e[s]={numFmtId:i,fontId:0,fillId:0,borderId:0,xfId:0,applyNumberFormat:1},s}function hr(e,t,r){if(e&&e["!ref"]){var n=Lt(e["!ref"]);if(n.e.c=0;--r)n=((16384&n?1:0)|n<<1&32767)^t[r];return 52811^n}(e.password).toString(16).toUpperCase()),He("sheetProtection",null,t)}function mr(e,t,r,n,a,i,o){if(e.c&&r["!comments"].push([t,e.c]),(void 0===e.v||"z"===e.t&&!(n||{}).sheetStubs)&&"string"!=typeof e.f&&void 0===e.z)return"";var s="",l=e.t,c=e.v;if("z"!==e.t)switch(e.t){case"b":s=e.v?"1":"0";break;case"n":isNaN(e.v)?(e.t="e",s=jt[e.v=36]):isFinite(e.v)?s=""+e.v:(e.t="e",s=jt[e.v=7]);break;case"e":s=jt[e.v];break;case"d":if(n&&n.cellDates){var f=me(e.v,o);s=f.toISOString(),f.getUTCFullYear()<1900&&(s=s.slice(s.indexOf("T")+1).replace("Z",""))}else(e=ge(e)).t="n",s=""+(e.v=fe(me(e.v,o),o));void 0===e.z&&(e.z=S[14]);break;default:s=e.v}var h="z"==e.t||null==e.v?"":Be("v",Ee(s)),u={r:t},p=fr(n.cellXfs,e,n);switch(0!==p&&(u.s=p),e.t){case"n":case"z":break;case"d":u.t="d";break;case"b":u.t="b";break;case"e":u.t="e";break;default:if(null==e.v){delete e.t;break}if(e.v.length>32767)throw new Error("Text length must not exceed 32767 characters");if(n&&n.bookSST){h=Be("v",""+function(e,t,r){var n=0,a=e.length;if(r){if(lr?r.has(t):Object.prototype.hasOwnProperty.call(r,t))for(var i=lr?r.get(t):r[t];n16383||f.e.r>1048575){if(t.WTF)throw new Error("Range "+c+" exceeds format limit A1:XFD1048576");f.e.c=Math.min(f.e.c,16383),f.e.r=Math.min(f.e.c,1048575),c=It(f)}n||(n={}),l["!comments"]=[];var h=[];!function(e,t,r,n,a){var i=!1,o={},s=null;if("xlsx"!==n.bookType&&t.vbaraw){var l=t.SheetNames[r];try{t.Workbook&&(l=t.Workbook.Sheets[r].CodeName||l)}catch(e){}i=!0,o.codeName=$e(Ee(l))}if(e&&e["!outline"]){var c={summaryBelow:1,summaryRight:1};e["!outline"].above&&(c.summaryBelow=0),e["!outline"].left&&(c.summaryRight=0),s=(s||"")+He("outlinePr",null,c)}(i||s)&&(a[a.length]=He("sheetPr",s,o))}(l,r,e,t,i),i[i.length]=He("dimension",null,{ref:c}),i[i.length]=function(e,t,r,n){var a={workbookViewId:"0"};return(((n||{}).Workbook||{}).Views||[])[0]&&(a.rightToLeft=n.Workbook.Views[0].RTL?"1":"0"),He("sheetViews",He("sheetView",null,a),{})}(0,0,0,r),t.sheetFormat&&(i[i.length]=He("sheetFormatPr",null,{defaultRowHeight:t.sheetFormat.defaultRowHeight||"16",baseColWidth:t.sheetFormat.baseColWidth||"10",outlineLevelRow:t.sheetFormat.outlineLevelRow||"7"})),null!=l["!cols"]&&l["!cols"].length>0&&(i[i.length]=function(e,t){for(var r,n=[""],a=0;a!=t.length;++a)(r=t[a])&&(n[n.length]=He("col",null,cr(a,r)));return n[n.length]="",n.join("")}(0,l["!cols"])),i[a=i.length]="",l["!links"]=[],null!=l["!ref"]&&(s=function(e,t,r,n){var a,i,o=[],s=[],l=Lt(e["!ref"]),c="",f="",h=[],u=0,p=0,d=e["!rows"],m=null!=e["!data"],g=m?e["!data"]:[],v={r:f},b=-1,x=(((n||{}).Workbook||{}).WBProps||{}).date1904;for(p=l.s.c;p<=l.e.c;++p)h[p]=Ft(p);for(u=l.s.r;u<=l.e.r;++u){s=[],f=Ot(u);var w=m?g[u]:[];for(p=l.s.c;p<=l.e.c;++p){a=h[p]+f;var y=m?w[p]:e[a];void 0!==y&&null!=(c=mr(y,a,e,t,0,0,x))&&s.push(c)}(s.length>0||d&&d[u])&&(v={r:f},d&&d[u]&&((i=d[u]).hidden&&(v.hidden=1),b=-1,i.hpx?b=rr(i.hpx):i.hpt&&(b=i.hpt),b>-1&&(v.ht=b,v.customHeight=1),i.level&&(v.outlineLevel=i.level)),o[o.length]=He("row",s.join(""),v))}if(d)for(;u-1&&(v.ht=b,v.customHeight=1),i.level&&(v.outlineLevel=i.level),o[o.length]=He("row","",v));return o.join("")}(l,t,0,r),s.length>0&&(i[i.length]=s)),i.length>a+1&&(i[i.length]="",i[a]=i[a].replace("/>",">")),l["!protect"]&&(i[i.length]=dr(l["!protect"])),null!=l["!autofilter"]&&(i[i.length]=function(e,t,r,n){var a="string"==typeof e.ref?e.ref:It(e.ref);r.Workbook||(r.Workbook={Sheets:[]}),r.Workbook.Names||(r.Workbook.Names=[]);var i=r.Workbook.Names,o=Nt(a);o.s.r==o.e.r&&(o.e.r=Nt(t["!ref"]).e.r,a=It(o));for(var s=0;s0&&(i[i.length]=function(e){if(0===e.length)return"";for(var t='',r=0;r!=e.length;++r)t+='';return t+""}(l["!merges"]));var u,p,d=-1,m=-1;return l["!links"].length>0&&(i[i.length]="",l["!links"].forEach((function(e){e[1].Target&&(u={ref:e[0]},"#"!=e[1].Target.charAt(0)&&(m=Jt(n,-1,Ee(e[1].Target).replace(/#[\s\S]*$/,""),Vt.HLINK),u["r:id"]="rId"+m),(d=e[1].Target.indexOf("#"))>-1&&(u.location=Ee(e[1].Target.slice(d+1))),e[1].Tooltip&&(u.tooltip=Ee(e[1].Tooltip)),u.display=e[1].display,i[i.length]=He("hyperlink",null,u))})),i[i.length]=""),delete l["!links"],null!=l["!margins"]&&(i[i.length]=(function(e,t){if(e){var r=[.7,.7,.75,.75,.3,.3];null==e.left&&(e.left=r[0]),null==e.right&&(e.right=r[1]),null==e.top&&(e.top=r[2]),null==e.bottom&&(e.bottom=r[3]),null==e.header&&(e.header=r[4]),null==e.footer&&(e.footer=r[5])}}(p=l["!margins"]),He("pageMargins",null,p))),t&&!t.ignoreEC&&null!=t.ignoreEC||(i[i.length]=Be("ignoredErrors",He("ignoredError",null,{numberStoredAsText:1,sqref:c}))),h.length>0&&(m=Jt(n,-1,"../drawings/drawing"+(e+1)+".xml",Vt.DRAW),i[i.length]=He("drawing",null,{"r:id":"rId"+m}),l["!drawing"]=h),l["!comments"].length>0&&(m=Jt(n,-1,"../drawings/vmlDrawing"+(e+1)+".vml",Vt.VML),i[i.length]=He("legacyDrawing",null,{"r:id":"rId"+m}),l["!legacy"]=m),i.length>1&&(i[i.length]="",i[1]=i[1].replace("/>",">")),i.join("")}var vr=[["allowRefreshQuery",!1,"bool"],["autoCompressPictures",!0,"bool"],["backupFile",!1,"bool"],["checkCompatibility",!1,"bool"],["CodeName",""],["date1904",!1,"bool"],["defaultThemeVersion",0,"int"],["filterPrivacy",!1,"bool"],["hidePivotFieldList",!1,"bool"],["promptedSolutions",!1,"bool"],["publishItems",!1,"bool"],["refreshAllConnections",!1,"bool"],["saveExternalLinkValues",!0,"bool"],["showBorderUnselectedTables",!0,"bool"],["showInkAnnotation",!0,"bool"],["showObjects","all"],["showPivotChartFilter",!1,"bool"],["updateLinks","userSet"]],br=":][*?/\\".split("");function xr(e,t){try{if(""==e)throw new Error("Sheet name cannot be blank");if(e.length>31)throw new Error("Sheet name cannot exceed 31 chars");if(39==e.charCodeAt(0)||39==e.charCodeAt(e.length-1))throw new Error("Sheet name cannot start or end with apostrophe (')");if("history"==e.toLowerCase())throw new Error("Sheet name cannot be 'History'");br.forEach((function(t){if(-1!=e.indexOf(t))throw new Error("Sheet name cannot contain : \\ / ? * [ ]")}))}catch(e){if(t)return!1;throw e}return!0}function wr(e){if(!e||!e.SheetNames||!e.Sheets)throw new Error("Invalid Workbook");if(!e.SheetNames.length)throw new Error("Workbook is empty");var t,r,n,a=e.Workbook&&e.Workbook.Sheets||[];t=e.SheetNames,r=a,n=!!e.vbaraw,t.forEach((function(e,a){xr(e);for(var i=0;i22)throw new Error("Bad Code Name: Worksheet"+o)}}));for(var i=0;ir||a[h].s.c>l||a[h].e.r1&&(o.rowspan=c),f>1&&(o.colspan=f),n.editable?d=''+d+"":p&&(o["data-t"]=p&&p.t||"z",null!=p.v&&(o["data-v"]=Ne(p.v instanceof Date?p.v.toISOString():p.v)),null!=p.z&&(o["data-z"]=p.z),p.l&&"#"!=(p.l.Target||"#").charAt(0)&&(d=''+d+"")),o.id=(n.id||"sjs")+"-"+u,i.push(He("td",d,o))}}return""+i.join("")+""}function Cr(e,t,r){var n=t.rows;if(!n)throw"Unsupported origin when "+t.tagName+" is not a TABLE";var a=r||{},i=null!=e["!data"],o=0,s=0;if(null!=a.origin)if("number"==typeof a.origin)o=a.origin;else{var l="string"==typeof a.origin?Et(a.origin):a.origin;o=l.r,s=l.c}var c=Math.min(a.sheetRows||1e7,n.length),f={s:{r:0,c:0},e:{r:o,c:s}};if(e["!ref"]){var h=Nt(e["!ref"]);f.s.r=Math.min(f.s.r,h.s.r),f.s.c=Math.min(f.s.c,h.s.c),f.e.r=Math.max(f.e.r,h.e.r),f.e.c=Math.max(f.e.c,h.e.c),-1==o&&(f.e.r=o=h.e.r+1)}var u=[],p=0,d=e["!rows"]||(e["!rows"]=[]),m=0,g=0,v=0,b=0,x=0,w=0;for(e["!cols"]||(e["!cols"]=[]);m1||w>1)&&u.push({s:{r:g+o,c:b+s},e:{r:g+o+(x||1)-1,c:b+s+(w||1)-1}});var D={t:"s",v:_},O=k.getAttribute("data-t")||k.getAttribute("t")||"";null!=_&&(0==_.length?D.t=O||"z":a.raw||0==_.trim().length||"s"==O||("e"==O&&jt[+_]?D={t:"e",v:+_,w:jt[+_]}:"TRUE"===_?D={t:"b",v:!0}:"FALSE"===_?D={t:"b",v:!1}:isNaN(be(_))?isNaN(ke(_).getDate())?35==_.charCodeAt(0)&&null!=Bt[_]&&(D={t:"e",v:Bt[_],w:_}):(D={t:"d",v:me(_)},a.UTC&&(D.v=_e(D.v)),a.cellDates||(D={t:"n",v:fe(D.v)}),D.z=a.dateNF||S[14]):D={t:"n",v:be(_)})),void 0===D.z&&null!=A&&(D.z=A);var F="",E=k.getElementsByTagName("A");if(E&&E.length)for(var M=0;M=c&&(e["!fullref"]=It((f.e.r=n.length-m+g-1+o,f))),e}function Sr(e,t){var r={};return(t||{}).dense&&(r["!data"]=[]),Cr(r,e,t)}function kr(e){var t="",r=function(e){return e.ownerDocument.defaultView&&"function"==typeof e.ownerDocument.defaultView.getComputedStyle?e.ownerDocument.defaultView.getComputedStyle:"function"==typeof getComputedStyle?getComputedStyle:null} +/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */(e);return r&&(t=r(e).getPropertyValue("display")),t||(t=e.style&&e.style.display),"none"===t}function _r(e){var t;(t=[["cellDates",!1],["bookSST",!1],["bookType","xlsx"],["compression",!1],["WTF",!1]],function(e){for(var r=0;r!=t.length;++r){var n=t[r];void 0===e[n[0]]&&(e[n[0]]=n[1]),"n"===n[2]&&(e[n[0]]=Number(e[n[0]]))}})(e)}function Ar(e,t){var r;e&&!e.SSF&&(e.SSF=ge(S)),e&&e.SSF&&(r||(r={}),r[0]="General",r[1]="0",r[2]="0.00",r[3]="#,##0",r[4]="#,##0.00",r[9]="0%",r[10]="0.00%",r[11]="0.00E+00",r[12]="# ?/?",r[13]="# ??/??",r[14]="m/d/yy",r[15]="d-mmm-yy",r[16]="d-mmm",r[17]="mmm-yy",r[18]="h:mm AM/PM",r[19]="h:mm:ss AM/PM",r[20]="h:mm",r[21]="h:mm:ss",r[22]="m/d/yy h:mm",r[37]="#,##0 ;(#,##0)",r[38]="#,##0 ;[Red](#,##0)",r[39]="#,##0.00;(#,##0.00)",r[40]="#,##0.00;[Red](#,##0.00)",r[45]="mm:ss",r[46]="[h]:mm:ss",r[47]="mmss.0",r[48]="##0.0E+0",r[49]="@",r[56]='"上午/下午 "hh"時"mm"分"ss"秒 "',S=r,function(e){for(var t=0;392!=t;++t)void 0!==e[t]&&Q(e[t],t)}(e.SSF),t.revssf=function(e){for(var t=[],r=ie(e),n=0;n!==r.length;++n)t[e[r[n]]]=parseInt(r[n],10);return t}(e.SSF),t.revssf[e.SSF[65535]]=0,t.ssf=e.SSF),t.rels={},t.wbrels={},t.Strings=[],t.Strings.Count=0,t.Strings.Unique=0,lr?t.revStrings=new Map:(t.revStrings={},t.revStrings.foo=[],delete t.revStrings.foo);var n="xml",a=sr.indexOf(t.bookType)>-1,i={workbooks:[],sheets:[],charts:[],dialogs:[],macros:[],rels:[],strs:[],comments:[],threadedcomments:[],links:[],coreprops:[],extprops:[],custprops:[],themes:[],styles:[],calcchains:[],vba:[],drawings:[],metadata:[],people:[],TODO:[],xmlns:""};_r(t=t||{});var o,s,l,c=re.utils.cfb_new(),f="",h=0;if(t.cellXfs=[],fr(t.cellXfs,{},{revssf:{General:0}}),e.Props||(e.Props={}),Ae(c,f="docProps/core.xml",function(e,t){var r=t||{},n=[Te,He("cp:coreProperties",null,{"xmlns:cp":Ve.CORE_PROPS,"xmlns:dc":Ve.dc,"xmlns:dcterms":Ve.dcterms,"xmlns:dcmitype":Ve.dcmitype,"xmlns:xsi":Ve.xsi})],a={};if(!e&&!r.Props)return n.join("");e&&(null!=e.CreatedDate&&Yt("dcterms:created","string"==typeof e.CreatedDate?e.CreatedDate:Xe(e.CreatedDate,r.WTF),{"xsi:type":"dcterms:W3CDTF"},n,a),null!=e.ModifiedDate&&Yt("dcterms:modified","string"==typeof e.ModifiedDate?e.ModifiedDate:Xe(e.ModifiedDate,r.WTF),{"xsi:type":"dcterms:W3CDTF"},n,a));for(var i=0;i!=qt.length;++i){var o=qt[i],s=r.Props&&null!=r.Props[o[1]]?r.Props[o[1]]:e?e[o[1]]:null;!0===s?s="1":!1===s?s="0":"number"==typeof s&&(s=String(s)),null!=s&&Yt(o[0],s,null,n,a)}return n.length>2&&(n[n.length]="",n[1]=n[1].replace("/>",">")),n.join("")}(e.Props,t)),i.coreprops.push(f),Jt(t.rels,2,f,Vt.CORE_PROPS),f="docProps/app.xml",e.Props&&e.Props.SheetNames);else if(e.Workbook&&e.Workbook.Sheets){for(var u=[],p=0;pWorksheets")+l("vt:variant",l("vt:i4",String(o.Worksheets))),{size:2,baseType:"variant"})),s[s.length]=l("TitlesOfParts",l("vt:vector",o.SheetNames.map((function(e){return""+Ee(e)+""})).join(""),{size:o.Worksheets,baseType:"lpstr"})),s.length>2&&(s[s.length]="",s[1]=s[1].replace("/>",">")),s.join(""))),i.extprops.push(f),Jt(t.rels,3,f,Vt.EXT_PROPS),e.Custprops!==e.Props&&ie(e.Custprops||{}).length>0&&(Ae(c,f="docProps/custom.xml",Kt(e.Custprops)),i.custprops.push(f),Jt(t.rels,4,f,Vt.CUST_PROPS));var d,m,g=["SheetJ5"];for(t.tcid=0,h=1;h<=e.SheetNames.length;++h){var v={"!id":{}},b=e.Sheets[e.SheetNames[h-1]];(b||{})["!type"];if(Ae(c,f="xl/worksheets/sheet"+h+"."+n,gr(h-1,t,e,v)),i.sheets.push(f),Jt(t.wbrels,-1,"worksheets/sheet"+h+"."+n,Vt.WS[0]),b){var x=b["!comments"],w=!1,y="";if(x&&x.length>0){var C=!1;x.forEach((function(e){e[1].forEach((function(e){1==e.T&&(C=!0)}))})),C&&(Ae(c,y="xl/threadedComments/threadedComment"+h+".xml",or(x,g,t)),i.threadedcomments.push(y),Jt(v,-1,"../threadedComments/threadedComment"+h+".xml",Vt.TCMNT)),Ae(c,y="xl/comments"+h+"."+n,ir(x)),i.comments.push(y),Jt(v,-1,"../comments"+h+"."+n,Vt.CMNT),w=!0}b["!legacy"]&&w&&Ae(c,"xl/drawings/vmlDrawing"+h+".vml",ar(h,b["!comments"])),delete b["!comments"],delete b["!legacy"]}v["!id"].rId1&&Ae(c,(m=void 0,m=(d=f).lastIndexOf("/"),d.slice(0,m+1)+"_rels/"+d.slice(m+1)+".rels"),Gt(v))}return null!=t.Strings&&t.Strings.length>0&&(Ae(c,f="xl/sharedStrings."+n,function(e,t){if(!t.bookSST)return"";var r=[Te];r[r.length]=He("sst",null,{xmlns:Ge[0],count:e.Count,uniqueCount:e.Unique});for(var n=0;n!=e.length;++n)if(null!=e[n]){var a=e[n],i="";a.r?i+=a.r:(i+=""),i+="",r[r.length]=i}return r.length>2&&(r[r.length]="",r[1]=r[1].replace("/>",">")),r.join("")}(t.Strings,t)),i.strs.push(f),Jt(t.wbrels,-1,"sharedStrings."+n,Vt.SST)),Ae(c,f="xl/workbook."+n,function(e){var t=[Te];t[t.length]=He("workbook",null,{xmlns:Ge[0],"xmlns:r":Ve.r});var r=e.Workbook&&(e.Workbook.Names||[]).length>0,n={codeName:"ThisWorkbook"};e.Workbook&&e.Workbook.WBProps&&(vr.forEach((function(t){null!=e.Workbook.WBProps[t[0]]&&e.Workbook.WBProps[t[0]]!=t[1]&&(n[t[0]]=e.Workbook.WBProps[t[0]])})),e.Workbook.WBProps.CodeName&&(n.codeName=e.Workbook.WBProps.CodeName,delete n.CodeName)),t[t.length]=He("workbookPr",null,n);var a=e.Workbook&&e.Workbook.Sheets||[],i=0;if(a&&a[0]&&a[0].Hidden){for(t[t.length]="",i=0;i!=e.SheetNames.length&&a[i]&&a[i].Hidden;++i);i==e.SheetNames.length&&(i=0),t[t.length]='',t[t.length]=""}for(t[t.length]="",i=0;i!=e.SheetNames.length;++i){var o={name:Ee(e.SheetNames[i].slice(0,31))};if(o.sheetId=""+(i+1),o["r:id"]="rId"+(i+1),a[i])switch(a[i].Hidden){case 1:o.state="hidden";break;case 2:o.state="veryHidden"}t[t.length]=He("sheet",null,o)}return t[t.length]="",r&&(t[t.length]="",e.Workbook&&e.Workbook.Names&&e.Workbook.Names.forEach((function(e){var r={name:e.Name};e.Comment&&(r.comment=e.Comment),null!=e.Sheet&&(r.localSheetId=""+e.Sheet),e.Hidden&&(r.hidden="1"),e.Ref&&(t[t.length]=He("definedName",Ee(e.Ref),r))})),t[t.length]=""),t.length>2&&(t[t.length]="",t[1]=t[1].replace("/>",">")),t.join("")}(e)),i.workbooks.push(f),Jt(t.rels,1,f,Vt.WB),Ae(c,f="xl/theme/theme1.xml",function(e,t){if(t&&t.themeXLSX)return t.themeXLSX;if(e&&"string"==typeof e.raw)return e.raw;var r=[Te];return r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]='',r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]='',r[r.length]="",r[r.length]="",r[r.length]="",r[r.length]="",r.join("")}(e.Themes,t)),i.themes.push(f),Jt(t.wbrels,-1,"theme/theme1.xml",Vt.THEME),Ae(c,f="xl/styles."+n,nr(e,t)),i.styles.push(f),Jt(t.wbrels,-1,"styles."+n,Vt.STY),e.vbaraw&&a&&(Ae(c,f="xl/vbaProject.bin",e.vbaraw),i.vba.push(f),Jt(t.wbrels,-1,"vbaProject.bin",Vt.VBA)),Ae(c,f="xl/metadata."+n,function(){var e=[Te];return e.push('\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n'),e.join("")}()),i.metadata.push(f),Jt(t.wbrels,-1,"metadata."+n,Vt.XLMETA),g.length>1&&(Ae(c,f="xl/persons/person.xml",function(e){var t=[Te,He("personList",null,{xmlns:Ve.TCMNT,"xmlns:x":Ge[0]}).replace(/[\/]>/,">")];return e.forEach((function(e,r){t.push(He("person",null,{displayName:e,id:"{54EE7950-7262-4200-6969-"+("000000000000"+r).slice(-12)+"}",userId:e,providerId:"None"}))})),t.push(""),t.join("")}(g)),i.people.push(f),Jt(t.wbrels,-1,"persons/person.xml",Vt.PEOPLE)),Ae(c,"[Content_Types].xml",Xt(i,t)),Ae(c,"_rels/.rels",Gt(t.rels)),Ae(c,"xl/_rels/workbook.xml.rels",Gt(t.wbrels)),delete t.revssf,delete t.ssf,c}function Tr(e,t){var r=ge(t||{});return function(e,t){var r={},n=a?"nodebuffer":"undefined"!=typeof Uint8Array?"array":"string";t.compression&&(r.compression="DEFLATE");if(t.password)r.type=n;else switch(t.type){case"base64":r.type="base64";break;case"binary":r.type="string";break;case"string":throw new Error("'string' output type invalid for '"+t.bookType+"' files");case"buffer":case"file":r.type=n;break;default:throw new Error("Unrecognized type "+t.type)}var i=e.FullPaths?re.write(e,{fileType:"zip",type:{nodebuffer:"buffer",string:"binary"}[r.type]||r.type,compression:!!t.compression}):e.generate(r);if("undefined"!=typeof Deno&&"string"==typeof i){if("binary"==t.type||"base64"==t.type)return i;i=new Uint8Array(f(i))}return t.password&&"undefined"!=typeof encrypt_agile?function(e,t){switch(t.type){case"base64":case"binary":break;case"buffer":case"array":t.type="";break;case"file":return ae(t.file,re.write(e,{type:a?"buffer":""}));case"string":throw new Error("'string' output type invalid for '"+t.bookType+"' files");default:throw new Error("Unrecognized type "+t.type)}return re.write(e,t)}(encrypt_agile(i,t.password),t):"file"===t.type?ae(t.file,i):"string"==t.type?Ue(i):i}(Ar(e,r),r)}function Dr(e,t){wr(e);var r=ge(t||{});if(r.cellStyles&&(r.cellNF=!0,r.sheetStubs=!0),"array"==r.type){r.type="binary";var n=Dr(e,r);return r.type="array",f(n)}return Tr(e,r)}function Or(e,t,r){var n=r||{};return n.type="file",n.file=t,function(e){if(!e.bookType){var t=e.file.slice(e.file.lastIndexOf(".")).toLowerCase();t.match(/^\.[a-z]+$/)&&(e.bookType=t.slice(1)),e.bookType={xls:"biff8",htm:"html",slk:"sylk",socialcalc:"eth",Sh33tJS:"WTF"}[e.bookType]||e.bookType}}(n),Dr(e,n)}function Fr(e,t,r,n,a,i,o){var s,l=Ot(r),c=o.defval,f=o.raw||!Object.prototype.hasOwnProperty.call(o,"raw"),h=!0,u=null!=e["!data"],p=1===a?[]:{};if(1!==a)if(Object.defineProperty)try{Object.defineProperty(p,"__rowNum__",{value:r,enumerable:!1})}catch(e){p.__rowNum__=r}else p.__rowNum__=r;if(!u||e["!data"][r])for(var d=t.s.c;d<=t.e.c;++d){var m=u?(e["!data"][r]||[])[d]:e[n[d]+l];if(null!=m&&void 0!==m.t){var g=m.v;switch(m.t){case"z":if(null==g)break;continue;case"e":g=0==g?null:void 0;break;case"s":case"b":case"n":if(!m.z||!J(m.z))break;if("number"==typeof(g=he(g)))break;case"d":o&&(o.UTC||!1===o.raw)||(s=new Date(g),g=new Date(s.getUTCFullYear(),s.getUTCMonth(),s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds(),s.getUTCMilliseconds()));break;default:throw new Error("unrecognized type "+m.t)}if(null!=i[d]){if(null==g)if("e"==m.t&&null===g)p[i[d]]=null;else if(void 0!==c)p[i[d]]=c;else{if(!f||null!==g)continue;p[i[d]]=null}else p[i[d]]=("n"===m.t&&"boolean"==typeof o.rawNumbers?o.rawNumbers:f)?g:$t(m,g,o);null!=g&&(h=!1)}}else{if(void 0===c)continue;null!=i[d]&&(p[i[d]]=c)}}return{row:p,isempty:h}}function Er(e,t){if(null==e||null==e["!ref"])return[];var r={t:"n",v:0},n=0,a=1,i=[],o=0,s="",l={s:{r:0,c:0},e:{r:0,c:0}},c=t||{},f=null!=c.range?c.range:e["!ref"];switch(1===c.header?n=1:"A"===c.header?n=2:Array.isArray(c.header)?n=3:null==c.header&&(n=0),typeof f){case"string":l=Lt(f);break;case"number":(l=Lt(e["!ref"])).s.r=f;break;default:l=f}n>0&&(a=0);var h=Ot(l.s.r),u=[],p=[],d=0,m=0,g=null!=e["!data"],v=l.s.r,b=0,x={};g&&!e["!data"][v]&&(e["!data"][v]=[]);var w=c.skipHidden&&e["!cols"]||[],y=c.skipHidden&&e["!rows"]||[];for(b=l.s.c;b<=l.e.c;++b)if(!(w[b]||{}).hidden)switch(u[b]=Ft(b),r=g?e["!data"][v][b]:e[u[b]+h],n){case 1:i[b]=b-l.s.c;break;case 2:i[b]=u[b];break;case 3:i[b]=c.header[b-l.s.c];break;default:if(null==r&&(r={w:"__EMPTY",t:"s"}),s=o=$t(r,null,c),m=x[o]||0){do{s=o+"_"+m++}while(x[s]);x[o]=m,x[s]=1}else x[o]=1;i[b]=s}for(v=l.s.r+a;v<=l.e.r;++v)if(!(y[v]||{}).hidden){var C=Fr(e,l,v,u,n,i,c);(!1===C.isempty||(1===n?!1!==c.blankrows:c.blankrows))&&(p[d++]=C.row)}return p.length=d,p}!function(){try{return"undefined"==typeof Uint8Array||void 0===Uint8Array.prototype.subarray?"slice":"undefined"!=typeof Buffer?void 0===Buffer.prototype.subarray?"slice":("function"==typeof Buffer.from?Buffer.from([72,62]):new Buffer([72,62]))instanceof Uint8Array?"subarray":"slice":"subarray"}catch(e){return"slice"}}();var Mr=/"/g;function Nr(e,t,r,n,a,i,o,s,l){for(var c=!0,f=[],h="",u=Ot(r),p=null!=e["!data"],d=p&&e["!data"][r]||[],m=t.s.c;m<=t.e.c;++m)if(n[m]){var g=p?d[m]:e[n[m]+u];if(null==g)h="";else if(null!=g.v){c=!1,h=""+(l.rawNumbers&&"n"==g.t?g.v:$t(g,null,l));for(var v=0,b=0;v!==h.length;++v)if((b=h.charCodeAt(v))===a||b===i||34===b||l.forceQuotes){h='"'+h.replace(Mr,'""')+'"';break}"ID"==h&&0==s&&0==f.length&&(h='"ID"')}else null==g.f||g.F?h="":(c=!1,(h="="+g.f).indexOf(",")>=0&&(h='"'+h.replace(Mr,'""')+'"'));f.push(h)}if(l.strip)for(;""===f[f.length-1];)--f.length;return!1===l.blankrows&&c?null:f.join(o)}function Ir(e,t){var r=[],n=null==t?{}:t;if(null==e||null==e["!ref"])return"";for(var a=Lt(e["!ref"]),i=void 0!==n.FS?n.FS:",",o=i.charCodeAt(0),s=void 0!==n.RS?n.RS:"\n",l=s.charCodeAt(0),c="",f=[],h=n.skipHidden&&e["!cols"]||[],u=n.skipHidden&&e["!rows"]||[],p=a.s.c;p<=a.e.c;++p)(h[p]||{}).hidden||(f[p]=Ft(p));for(var d=0,m=a.s.r;m<=a.e.r;++m)(u[m]||{}).hidden||null!=(c=Nr(e,a,m,f,o,l,i,d,n))&&(c||!1!==n.blankrows)&&r.push((d++?s:"")+c);return r.join("")}function Pr(e,t,r){var n=r||{},a=e?null!=e["!data"]:n.dense,i=+!n.skipHeader,o=e||{};!e&&a&&(o["!data"]=[]);var s=0,l=0;if(o&&null!=n.origin)if("number"==typeof n.origin)s=n.origin;else{var c="string"==typeof n.origin?Et(n.origin):n.origin;s=c.r,l=c.c}var f={s:{c:0,r:0},e:{c:l,r:s+t.length-1+i}};if(o["!ref"]){var h=Lt(o["!ref"]);f.e.c=Math.max(f.e.c,h.e.c),f.e.r=Math.max(f.e.r,h.e.r),-1==s&&(s=h.e.r+1,f.e.r=s+t.length-1+i)}else-1==s&&(s=0,f.e.r=t.length-1+i);var u=n.header||[],p=0,d=[];t.forEach((function(e,t){a&&!o["!data"][s+t+i]&&(o["!data"][s+t+i]=[]),a&&(d=o["!data"][s+t+i]),ie(e).forEach((function(r){-1==(p=u.indexOf(r))&&(u[p=u.length]=r);var c=e[r],f="z",h="",m=a?"":Ft(l+p)+Ot(s+t+i),g=a?d[l+p]:o[m];!c||"object"!=typeof c||c instanceof Date?("number"==typeof c?f="n":"boolean"==typeof c?f="b":"string"==typeof c?f="s":c instanceof Date?(f="d",n.UTC||(c=_e(c)),n.cellDates||(f="n",c=fe(c)),h=null!=g&&g.z&&J(g.z)?g.z:n.dateNF||S[14]):null===c&&n.nullError&&(f="e",c=0),g?(g.t=f,g.v=c,delete g.w,delete g.R,h&&(g.z=h)):a?d[l+p]=g={t:f,v:c}:o[m]=g={t:f,v:c},h&&(g.z=h)):a?d[l+p]=c:o[m]=c}))})),f.e.c=Math.max(f.e.c,l+u.length-1);var m=Ot(s);if(a&&!o["!data"][s]&&(o["!data"][s]=[]),i)for(p=0;p=65535)throw new Error("Too many worksheets");if(n&&e.SheetNames.indexOf(r)>=0&&r.length<32){var i=r.match(/\d+$/);a=i&&+i[0]||0;var o=i&&r.slice(0,i.index)||r;for(++a;a<=65535&&-1!=e.SheetNames.indexOf(r=o+a);++a);}if(xr(r),e.SheetNames.indexOf(r)>=0)throw new Error("Worksheet with name |"+r+"| already exists!");return e.SheetNames.push(r),e.Sheets[r]=t,r}function Ur(e,t,r){return t?(e.l={Target:t},r&&(e.l.Tooltip=r)):delete e.l,e}var $r={encode_col:Ft,encode_row:Ot,encode_cell:Mt,encode_range:It,decode_col:function(e){for(var t=e.replace(/^\$([A-Z])/,"$1"),r=0,n=0;n!==t.length;++n)r=26*r+t.charCodeAt(n)-64;return r-1},decode_row:function(e){return parseInt(e.replace(/\$(\d+)$/,"$1"),10)-1},split_cell:function(e){return e.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(",")},decode_cell:Et,decode_range:Nt,format_cell:$t,sheet_new:function(e){var t={};return(e||{}).dense&&(t["!data"]=[]),t},sheet_add_aoa:zt,sheet_add_json:Pr,sheet_add_dom:Cr,aoa_to_sheet:function(e,t){return zt(null,e,t)},json_to_sheet:function(e,t){return Pr(null,e,t)},table_to_sheet:Sr,table_to_book:function(e,t){return function(e,t){var r=t&&t.sheet?t.sheet:"Sheet1",n={};return n[r]=e,{SheetNames:[r],Sheets:n}}(Sr(e,t),t)},sheet_to_csv:Ir,sheet_to_txt:function(e,t){return t||(t={}),t.FS="\t",t.RS="\n",Ir(e,t)},sheet_to_json:Er,sheet_to_html:function(e,t){var r=t||{},n=null!=r.header?r.header:'SheetJS Table Export',a=null!=r.footer?r.footer:"",i=[n],o=Nt(e["!ref"]||"A1");if(i.push(function(e,t,r){return[].join("")+""}(0,0,r)),e["!ref"])for(var s=o.s.r;s<=o.e.r;++s)i.push(yr(e,o,s,r));return i.push(""+a),i.join("")},sheet_to_formulae:function(e,t){var r,n="",a="";if(null==e||null==e["!ref"])return[];var i,o=Lt(e["!ref"]),s="",l=[],c=[],f=null!=e["!data"];for(i=o.s.c;i<=o.e.c;++i)l[i]=Ft(i);for(var h=o.s.r;h<=o.e.r;++h)for(s=Ot(h),i=o.s.c;i<=o.e.c;++i)if(n=l[i]+s,a="",void 0!==(r=f?(e["!data"][h]||[])[i]:e[n])){if(null!=r.F){if(n=r.F,!r.f)continue;a=r.f,-1==n.indexOf(":")&&(n=n+":"+n)}if(null!=r.f)a=r.f;else{if(t&&!1===t.values)continue;if("z"==r.t)continue;if("n"==r.t&&null!=r.v)a=""+r.v;else if("b"==r.t)a=r.v?"TRUE":"FALSE";else if(void 0!==r.w)a="'"+r.w;else{if(void 0===r.v)continue;a="s"==r.t?"'"+r.v:""+r.v}}c[c.length]=n+"="+a}return c},sheet_to_row_object_array:Er,sheet_get_cell:Rr,book_new:function(e,t){var r={SheetNames:[],Sheets:{}};return e&&Lr(r,e,t||"Sheet1"),r},book_append_sheet:Lr,book_set_sheet_visibility:function(e,t,r){e.Workbook||(e.Workbook={}),e.Workbook.Sheets||(e.Workbook.Sheets=[]);var n=function(e,t){if("number"==typeof t){if(t>=0&&e.SheetNames.length>t)return t;throw new Error("Cannot find sheet # "+t)}if("string"==typeof t){var r=e.SheetNames.indexOf(t);if(r>-1)return r;throw new Error("Cannot find sheet name |"+t+"|")}throw new Error("Cannot find sheet |"+t+"|")}(e,t);switch(e.Workbook.Sheets[n]||(e.Workbook.Sheets[n]={}),r){case 0:case 1:case 2:break;default:throw new Error("Bad sheet visibility setting "+r)}e.Workbook.Sheets[n].Hidden=r},cell_set_number_format:function(e,t){return e.z=t,e},cell_set_hyperlink:Ur,cell_set_internal_link:function(e,t,r){return Ur(e,"#"+t,r)},cell_add_comment:function(e,t,r){e.c||(e.c=[]),e.c.push({t,a:r||"SheetJS"})},sheet_set_array_formula:function(e,t,r,n){for(var a="string"!=typeof t?t:Lt(t),i="string"==typeof t?t:It(t),o=a.s.r;o<=a.e.r;++o)for(var s=a.s.c;s<=a.e.c;++s){var l=Rr(e,o,s);l.t="n",l.F=i,delete l.v,o==a.s.r&&s==a.s.c&&(l.f=r,n&&(l.D=!0))}var c=Nt(e["!ref"]);return c.s.r>a.s.r&&(c.s.r=a.s.r),c.s.c>a.s.c&&(c.s.c=a.s.c),c.e.r} */ diff --git a/Source/javascriptsource/nanoflowcommons/actions/GetPlatform.js b/Source/javascriptsource/nanoflowcommons/actions/GetPlatform.js index 6c55d6b0..20ee30cf 100644 --- a/Source/javascriptsource/nanoflowcommons/actions/GetPlatform.js +++ b/Source/javascriptsource/nanoflowcommons/actions/GetPlatform.js @@ -12,7 +12,7 @@ import { Big } from "big.js"; /** * Get the client platform (NanoflowCommons.Platform) where the action is running. - * @returns {Promise.<"NanoflowCommons.Platform.Web"|"NanoflowCommons.Platform.Native_mobile"|"NanoflowCommons.Platform.Hybrid_mobile">} + * @returns {Promise.} */ export async function GetPlatform() { // BEGIN USER CODE diff --git a/Source/javascriptsource/nanoflowcommons/actions/GetStraightLineDistance.js b/Source/javascriptsource/nanoflowcommons/actions/GetStraightLineDistance.js index f3e2c7e7..0bc2196e 100644 --- a/Source/javascriptsource/nanoflowcommons/actions/GetStraightLineDistance.js +++ b/Source/javascriptsource/nanoflowcommons/actions/GetStraightLineDistance.js @@ -24,7 +24,7 @@ function kmToNauticalMile(km) { * @param {Big} longitudePoint1 * @param {Big} latitudePoint2 * @param {Big} longitudePoint2 - * @param {"NanoflowCommons.Enum_DistanceUnit.KILOMETER"|"NanoflowCommons.Enum_DistanceUnit.STATUTE_MILE"|"NanoflowCommons.Enum_DistanceUnit.NAUTICAL_MILE"} unit + * @param {undefined|"KILOMETER"|"STATUTE_MILE"|"NAUTICAL_MILE"} unit * @returns {Promise.} */ export async function GetStraightLineDistance(latitudePoint1, longitudePoint1, latitudePoint2, longitudePoint2, unit) { diff --git a/Source/javascriptsource/nanoflowcommons/actions/ReverseGeocode.js b/Source/javascriptsource/nanoflowcommons/actions/ReverseGeocode.js index e58da2fc..1cf36243 100644 --- a/Source/javascriptsource/nanoflowcommons/actions/ReverseGeocode.js +++ b/Source/javascriptsource/nanoflowcommons/actions/ReverseGeocode.js @@ -15,7 +15,7 @@ import Geodecoder from 'react-native-geocoder'; * Reverse geocoding is the process of converting geographic coordinates (latitude and longitude) into a human-readable address. * @param {string} latitude - This field is required. * @param {string} longitude - This field is required. - * @param {"NanoflowCommons.GeocodingProvider.Google"|"NanoflowCommons.GeocodingProvider.Geocodio"|"NanoflowCommons.GeocodingProvider.LocationIQ"|"NanoflowCommons.GeocodingProvider.MapQuest"} geocodingProvider - This field is required for use on web. + * @param {undefined|"Google"|"Geocodio"|"LocationIQ"|"MapQuest"} geocodingProvider - This field is required for use on web. * @param {string} providerApiKey - This field is required for use on web. Note that the keys are accessible by the end users and should be protected in other ways; for example restricted domain name. * @returns {Promise.} */ diff --git a/Source/javascriptsource/unittesting/actions/JS_CopyToClipboard.js b/Source/javascriptsource/unittesting/actions/JS_CopyToClipboard.js new file mode 100644 index 00000000..48cab973 --- /dev/null +++ b/Source/javascriptsource/unittesting/actions/JS_CopyToClipboard.js @@ -0,0 +1,22 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +import "mx-global"; +import { Big } from "big.js"; + +// BEGIN EXTRA CODE +// END EXTRA CODE + +/** + * @param {string} text + * @returns {Promise.} + */ +export async function JS_CopyToClipboard(text) { + // BEGIN USER CODE + navigator.clipboard.writeText(text); + // END USER CODE +} diff --git a/Source/javasource/communitycommons/Misc.java b/Source/javasource/communitycommons/Misc.java index 054ee2fb..2a1f4ec9 100644 --- a/Source/javasource/communitycommons/Misc.java +++ b/Source/javasource/communitycommons/Misc.java @@ -1,736 +1,744 @@ -package communitycommons; - -import com.mendix.core.Core; -import com.mendix.core.CoreException; -import com.mendix.core.conf.RuntimeVersion; -import com.mendix.core.objectmanagement.member.MendixBoolean; -import com.mendix.integration.WebserviceException; -import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.systemwideinterfaces.core.ISession; -import com.mendix.systemwideinterfaces.core.IUser; -import communitycommons.proxies.LogNodes; -import static communitycommons.proxies.constants.Constants.getMergeMultiplePdfs_MaxAtOnce; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLConnection; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Collectors; -import org.apache.commons.io.IOUtils; -import org.apache.pdfbox.multipdf.Overlay; -import org.apache.pdfbox.multipdf.PDFMergerUtility; -import org.apache.pdfbox.pdmodel.PDDocument; -import system.proxies.FileDocument; -import system.proxies.Language; - -public class Misc { - - private static final String LOGNODE = LogNodes.CommunityCommons.name(); - private static boolean UNDER_TEST = false; - - static { - try { - // if this succeeds, we have a runtime - Logging.createLogNode(LOGNODE); - } catch (NullPointerException npe) { - UNDER_TEST = true; - } - } - - public abstract static class IterateCallback { - - boolean start = false; - boolean stop = false; - private Iterator mapIter; - - public abstract void hit(T1 key, T2 value) throws Exception; - - public void exit() { - stop = true; - } - - public void remove() { - mapIter.remove(); - } - - synchronized void runOn(Map map) throws Exception { - if (start) { - throw new IllegalMonitorStateException(); - } - start = true; - - try { - this.mapIter = map.keySet().iterator(); - - while (mapIter.hasNext()) { - T1 key = mapIter.next(); - T2 value = map.get(key); - - hit(key, value); - - if (stop) { - break; - } - } - } finally { - //reset state to allow reuse, even when exceptions occur - mapIter = null; - stop = false; - start = false; - } - } - } - - /** - * - * @param Any Java enumeration, such as a proxy class for a Mendix enumeration - * @param enumClass For instance: LogLevel.class - * @param value The value to look up in the enumeration - * @return An Optional of the requested enumeration. Will have the requested value if found, - * Optional.empty() otherwise. - */ - public static > Optional enumFromString(final Class enumClass, final String value) { - try { - if (value != null) { - return Optional.of(E.valueOf(enumClass, value)); - } - } catch (IllegalArgumentException iae) { - if (!UNDER_TEST) { - Logging.warn(LOGNODE, String.format("No enumeration with value %s found", value)); - } - } - return Optional.empty(); - } - - /** - * Because you cannot remove items from a map while iteration, this function is introduced. In - * the callback, you can use this.remove() or this.exit() to either remove or break the loop. - * Use return; to continue - * - * @throws Exception - */ - public static void iterateMap(Map map, IterateCallback callback) throws Exception { - //http://marxsoftware.blogspot.com/2008/04/removing-entry-from-java-map-during.html - if (map == null || callback == null) { - throw new IllegalArgumentException(); - } - - callback.runOn(map); - } - - public static String getApplicationURL() { - final String applicationURL = UNDER_TEST ? "http://localhost:8080/" : Core.getConfiguration().getApplicationRootUrl(); - return StringUtils.removeEnd(applicationURL, "/"); - } - - public static String getRuntimeVersion() { - RuntimeVersion runtimeVersion = RuntimeVersion.getInstance(); - return runtimeVersion.toString(); - } - - public static String getModelVersion() { - return Core.getModelVersion(); - } - - public static void throwException(String message) throws UserThrownException { - throw new UserThrownException(message); - } - - public static void throwWebserviceException(String faultstring) throws WebserviceException { - throw new WebserviceException(WebserviceException.clientFaultCode, faultstring); - } - - public static String retrieveURL(String url, String postdata) throws Exception { - // Send data, appname - URLConnection conn = new URL(url).openConnection(); - - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - - if (postdata != null) { - try ( - OutputStream os = conn.getOutputStream()) { - IOUtils.copy(new ByteArrayInputStream(postdata.getBytes(StandardCharsets.UTF_8)), os); - } - } - - String result; - try ( - InputStream is = conn.getInputStream()) { - // Get the response - result = IOUtils.toString(is, StandardCharsets.UTF_8); - } - - return result; - } - - public static Boolean duplicateFileDocument(IContext context, IMendixObject toClone, IMendixObject target) throws Exception { - if (toClone == null || target == null) { - throw new Exception("No file to clone or to clone into provided"); - } - - MendixBoolean hasContents = (MendixBoolean) toClone.getMember(context, FileDocument.MemberNames.HasContents.toString()); - if (!hasContents.getValue(context)) { - return false; - } - - try ( - InputStream inputStream = Core.getFileDocumentContent(context, toClone)) { - Core.storeFileDocumentContent(context, target, (String) toClone.getValue(context, system.proxies.FileDocument.MemberNames.Name.toString()), inputStream); - } - - return true; - } - - public static Boolean duplicateImage(IContext context, IMendixObject toClone, IMendixObject target, int thumbWidth, int thumbHeight) throws Exception { - if (toClone == null || target == null) { - throw new Exception("No file to clone or to clone into provided"); - } - - MendixBoolean hasContents = (MendixBoolean) toClone.getMember(context, FileDocument.MemberNames.HasContents.toString()); - if (!hasContents.getValue(context)) { - return false; - } - - try ( - InputStream inputStream = Core.getImage(context, toClone, false)) { - Core.storeImageDocumentContent(context, target, inputStream, thumbWidth, thumbHeight); - - } - - return true; - } - - public static Boolean storeURLToFileDocument(IContext context, String url, IMendixObject __document, String filename) throws IOException { - if (__document == null || url == null || filename == null) { - throw new IllegalArgumentException("No document, filename or URL provided"); - } - - final int MAX_REMOTE_FILESIZE = 1024 * 1024 * 200; //maximum of 200 MB - try { - URL imageUrl = new URL(url); - URLConnection connection = imageUrl.openConnection(); - //we connect in 20 seconds or not at all - connection.setConnectTimeout(20000); - connection.setReadTimeout(20000); - connection.connect(); - - int contentLength = connection.getContentLength(); - - //check on forehand the size of the remote file, we don't want to kill the server by providing a 3 terabyte image. - Logging.trace(LOGNODE, String.format("Remote filesize: %d", contentLength)); - - if (contentLength > MAX_REMOTE_FILESIZE) { //maximum of 200 mb - throw new IllegalArgumentException(String.format("Wrong filesize of remote url: %d (max: %d)", contentLength, MAX_REMOTE_FILESIZE)); - } - - InputStream fileContentIS; - try (InputStream connectionInputStream = connection.getInputStream()) { - if (contentLength >= 0) { - fileContentIS = connectionInputStream; - } else { // contentLength is negative or unknown - Logging.trace(LOGNODE, String.format("Unknown content length; limiting to %d", MAX_REMOTE_FILESIZE)); - byte[] outBytes = new byte[MAX_REMOTE_FILESIZE]; - int actualLength = IOUtils.read(connectionInputStream, outBytes, 0, MAX_REMOTE_FILESIZE); - fileContentIS = new ByteArrayInputStream(Arrays.copyOf(outBytes, actualLength)); - } - Core.storeFileDocumentContent(context, __document, filename, fileContentIS); - } - } catch (IOException ioe) { - Logging.error(LOGNODE, String.format("A problem occurred while reading from URL %s: %s", url, ioe.getMessage())); - throw ioe; - } - - return true; - } - - public static Long getFileSize(IContext context, IMendixObject document) { - final int BUFFER_SIZE = 4096; - long size = 0; - - if (context != null) { - byte[] buffer = new byte[BUFFER_SIZE]; - - try ( - InputStream inputStream = Core.getFileDocumentContent(context, document)) { - int i; - while ((i = inputStream.read(buffer)) != -1) { - size += i; - } - } catch (IOException e) { - Logging.error(LOGNODE, "Couldn't determine filesize of FileDocument '" + document.getId()); - } - } - - return size; - } - - public static void delay(long delaytime) throws InterruptedException { - Thread.sleep(delaytime); - } - - public static IContext getContextFor(IContext context, String username, boolean sudoContext) { - if (username == null || username.isEmpty()) { - throw new RuntimeException("Assertion: No username provided"); - } - - if (username.equals(context.getSession().getUserName())) { - return context; - } else { // when it is a scheduled event, then get the right session. - ISession session = getSessionFor(context, username); - - IContext c = session.createContext(); - if (sudoContext) { - return c.createSudoClone(); - } - - return c; - } - } - - private static ISession getSessionFor(IContext context, String username) { - ISession session = Core.getActiveSession(username); - - if (session == null) { - IContext newContext = context.getSession().createContext().createSudoClone(); - newContext.startTransaction(); - try { - session = initializeSessionForUser(newContext, username); - } catch (CoreException e) { - newContext.rollbackTransaction(); - - throw new RuntimeException("Failed to initialize session for user: " + username + ": " + e.getMessage(), e); - } finally { - newContext.endTransaction(); - } - } - - return session; - } - - private static ISession initializeSessionForUser(IContext context, String username) throws CoreException { - IUser user = Core.getUser(context, username); - - if (user == null) { - throw new RuntimeException("Assertion: user with username '" + username + "' does not exist"); - } - - return Core.initializeSession(user, null); - } - - public static Object executeMicroflowAsUser(IContext context, - String microflowName, String username, Boolean sudoContext, Object... args) throws Exception { - - if (context == null) { - throw new Exception("Assertion: No context provided"); - } - if (microflowName == null || microflowName.isEmpty()) { - throw new Exception("Assertion: No context provided"); - } - if (!Core.getMicroflowNames().contains(microflowName)) { - throw new Exception("Assertion: microflow not found: " + microflowName); - } - if (args.length % 2 != 0) { - throw new Exception("Assertion: odd number of dynamic arguments provided, please name every argument: " + args.length); - } - - Map params = new LinkedHashMap(); - for (int i = 0; i < args.length; i += 2) { - if (args[i] != null) { - params.put(args[i].toString(), args[i + 1]); - } - } - - IContext c = getContextFor(context, username, sudoContext); - - return Core.microflowCall(microflowName).withParams(params).execute(c); - } - - //MWE: based on: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executor.html - static class MFSerialExecutor { - - private static MFSerialExecutor _instance = new MFSerialExecutor(); - - private final AtomicLong tasknr = new AtomicLong(); - private final ExecutorService executor; - - public static MFSerialExecutor instance() { - return _instance; - } - - private MFSerialExecutor() { - executor = Executors.newSingleThreadExecutor(new ThreadFactory() { - - //Default thread factory takes care of setting the proper thread context - private final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); - - @Override - public Thread newThread(Runnable runnable) { - Thread t = defaultFactory.newThread(runnable); - t.setPriority(Thread.MIN_PRIORITY); - t.setName("CommunityCommons background pool executor thread"); - return t; - } - - }); - } - - public void execute(final Runnable command) { - if (command == null) { - throw new NullPointerException("command"); - } - - final long currenttasknr = tasknr.incrementAndGet(); - Logging.debug(LOGNODE, "[RunMicroflowAsyncInQueue] Scheduling task #" + currenttasknr); - - executor.submit(new Runnable() { - @Override - public void run() { - Logging.debug(LOGNODE, "[RunMicroflowAsyncInQueue] Running task #" + currenttasknr); - try { - command.run(); - } catch (RuntimeException e) { - Logging.error(LOGNODE, "[RunMicroflowAsyncInQueue] Execution of task #" + currenttasknr + " failed: " + e.getMessage(), e); - throw e; //single thread executor will continue, even if an exception is thrown. - } - Logging.debug(LOGNODE, "[RunMicroflowAsyncInQueue] Completed task #" + currenttasknr + ". Tasks left: " + (tasknr.get() - currenttasknr)); - } - }); - } - } - - public static Boolean runMicroflowAsyncInQueue(final String microflowName) { - MFSerialExecutor.instance().execute(new Runnable() { - @Override - public void run() { - try { - Future future = Core.executeAsync(Core.createSystemContext(), microflowName, true, new HashMap<>()); //MWE: somehow, it only works with system context... well thats OK for now. - future.get(); - } catch (CoreException | InterruptedException | ExecutionException e) { - throw new RuntimeException("Failed to run Async: " + microflowName + ": " + e.getMessage(), e); - } - } - }); - return true; - } - - public static Boolean runMicroflowInBackground(final IContext context, final String microflowName, - final IMendixObject paramObject) { - - MFSerialExecutor.instance().execute(new Runnable() { - - @Override - public void run() { - try { - IContext c = Core.createSystemContext(); - if (paramObject != null) { - Core.executeAsync(c, microflowName, true, paramObject).get(); //MWE: somehow, it only works with system context... well thats OK for now. - } else { - Core.executeAsync(c, microflowName, true, new HashMap<>()).get(); //MWE: somehow, it only works with system context... well thats OK for now. - } - } catch (CoreException | InterruptedException | ExecutionException e) { - throw new RuntimeException("Failed to run Async: " + microflowName + ": " + e.getMessage(), e); - } - - } - - }); - return true; - } - - private interface IBatchItemHandler { - - void exec(IContext context, IMendixObject obj) throws Exception; - - } - - private static class BatchState { - - private int state = 0; //-1 = error, 1 = done. - private final IBatchItemHandler callback; - - public BatchState(IBatchItemHandler callback) { - this.callback = callback; - } - - public void setState(int state) { - this.state = state; - } - - public int getState() { - return state; - } - - public void handle(IContext context, IMendixObject obj) throws Exception { - callback.exec(context, obj); - } - } - - public static Boolean executeMicroflowInBatches(String xpath, final String microflow, int batchsize, boolean waitUntilFinished, boolean asc) throws CoreException, InterruptedException { - Logging.debug(LOGNODE, "[ExecuteInBatches] Starting microflow batch '" + microflow + "..."); - - return executeInBatches(xpath, new BatchState(new IBatchItemHandler() { - - @Override - public void exec(IContext context, IMendixObject obj) throws Exception { - Core.executeAsync(context, microflow, true, obj).get(); - } - - }), batchsize, waitUntilFinished, asc); - } - - public static Boolean recommitInBatches(String xpath, int batchsize, - boolean waitUntilFinished, Boolean asc) throws CoreException, InterruptedException { - Logging.debug(LOGNODE, "[ExecuteInBatches] Starting recommit batch..."); - - return executeInBatches(xpath, new BatchState(new IBatchItemHandler() { - - @Override - public void exec(IContext context, IMendixObject obj) throws Exception { - Core.commit(context, obj); - } - - }), batchsize, waitUntilFinished, asc); - } - - public static Boolean executeInBatches(String xpathRaw, BatchState batchState, int batchsize, boolean waitUntilFinished, boolean asc) throws CoreException, InterruptedException { - String xpath = xpathRaw.startsWith("//") ? xpathRaw : "//" + xpathRaw; - - long count = Core.retrieveXPathQueryAggregate(Core.createSystemContext(), "count(" + xpath + ")"); - int loop = (int) Math.ceil(((float) count) / ((float) batchsize)); - - Logging.debug(LOGNODE, - "[ExecuteInBatches] Starting batch on ~ " + count + " objects divided over ~ " + loop + " batches. " - + (waitUntilFinished ? "Waiting until the batch has finished..." : "") - ); - - executeInBatchesHelper(xpath, batchsize, 0, batchState, count, asc); - - if (waitUntilFinished) { - while (batchState.getState() == 0) { - Thread.sleep(5000); - } - if (batchState.getState() == 1) { - Logging.debug(LOGNODE, "[ExecuteInBatches] Successfully finished batch"); - return true; - } - Logging.error(LOGNODE, "[ExecuteInBatches] Failed to finish batch. Please check the application log for more details."); - return false; - } - - return true; - } - - static void executeInBatchesHelper(final String xpath, final int batchsize, final long last, final BatchState batchState, final long count, final boolean asc) { - MFSerialExecutor.instance().execute(new Runnable() { - - @Override - public void run() { - try { - Thread.sleep(200); - IContext c = Core.createSystemContext(); - - List objects = Core.retrieveXPathQuery(c, xpath + (last > 0 ? "[id " + (asc ? "> " : "< ") + last + "]" : ""), - batchsize, - 0, - new HashMap() { - { - put("id", asc ? "asc" : "desc"); - } - } - ); - - //no new objects found :) - if (objects.isEmpty()) { - Logging.debug(LOGNODE, "[ExecuteInBatches] Succesfully finished batch on ~" + count + " objects."); - batchState.setState(1); - } else { - - //process objects - for (IMendixObject obj : objects) { - batchState.handle(c, obj); - } - - //invoke next batch - executeInBatchesHelper(xpath, batchsize, objects.get(objects.size() - 1).getId().toLong(), batchState, count, asc); - } - } catch (Exception e) { - batchState.setState(-1); - throw new RuntimeException("[ExecuteInBatches] Failed to run in batch: " + e.getMessage(), e); - } - } - - }); - } - - /** - * Tests if two objects are equal with throwing unecessary null pointer exceptions. - * - * This is almost the most stupid function ever, since it should be part of Java itself. - * - * @param left - * @param right - * @return - * @deprecated Native Java function Objects.equals() is available since Java 7 - */ - @Deprecated - public static boolean objectsAreEqual(Object left, Object right) { - if (left == null && right == null) { - return true; - } - if (left == null || right == null) { - return false; - } - return left.equals(right); - } - - /** - * Get the default language - * - * @param context - * @return The default language - * @throws CoreException - */ - public static Language getDefaultLanguage(IContext context) throws CoreException { - String languageCode = Core.getDefaultLanguage().getCode(); - List languageList = Language.load(context, "[Code = '" + languageCode + "']"); - if (languageList == null || languageList.isEmpty()) { - throw new RuntimeException("No language found for default language constant value " + languageCode); - } - return languageList.get(0); - } - - public static boolean mergePDF(IContext context, List documents, IMendixObject mergedDocument) throws IOException { - if (getMergeMultiplePdfs_MaxAtOnce() <= 0 || documents.size() <= getMergeMultiplePdfs_MaxAtOnce()) { - - List sources = new ArrayList<>(); - try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { - PDFMergerUtility mergePdf = new PDFMergerUtility(); - - for (FileDocument file : documents) { - InputStream content = Core.getFileDocumentContent(context, file.getMendixObject()); - sources.add(content); - } - mergePdf.addSources(sources); - mergePdf.setDestinationStream(out); - mergePdf.mergeDocuments(null); - - Core.storeFileDocumentContent(context, mergedDocument, new ByteArrayInputStream(out.toByteArray())); - - out.reset(); - documents.clear(); - } catch (IOException e) { - throw new RuntimeException("Failed to merge documents" + e.getMessage(), e); - } finally { // We cannot use try-with-resources because streams would be prematurely closed - for (InputStream is : sources) { - is.close(); - } - } - - return true; - } else { - throw new IllegalArgumentException("MergeMultiplePDFs: you cannot merge more than " + getMergeMultiplePdfs_MaxAtOnce() - + " PDF files at once. You are trying to merge " + documents.size() + " PDF files."); - } - } - - /** - * Overlay a generated PDF document with another PDF (containing the company stationary for - * example) - * - * @param context - * @param generatedDocumentMendixObject The document to overlay - * @param overlayMendixObject The document containing the overlay - * @param onTopOfContent if true, puts overlay position in the foreground, otherwise in the - * background - * @return boolean - * @throws IOException - */ - public static boolean overlayPdf(IContext context, IMendixObject generatedDocumentMendixObject, IMendixObject overlayMendixObject, boolean onTopOfContent) throws IOException { - Logging.trace(LOGNODE, "Retrieve generated document"); - try ( - PDDocument inputDoc = PDDocument.load(Core.getFileDocumentContent(context, generatedDocumentMendixObject)); - PDDocument overlayDoc = PDDocument.load(Core.getFileDocumentContent(context, overlayMendixObject)); - ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - Logging.trace(LOGNODE, "Overlay PDF start, retrieve overlay PDF"); - - Logging.trace(LOGNODE, "Perform overlay"); - Overlay overlay = new Overlay(); - overlay.setInputPDF(inputDoc); - overlay.setDefaultOverlayPDF(overlayDoc); - if (onTopOfContent == true) { - overlay.setOverlayPosition(Overlay.Position.FOREGROUND); - } else { - overlay.setOverlayPosition(Overlay.Position.BACKGROUND); - } - - Logging.trace(LOGNODE, "Save result in output stream"); - - overlay.overlay(new HashMap<>()).save(baos); - - Logging.trace(LOGNODE, "Duplicate result in input stream"); - try (InputStream overlayedContent = new ByteArrayInputStream(baos.toByteArray())) { - Logging.trace(LOGNODE, "Store result in original document"); - Core.storeFileDocumentContent(context, generatedDocumentMendixObject, overlayedContent); - } - } - - Logging.trace(LOGNODE, "Overlay PDF end"); - return true; - } - - /** - * Get the Cloud Foundry Instance Index (0 for leader and >0 for slave) - * - * @return CF_INSTANCE_INDEX environment variable if available, otherwise -1 - */ - public static long getCFInstanceIndex() { - long cfInstanceIndex = -1L; - - try { - cfInstanceIndex = Long.parseLong(System.getenv("CF_INSTANCE_INDEX")); - } catch (SecurityException securityException) { - Logging.info(LOGNODE, "GetCFInstanceIndex: Could not access environment variable CF_INSTANCE_INDEX, permission denied. Value of -1 is returned."); - } catch (NumberFormatException numberFormatException) { - Logging.info(LOGNODE, "GetCFInstanceIndex: Could not parse value of environment variable CF_INSTANCE_INDEX as Long. Value of -1 is returned."); - } catch (NullPointerException nullPointerException) { - Logging.info(LOGNODE, "GetCFInstanceIndex: Could not find value for environment variable CF_INSTANCE_INDEX. This could indicate a local deployment is running. Value of -1 is returned."); - } - - return cfInstanceIndex; - } - - /** - * Returns the top n items of a List - * - * @param the type of the list elements - * @param objects the list to take the top n items from - * @param top the number of items to take - * @return the sublist of
objects
with max - *
top
elements - */ - public static List listTop(List objects, int top) { - return objects.stream() - .limit(top) - .collect(Collectors.toList()); - } -} +package communitycommons; + +import com.mendix.core.Core; +import com.mendix.core.CoreException; +import com.mendix.core.objectmanagement.member.MendixBoolean; +import com.mendix.integration.WebserviceException; +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.ISession; +import com.mendix.systemwideinterfaces.core.IUser; +import communitycommons.proxies.LogNodes; +import static communitycommons.proxies.constants.Constants.getMergeMultiplePdfs_MaxAtOnce; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; +import org.apache.commons.io.IOUtils; +import org.apache.pdfbox.multipdf.Overlay; +import org.apache.pdfbox.multipdf.PDFMergerUtility; +import org.apache.pdfbox.pdmodel.PDDocument; +import system.proxies.FileDocument; +import system.proxies.Language; + +public class Misc { + + private static final String LOGNODE = LogNodes.CommunityCommons.name(); + private static boolean UNDER_TEST = false; + + static { + try { + // if this succeeds, we have a runtime + Logging.createLogNode(LOGNODE); + } catch (NullPointerException npe) { + UNDER_TEST = true; + } + } + + public abstract static class IterateCallback { + + boolean start = false; + boolean stop = false; + private Iterator mapIter; + + public abstract void hit(T1 key, T2 value) throws Exception; + + synchronized public void exit() { + stop = true; + } + + synchronized public void remove() { + mapIter.remove(); + } + + synchronized void runOn(Map map) throws Exception { + if (start) { + throw new IllegalMonitorStateException(); + } + start = true; + + try { + this.mapIter = map.keySet().iterator(); + + while (mapIter.hasNext()) { + T1 key = mapIter.next(); + T2 value = map.get(key); + + hit(key, value); + + if (stop) { + break; + } + } + } finally { + //reset state to allow reuse, even when exceptions occur + mapIter = null; + stop = false; + start = false; + } + } + } + + /** + * + * @param Any Java enumeration, such as a proxy class for a Mendix enumeration + * @param enumClass For instance: LogLevel.class + * @param value The value to look up in the enumeration + * @return An Optional of the requested enumeration. Will have the requested value if found, + * Optional.empty() otherwise. + */ + public static > Optional enumFromString(final Class enumClass, final String value) { + try { + if (value != null) { + return Optional.of(E.valueOf(enumClass, value)); + } + } catch (IllegalArgumentException iae) { + if (!UNDER_TEST) { + Logging.warn(LOGNODE, String.format("No enumeration with value %s found", value)); + } + } + return Optional.empty(); + } + + /** + * Because you cannot remove items from a map while iteration, this function is introduced. In + * the callback, you can use this.remove() or this.exit() to either remove or break the loop. + * Use return; to continue + * + * @throws Exception + */ + public static void iterateMap(Map map, IterateCallback callback) throws Exception { + //http://marxsoftware.blogspot.com/2008/04/removing-entry-from-java-map-during.html + if (map == null || callback == null) { + throw new IllegalArgumentException(); + } + + callback.runOn(map); + } + + public static String getApplicationURL() { + final String applicationURL = UNDER_TEST ? "http://localhost:8080/" : Core.getConfiguration().getApplicationRootUrl(); + return StringUtils.removeEnd(applicationURL, "/"); + } + + /** + * @return the runtime version + * @deprecated since 11.0.0. Use {@link com.mendix.core.Core.getRuntimeVersion} instead + */ + @Deprecated + public static String getRuntimeVersion() { + return Core.getRuntimeVersion(); + } + + /** + * @return the model version + * @deprecated since 11.0.0. Use {@link com.mendix.core.Core.getModelVersion} instead + */ + @Deprecated + public static String getModelVersion() { + return Core.getModelVersion(); + } + + public static void throwException(String message) throws UserThrownException { + throw new UserThrownException(message); + } + + public static void throwWebserviceException(String faultstring) throws WebserviceException { + throw new WebserviceException(WebserviceException.clientFaultCode, faultstring); + } + + public static String retrieveURL(String url, String postdata) throws Exception { + // Send data, appname + URLConnection conn = new URI(url).toURL().openConnection(); + + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + + if (postdata != null) { + try ( + OutputStream os = conn.getOutputStream()) { + IOUtils.copy(new ByteArrayInputStream(postdata.getBytes(StandardCharsets.UTF_8)), os); + } + } + + String result; + try ( + InputStream is = conn.getInputStream()) { + // Get the response + result = IOUtils.toString(is, StandardCharsets.UTF_8); + } + + return result; + } + + public static Boolean duplicateFileDocument(IContext context, IMendixObject toClone, IMendixObject target) throws Exception { + if (toClone == null || target == null) { + throw new Exception("No file to clone or to clone into provided"); + } + + MendixBoolean hasContents = (MendixBoolean) toClone.getMember(FileDocument.MemberNames.HasContents.toString()); + if (!hasContents.getValue(context)) { + return false; + } + + try ( + InputStream inputStream = Core.getFileDocumentContent(context, toClone)) { + Core.storeFileDocumentContent(context, target, (String) toClone.getValue(context, system.proxies.FileDocument.MemberNames.Name.toString()), inputStream); + } + + return true; + } + + public static Boolean duplicateImage(IContext context, IMendixObject toClone, IMendixObject target, int thumbWidth, int thumbHeight) throws Exception { + if (toClone == null || target == null) { + throw new Exception("No file to clone or to clone into provided"); + } + + MendixBoolean hasContents = (MendixBoolean) toClone.getMember(FileDocument.MemberNames.HasContents.toString()); + if (!hasContents.getValue(context)) { + return false; + } + + try ( + InputStream inputStream = Core.getImage(context, toClone, false)) { + Core.storeImageDocumentContent(context, target, inputStream, thumbWidth, thumbHeight); + + } + + return true; + } + + public static Boolean storeURLToFileDocument(IContext context, String url, IMendixObject __document, String filename) throws IOException, URISyntaxException { + if (__document == null || url == null || filename == null) { + throw new IllegalArgumentException("No document, filename or URL provided"); + } + + final int MAX_REMOTE_FILESIZE = 1024 * 1024 * 200; //maximum of 200 MB + try { + URL imageUrl = new URI(url).toURL(); + URLConnection connection = imageUrl.openConnection(); + //we connect in 20 seconds or not at all + connection.setConnectTimeout(20000); + connection.setReadTimeout(20000); + connection.connect(); + + int contentLength = connection.getContentLength(); + + //check on forehand the size of the remote file, we don't want to kill the server by providing a 3 terabyte image. + Logging.trace(LOGNODE, String.format("Remote filesize: %d", contentLength)); + + if (contentLength > MAX_REMOTE_FILESIZE) { //maximum of 200 mb + throw new IllegalArgumentException(String.format("Wrong filesize of remote url: %d (max: %d)", contentLength, MAX_REMOTE_FILESIZE)); + } + + InputStream fileContentIS; + try (InputStream connectionInputStream = connection.getInputStream()) { + if (contentLength >= 0) { + fileContentIS = connectionInputStream; + } else { // contentLength is negative or unknown + Logging.trace(LOGNODE, String.format("Unknown content length; limiting to %d", MAX_REMOTE_FILESIZE)); + byte[] outBytes = new byte[MAX_REMOTE_FILESIZE]; + int actualLength = IOUtils.read(connectionInputStream, outBytes, 0, MAX_REMOTE_FILESIZE); + fileContentIS = new ByteArrayInputStream(Arrays.copyOf(outBytes, actualLength)); + } + Core.storeFileDocumentContent(context, __document, filename, fileContentIS); + } + } catch (IOException | URISyntaxException e) { + Logging.error(LOGNODE, String.format("A problem occurred while reading from URL %s: %s", url, e.getMessage())); + throw e; + } + + return true; + } + + public static Long getFileSize(IContext context, IMendixObject document) { + final int BUFFER_SIZE = 4096; + long size = 0; + + if (context != null) { + byte[] buffer = new byte[BUFFER_SIZE]; + + try ( + InputStream inputStream = Core.getFileDocumentContent(context, document)) { + int i; + while ((i = inputStream.read(buffer)) != -1) { + size += i; + } + } catch (IOException e) { + Logging.error(LOGNODE, "Couldn't determine filesize of FileDocument '" + document.getId()); + } + } + + return size; + } + + public static void delay(long delaytime) throws InterruptedException { + Thread.sleep(delaytime); + } + + public static IContext getContextFor(IContext context, String username, boolean sudoContext) { + if (username == null || username.isEmpty()) { + throw new RuntimeException("Assertion: No username provided"); + } + + if (username.equals(context.getSession().getUserName())) { + return context; + } else { // when it is a scheduled event, then get the right session. + ISession session = getSessionFor(context, username); + + IContext c = session.createContext(); + if (sudoContext) { + return c.createSudoClone(); + } + + return c; + } + } + + private static ISession getSessionFor(IContext context, String username) { + ISession session = Core.getActiveSession(username); + + if (session == null) { + IContext newContext = context.getSession().createContext().createSudoClone(); + newContext.startTransaction(); + try { + session = initializeSessionForUser(newContext, username); + } catch (CoreException e) { + newContext.rollbackTransaction(); + + throw new RuntimeException("Failed to initialize session for user: " + username + ": " + e.getMessage(), e); + } finally { + newContext.endTransaction(); + } + } + + return session; + } + + private static ISession initializeSessionForUser(IContext context, String username) throws CoreException { + IUser user = Core.getUser(context, username); + + if (user == null) { + throw new RuntimeException("Assertion: user with username '" + username + "' does not exist"); + } + + return Core.initializeSession(user, null); + } + + public static Object executeMicroflowAsUser(IContext context, + String microflowName, String username, Boolean sudoContext, Object... args) throws Exception { + + if (context == null) { + throw new Exception("Assertion: No context provided"); + } + if (microflowName == null || microflowName.isEmpty()) { + throw new Exception("Assertion: No context provided"); + } + if (!Core.getMicroflowNames().contains(microflowName)) { + throw new Exception("Assertion: microflow not found: " + microflowName); + } + if (args.length % 2 != 0) { + throw new Exception("Assertion: odd number of dynamic arguments provided, please name every argument: " + args.length); + } + + Map params = new LinkedHashMap(); + for (int i = 0; i < args.length; i += 2) { + if (args[i] != null) { + params.put(args[i].toString(), args[i + 1]); + } + } + + IContext c = getContextFor(context, username, sudoContext); + + return Core.microflowCall(microflowName).withParams(params).execute(c); + } + + //MWE: based on: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executor.html + static class MFSerialExecutor { + + private static MFSerialExecutor _instance = new MFSerialExecutor(); + + private final AtomicLong tasknr = new AtomicLong(); + private final ExecutorService executor; + + public static MFSerialExecutor instance() { + return _instance; + } + + private MFSerialExecutor() { + executor = Executors.newSingleThreadExecutor(new ThreadFactory() { + + //Default thread factory takes care of setting the proper thread context + private final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); + + @Override + public Thread newThread(Runnable runnable) { + Thread t = defaultFactory.newThread(runnable); + t.setPriority(Thread.MIN_PRIORITY); + t.setName("CommunityCommons background pool executor thread"); + return t; + } + + }); + } + + public void execute(final Runnable command) { + if (command == null) { + throw new NullPointerException("command"); + } + + final long currenttasknr = tasknr.incrementAndGet(); + Logging.debug(LOGNODE, "[RunMicroflowAsyncInQueue] Scheduling task #" + currenttasknr); + + executor.submit(new Runnable() { + @Override + public void run() { + Logging.debug(LOGNODE, "[RunMicroflowAsyncInQueue] Running task #" + currenttasknr); + try { + command.run(); + } catch (RuntimeException e) { + Logging.error(LOGNODE, "[RunMicroflowAsyncInQueue] Execution of task #" + currenttasknr + " failed: " + e.getMessage(), e); + throw e; //single thread executor will continue, even if an exception is thrown. + } + Logging.debug(LOGNODE, "[RunMicroflowAsyncInQueue] Completed task #" + currenttasknr + ". Tasks left: " + (tasknr.get() - currenttasknr)); + } + }); + } + } + + public static Boolean runMicroflowAsyncInQueue(final String microflowName) { + MFSerialExecutor.instance().execute(new Runnable() { + @Override + public void run() { + try { + Future future = Core.executeAsync(Core.createSystemContext(), microflowName, true, new HashMap<>()); //MWE: somehow, it only works with system context... well thats OK for now. + future.get(); + } catch (CoreException | InterruptedException | ExecutionException e) { + throw new RuntimeException("Failed to run Async: " + microflowName + ": " + e.getMessage(), e); + } + } + }); + return true; + } + + public static Boolean runMicroflowInBackground(final IContext context, final String microflowName, + final IMendixObject paramObject) { + + MFSerialExecutor.instance().execute(new Runnable() { + + @Override + public void run() { + try { + IContext c = Core.createSystemContext(); + if (paramObject != null) { + Core.executeAsync(c, microflowName, true, paramObject).get(); //MWE: somehow, it only works with system context... well thats OK for now. + } else { + Core.executeAsync(c, microflowName, true, new HashMap<>()).get(); //MWE: somehow, it only works with system context... well thats OK for now. + } + } catch (CoreException | InterruptedException | ExecutionException e) { + throw new RuntimeException("Failed to run Async: " + microflowName + ": " + e.getMessage(), e); + } + + } + + }); + return true; + } + + private interface IBatchItemHandler { + + void exec(IContext context, IMendixObject obj) throws Exception; + + } + + private static class BatchState { + + private int state = 0; //-1 = error, 1 = done. + private final IBatchItemHandler callback; + + public BatchState(IBatchItemHandler callback) { + this.callback = callback; + } + + public void setState(int state) { + this.state = state; + } + + public int getState() { + return state; + } + + public void handle(IContext context, IMendixObject obj) throws Exception { + callback.exec(context, obj); + } + } + + public static Boolean executeMicroflowInBatches(String xpath, final String microflow, int batchsize, boolean waitUntilFinished, boolean asc) throws CoreException, InterruptedException { + Logging.debug(LOGNODE, "[ExecuteInBatches] Starting microflow batch '" + microflow + "..."); + + return executeInBatches(xpath, new BatchState(new IBatchItemHandler() { + + @Override + public void exec(IContext context, IMendixObject obj) throws Exception { + Core.executeAsync(context, microflow, true, obj).get(); + } + + }), batchsize, waitUntilFinished, asc); + } + + public static Boolean recommitInBatches(String xpath, int batchsize, + boolean waitUntilFinished, Boolean asc) throws CoreException, InterruptedException { + Logging.debug(LOGNODE, "[ExecuteInBatches] Starting recommit batch..."); + + return executeInBatches(xpath, new BatchState(new IBatchItemHandler() { + + @Override + public void exec(IContext context, IMendixObject obj) throws Exception { + Core.commit(context, obj); + } + + }), batchsize, waitUntilFinished, asc); + } + + public static Boolean executeInBatches(String xpathRaw, BatchState batchState, int batchsize, boolean waitUntilFinished, boolean asc) throws CoreException, InterruptedException { + String xpath = xpathRaw.startsWith("//") ? xpathRaw : "//" + xpathRaw; + + long count = Core.createXPathQuery("count(" + xpath + ")").executeAggregateLong(Core.createSystemContext()); + int loop = (int) Math.ceil(((float) count) / ((float) batchsize)); + + Logging.debug(LOGNODE, + "[ExecuteInBatches] Starting batch on ~ " + count + " objects divided over ~ " + loop + " batches. " + + (waitUntilFinished ? "Waiting until the batch has finished..." : "") + ); + + executeInBatchesHelper(xpath, batchsize, 0, batchState, count, asc); + + if (waitUntilFinished) { + while (batchState.getState() == 0) { + Thread.sleep(5000); + } + if (batchState.getState() == 1) { + Logging.debug(LOGNODE, "[ExecuteInBatches] Successfully finished batch"); + return true; + } + Logging.error(LOGNODE, "[ExecuteInBatches] Failed to finish batch. Please check the application log for more details."); + return false; + } + + return true; + } + + static void executeInBatchesHelper(final String xpath, final int batchsize, final long last, final BatchState batchState, final long count, final boolean asc) { + MFSerialExecutor.instance().execute(new Runnable() { + + @Override + public void run() { + try { + Thread.sleep(200); + IContext c = Core.createSystemContext(); + + List objects = + Core.createXPathQuery(xpath + (last > 0 ? "[id " + (asc ? "> " : "< ") + last + "]" : "")) + .setAmount(batchsize) + .setOffset(0) + .addSort("id", asc ? true : false) + .execute(c); + + //no new objects found :) + if (objects.isEmpty()) { + Logging.debug(LOGNODE, "[ExecuteInBatches] Succesfully finished batch on ~" + count + " objects."); + batchState.setState(1); + } else { + + //process objects + for (IMendixObject obj : objects) { + batchState.handle(c, obj); + } + + //invoke next batch + executeInBatchesHelper(xpath, batchsize, objects.get(objects.size() - 1).getId().toLong(), batchState, count, asc); + } + } catch (Exception e) { + batchState.setState(-1); + throw new RuntimeException("[ExecuteInBatches] Failed to run in batch: " + e.getMessage(), e); + } + } + + }); + } + + /** + * Tests if two objects are equal with throwing unecessary null pointer exceptions. + * + * This is almost the most stupid function ever, since it should be part of Java itself. + * + * @param left + * @param right + * @return + * @deprecated Native Java function Objects.equals() is available since Java 7 + */ + @Deprecated + public static boolean objectsAreEqual(Object left, Object right) { + if (left == null && right == null) { + return true; + } + if (left == null || right == null) { + return false; + } + return left.equals(right); + } + + /** + * Get the default language + * + * @param context + * @return The default language + * @throws CoreException + */ + public static Language getDefaultLanguage(IContext context) throws CoreException { + String languageCode = Core.getDefaultLanguage().getCode(); + List languageList = Language.load(context, "[Code = '" + languageCode + "']"); + if (languageList == null || languageList.isEmpty()) { + throw new RuntimeException("No language found for default language constant value " + languageCode); + } + return languageList.get(0); + } + + public static boolean mergePDF(IContext context, List documents, IMendixObject mergedDocument) throws IOException { + if (getMergeMultiplePdfs_MaxAtOnce() <= 0 || documents.size() <= getMergeMultiplePdfs_MaxAtOnce()) { + + List sources = new ArrayList<>(); + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + PDFMergerUtility mergePdf = new PDFMergerUtility(); + + for (FileDocument file : documents) { + InputStream content = Core.getFileDocumentContent(context, file.getMendixObject()); + sources.add(content); + } + mergePdf.addSources(sources); + mergePdf.setDestinationStream(out); + mergePdf.mergeDocuments(null); + + Core.storeFileDocumentContent(context, mergedDocument, new ByteArrayInputStream(out.toByteArray())); + + out.reset(); + documents.clear(); + } catch (IOException e) { + throw new RuntimeException("Failed to merge documents" + e.getMessage(), e); + } finally { // We cannot use try-with-resources because streams would be prematurely closed + for (InputStream is : sources) { + is.close(); + } + } + + return true; + } else { + throw new IllegalArgumentException("MergeMultiplePDFs: you cannot merge more than " + getMergeMultiplePdfs_MaxAtOnce() + + " PDF files at once. You are trying to merge " + documents.size() + " PDF files."); + } + } + + /** + * Overlay a generated PDF document with another PDF (containing the company stationary for + * example) + * + * @param context + * @param generatedDocumentMendixObject The document to overlay + * @param overlayMendixObject The document containing the overlay + * @param onTopOfContent if true, puts overlay position in the foreground, otherwise in the + * background + * @return boolean + * @throws IOException + */ + public static boolean overlayPdf(IContext context, IMendixObject generatedDocumentMendixObject, IMendixObject overlayMendixObject, boolean onTopOfContent) throws IOException { + Logging.trace(LOGNODE, "Retrieve generated document"); + try ( + PDDocument inputDoc = PDDocument.load(Core.getFileDocumentContent(context, generatedDocumentMendixObject)); + PDDocument overlayDoc = PDDocument.load(Core.getFileDocumentContent(context, overlayMendixObject)); + ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + Logging.trace(LOGNODE, "Overlay PDF start, retrieve overlay PDF"); + + Logging.trace(LOGNODE, "Perform overlay"); + try (Overlay overlay = new Overlay()) { + overlay.setInputPDF(inputDoc); + overlay.setDefaultOverlayPDF(overlayDoc); + if (onTopOfContent) { + overlay.setOverlayPosition(Overlay.Position.FOREGROUND); + } else { + overlay.setOverlayPosition(Overlay.Position.BACKGROUND); + } + + Logging.trace(LOGNODE, "Save result in output stream"); + + overlay.overlay(new HashMap<>()).save(baos); + } + + Logging.trace(LOGNODE, "Duplicate result in input stream"); + try (InputStream overlayedContent = new ByteArrayInputStream(baos.toByteArray())) { + Logging.trace(LOGNODE, "Store result in original document"); + Core.storeFileDocumentContent(context, generatedDocumentMendixObject, overlayedContent); + } + } + + Logging.trace(LOGNODE, "Overlay PDF end"); + return true; + } + + /** + * Get the Cloud Foundry Instance Index (0 for leader and >0 for slave) + * + * @return CF_INSTANCE_INDEX environment variable if available, otherwise -1 + */ + public static long getCFInstanceIndex() { + long cfInstanceIndex = -1L; + + try { + cfInstanceIndex = Long.parseLong(System.getenv("CF_INSTANCE_INDEX")); + } catch (SecurityException securityException) { + Logging.info(LOGNODE, "GetCFInstanceIndex: Could not access environment variable CF_INSTANCE_INDEX, permission denied. Value of -1 is returned."); + } catch (NumberFormatException numberFormatException) { + Logging.info(LOGNODE, "GetCFInstanceIndex: Could not parse value of environment variable CF_INSTANCE_INDEX as Long. Value of -1 is returned."); + } catch (NullPointerException nullPointerException) { + Logging.info(LOGNODE, "GetCFInstanceIndex: Could not find value for environment variable CF_INSTANCE_INDEX. This could indicate a local deployment is running. Value of -1 is returned."); + } + + return cfInstanceIndex; + } + + /** + * Returns the top n items of a List + * + * @param the type of the list elements + * @param objects the list to take the top n items from + * @param top the number of items to take + * @return the sublist of
objects
with max + *
top
elements + */ + public static List listTop(List objects, int top) { + return objects.stream() + .limit(top) + .collect(Collectors.toList()); + } +} diff --git a/Source/javasource/communitycommons/ORM.java b/Source/javasource/communitycommons/ORM.java index f666e32e..c6abd73f 100644 --- a/Source/javasource/communitycommons/ORM.java +++ b/Source/javasource/communitycommons/ORM.java @@ -12,7 +12,6 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import com.mendix.systemwideinterfaces.core.IMendixObject.ObjectState; import com.mendix.systemwideinterfaces.core.IMendixObjectMember; -import com.mendix.systemwideinterfaces.core.IMendixObjectMember.MemberState; import com.mendix.systemwideinterfaces.core.meta.IMetaAssociation; import com.mendix.systemwideinterfaces.core.meta.IMetaAssociation.AssociationType; import com.mendix.systemwideinterfaces.core.meta.IMetaEnumValue; @@ -37,7 +36,7 @@ public static Long getGUID(IMendixObject item) { public static String getOriginalValueAsString(IContext context, IMendixObject item, String member) { - return String.valueOf(item.getMember(context, member).getOriginalValue(context)); + return String.valueOf(item.getMember(member).getOriginalValue(context)); } public static boolean objectHasChanged(IMendixObject anyobject) { @@ -63,7 +62,7 @@ public static boolean memberHasChanged(IContext context, IMendixObject item, Str if (!item.hasMember(member)) { throw new IllegalArgumentException("Unknown member: " + member); } - return item.getMember(context, member).getState() == MemberState.CHANGED || item.getState() != ObjectState.NORMAL; + return item.getMember(member).isChanged() || item.getState() != ObjectState.NORMAL; } public static void deepClone(IContext c, IMendixObject source, IMendixObject target, String membersToSkip, String membersToKeep, String reverseAssociations, String excludeEntities, String excludeModules) throws CoreException { @@ -195,7 +194,7 @@ public static Boolean commitWithoutEvents(IContext context, IMendixObject subjec public static String getValueOfPath(IContext context, IMendixObject substitute, String fullpath, String datetimeformat) throws Exception { String[] path = fullpath.split("/"); if (path.length == 1) { - IMendixObjectMember member = substitute.getMember(context, path[0]); + IMendixObjectMember member = substitute.getMember(path[0]); //special case, see ticket 9135, format datetime. if (member instanceof MendixDateTime) { @@ -222,7 +221,7 @@ public static String getValueOfPath(IContext context, IMendixObject substitute, } else if (path.length == 0) { throw new Exception("communitycommons.ORM.getValueOfPath: Unexpected end of path."); } else { - IMendixObjectMember member = substitute.getMember(context, path[0]); + IMendixObjectMember member = substitute.getMember(path[0]); if (member instanceof MendixObjectReference) { MendixObjectReference ref = (MendixObjectReference) member; IMendixIdentifier id = ref.getValue(context); @@ -260,7 +259,7 @@ public static String getValueOfPath(IContext context, IMendixObject substitute, } private static boolean isFileDocument(IMendixObject object) { - return Core.isSubClassOf(Core.getMetaObject(FileDocument.entityName), object.getMetaObject()); + return object.getMetaObject().isFileDocument(); } public static Boolean cloneObject(IContext c, IMendixObject source, @@ -277,7 +276,7 @@ public static Boolean cloneObject(IContext c, IMendixObject source, } if ("__UUID__".equals(m.getName()) && (isFileDocument(source) || isFileDocument(target))) { continue; - } + } if (withAssociations || ((!(m instanceof MendixObjectReference) && !(m instanceof MendixObjectReferenceSet) && !(m instanceof MendixAutoNumber)))) { target.setValue(c, entry.getKey(), m.getValue(c)); } @@ -287,7 +286,12 @@ public static Boolean cloneObject(IContext c, IMendixObject source, public static IMendixObject firstWhere(IContext c, String entityName, Object member, String value) throws CoreException { - List items = Core.retrieveXPathQuery(c, String.format("//%s[%s = '%s']", entityName, member, value), 1, 0, new HashMap()); + List items = + Core.createXPathQuery(String.format("//%s[%s = '%s']", entityName, member, value)) + .setAmount(1) + .setOffset(0) + .execute(c); + if (items == null || items.size() == 0) { return null; } diff --git a/Source/javasource/communitycommons/StringUtils.java b/Source/javasource/communitycommons/StringUtils.java index 1f201edb..d828260a 100644 --- a/Source/javasource/communitycommons/StringUtils.java +++ b/Source/javasource/communitycommons/StringUtils.java @@ -64,6 +64,12 @@ public class StringUtils { public static final String HASH_ALGORITHM = "SHA-256"; + public static String hash(String value) throws NoSuchAlgorithmException, DigestException { + int LENGTH = 32; + return hash(value, LENGTH); + } + + @Deprecated public static String hash(String value, int length) throws NoSuchAlgorithmException, DigestException { byte[] inBytes = value.getBytes(StandardCharsets.UTF_8); byte[] outBytes = new byte[length]; @@ -487,7 +493,12 @@ public static String sanitizeHTML(String html, List policyParam PolicyFactory policyFactory = null; for (SanitizerPolicy param : policyParams) { - policyFactory = (policyFactory == null) ? SANITIZER_POLICIES.get(param.name()) : policyFactory.and(SANITIZER_POLICIES.get(param.name())); + PolicyFactory policyFactoryForParam = SANITIZER_POLICIES.get(param.name()); + policyFactory = (policyFactory == null) ? policyFactoryForParam : policyFactory.and(policyFactoryForParam); + } + + if (policyFactory == null) { + throw new IllegalArgumentException("Sanitizer policy not found."); } return sanitizeHTML(html, policyFactory); diff --git a/Source/javasource/communitycommons/XPath.java b/Source/javasource/communitycommons/XPath.java index 0bcf7d57..cc499a2a 100644 --- a/Source/javasource/communitycommons/XPath.java +++ b/Source/javasource/communitycommons/XPath.java @@ -1,885 +1,893 @@ -package communitycommons; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.text.translate.AggregateTranslator; -import org.apache.commons.text.translate.CharSequenceTranslator; -import org.apache.commons.text.translate.EntityArrays; -import org.apache.commons.text.translate.LookupTranslator; - -import com.mendix.core.Core; -import com.mendix.core.CoreException; -import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.systemwideinterfaces.core.IMendixIdentifier; -import com.mendix.systemwideinterfaces.core.IMendixObject; - -public class XPath { - /** - * Built-in tokens, see: - * https://docs.mendix.com/refguide/xpath-keywords-and-system-variables/ - */ - - /* Keywords */ - public static final String ID = "id"; - public static final String NULL = "NULL"; - public static final String Empty = "empty"; - - /* Object related */ - public static final String CurrentUser = "[%CurrentUser%]"; - public static final String CurrentObject = "[%CurrentObject%]"; - - /* Time related */ - public static final String CurrentDateTime = "[%CurrentDateTime%]"; - public static final String BeginOfCurrentMinute = "[%BeginOfCurrentMinute%]"; - public static final String BeginOfCurrentMinuteUTC = "[%BeginOfCurrentMinuteUTC%]"; - public static final String EndOfCurrentMinute = "[%EndOfCurrentMinute%]"; - public static final String EndOfCurrentMinuteUTC = "[%EndOfCurrentMinuteUTC%]"; - public static final String BeginOfCurrentHour = "[%BeginOfCurrentHour%]"; - public static final String BeginOfCurrentHourUTC = "[%BeginOfCurrentHourUTC%]"; - public static final String EndOfCurrentHour = "[%EndOfCurrentHour%]"; - public static final String EndOfCurrentHourUTC = "[%EndOfCurrentHourUTC%]"; - public static final String BeginOfCurrentDay = "[%BeginOfCurrentDay%]"; - public static final String BeginOfCurrentDayUTC = "[%BeginOfCurrentDayUTC%]"; - public static final String EndOfCurrentDay = "[%EndOfCurrentDay%]"; - public static final String EndOfCurrentDayUTC = "[%EndOfCurrentDayUTC%]"; - public static final String BeginOfYesterday = "[%BeginOfYesterday%]"; - public static final String BeginOfYesterdayUTC = "[%BeginOfYesterdayUTC%]"; - public static final String EndOfYesterday = "[%EndOfYesterday%]"; - public static final String EndOfYesterdayUTC = "[%EndOfYesterdayUTC%]"; - public static final String BeginOfTomorrow = "[%BeginOfTomorrow%]"; - public static final String BeginOfTomorrowUTC = "[%BeginOfTomorrowUTC%]"; - public static final String EndOfTomorrow = "[%EndOfTomorrow%]"; - public static final String EndOfTomorrowUTC = "[%EndOfTomorrowUTC%]"; - public static final String BeginOfCurrentWeek = "[%BeginOfCurrentWeek%]"; - public static final String BeginOfCurrentWeekUTC = "[%BeginOfCurrentWeekUTC%]"; - public static final String EndOfCurrentWeek = "[%EndOfCurrentWeek%]"; - public static final String EndOfCurrentWeekUTC = "[%EndOfCurrentWeekUTC%]"; - public static final String BeginOfCurrentMonth = "[%BeginOfCurrentMonth%]"; - public static final String BeginOfCurrentMonthUTC = "[%BeginOfCurrentMonthUTC%]"; - public static final String EndOfCurrentMonth = "[%EndOfCurrentMonth%]"; - public static final String EndOfCurrentMonthUTC = "[%EndOfCurrentMonthUTC%]"; - public static final String BeginOfCurrentYear = "[%BeginOfCurrentYear%]"; - public static final String BeginOfCurrentYearUTC = "[%BeginOfCurrentYearUTC%]"; - public static final String EndOfCurrentYear = "[%EndOfCurrentYear%]"; - public static final String EndOfCurrentYearUTC = "[%EndOfCurrentYearUTC%]"; - - public static final String DayLength = "[%DayLength%]"; - public static final String HourLength = "[%HourLength%]"; - public static final String MinuteLength = "[%MinuteLength%]"; - public static final String SecondLength = "[%SecondLength%]"; - public static final String WeekLength = "[%WeekLength%]"; - public static final String MonthLength = "[%MonthLength%]"; - public static final String YearLength = "[%YearLength%]"; - - private String entity; - private int offset = 0; - private int limit = -1; - // important, linked map, insertion order is relevant! - private LinkedHashMap sorting = new LinkedHashMap(); - private LinkedList closeStack = new LinkedList(); - private StringBuilder builder = new StringBuilder(); - private IContext context; - private Class proxyClass; - // state property, indicates whether 'and' needs to be inserted before the next - // constraint - private boolean requiresBinOp = false; - - public static XPath create(IContext c, String entityType) { - XPath res = new XPath(c, IMendixObject.class); - res.entity = entityType; - return res; - } - - public static XPath create(IContext c, Class proxyClass) { - return new XPath(c, proxyClass); - } - - private XPath(IContext c, Class proxyClass) { - try { - if (proxyClass != IMendixObject.class) - entity = (String) proxyClass.getMethod("getType").invoke(null); - } catch (Exception e) { - throw new IllegalArgumentException( - "Failed to determine entity type of proxy class. Did you provide a valid proxy class? '" - + proxyClass.getName() + "'"); - } - - this.proxyClass = proxyClass; - this.context = c; - } - - private XPath autoInsertAnd() { - if (requiresBinOp) - and(); - return this; - } - - private XPath requireBinOp(boolean requires) { - requiresBinOp = requires; - return this; - } - - public XPath offset(int offset) { - if (offset < 0) - throw new IllegalArgumentException("Offset should not be negative"); - - this.offset = offset; - return this; - } - - public XPath limit(int limit) { - if (limit < -1 || limit == 0) - throw new IllegalArgumentException("Limit should be larger than zero or -1. "); - - this.limit = limit; - return this; - } - - public XPath addSortingAsc(Object... sortparts) { - assertOdd(sortparts); - sorting.put(StringUtils.join(sortparts, '/'), "asc"); - return this; - } - - public XPath addSortingDesc(Object... sortparts) { - sorting.put(StringUtils.join(sortparts, "/"), "desc"); - return this; - } - - public XPath eq(Object attr, Object valuecomparison) { - return compare(attr, "=", valuecomparison); - } - - public XPath eq(Object... pathAndValue) { - return compare("=", pathAndValue); - } - - public XPath equalsIgnoreCase(Object attr, String value) { - // (contains(Name, $email) and length(Name) = length($email) - return subconstraint() - .contains(attr, value) - .and() - .append(" length(" + attr + ") = ").append(value == null ? "0" : valueToXPathValue(value.length())) - .close(); - } - - public XPath notEq(Object attr, Object valuecomparison) { - return compare(attr, "!=", valuecomparison); - } - - public XPath notEq(Object... pathAndValue) { - return compare("!=", pathAndValue); - } - - public XPath gt(Object attr, Object valuecomparison) { - return compare(attr, ">", valuecomparison); - } - - public XPath gt(Object... pathAndValue) { - return compare(">", pathAndValue); - } - - public XPath gte(Object attr, Object valuecomparison) { - return compare(attr, ">=", valuecomparison); - } - - public XPath gte(Object... pathAndValue) { - return compare(">=", pathAndValue); - } - - public XPath lt(Object attr, Object valuecomparison) { - return compare(attr, "<", valuecomparison); - } - - public XPath lt(Object... pathAndValue) { - return compare("<", pathAndValue); - } - - public XPath lte(Object attr, Object valuecomparison) { - return compare(attr, "<=", valuecomparison); - } - - public XPath lte(Object... pathAndValue) { - return compare("<=", pathAndValue); - } - - public XPath contains(Object attr, String value) { - return functionCall("contains", String.valueOf(attr), valueToXPathValue(value)); - } - - public XPath startsWith(Object attr, String value) { - return functionCall("starts-with", String.valueOf(attr), valueToXPathValue(value)); - } - - public XPath endsWith(Object attr, String value) { - return functionCall("ends-with", String.valueOf(attr), valueToXPathValue(value)); - } - - private XPath functionCall(String functionName, String... args) { - autoInsertAnd(); - append(" " + functionName + "("); - - if (args.length > 0) { - append(args[0]); - for (int i = 1; i < args.length; i++) { - append(","); - append(args[i]); - } - } - append(") "); - return requireBinOp(true); - } - - public XPath compare(Object attr, String operator, Object value) { - return compare(new Object[] { attr }, operator, value); - } - - private XPath compare(String operator, Object[] pathAndValue) { - assertEven(pathAndValue); - int lastIndex = pathAndValue.length - 1; - return compare(Arrays.copyOf(pathAndValue, lastIndex), operator, pathAndValue[lastIndex]); - } - - public XPath compare(Object[] path, String operator, Object value) { - assertOdd(path); - autoInsertAnd().append(StringUtils.join(path, '/')).append(" ").append(operator).append(" ") - .append(valueToXPathValue(value)); - return requireBinOp(true); - } - - public XPath hasReference(Object... path) { - assertEven(path); // Reference + entity type - autoInsertAnd().append(StringUtils.join(path, '/')); - return requireBinOp(true); - } - - public XPath subconstraint(Object... path) { - assertEven(path); - autoInsertAnd().append(StringUtils.join(path, '/')).append("["); - closeStack.push("]"); - return requireBinOp(false); - } - - public XPath subconstraint() { - autoInsertAnd().append("("); - closeStack.push(")"); - return requireBinOp(false); - } - - public XPath addConstraint() { - if (!closeStack.isEmpty() && !closeStack.peek().equals("]")) - throw new IllegalStateException("Cannot add a constraint while in the middle of something else.."); - - return append("][").requireBinOp(false); - } - - public XPath close() { - if (closeStack.isEmpty()) - throw new IllegalStateException("XPathbuilder close stack is empty!"); - append(closeStack.pop()); - return requireBinOp(true); - // MWE: note that a close does not necessary require a binary operator, for - // example with two subsequent block([bla][boe]) constraints, - // but openening a binary constraint reset the flag, so that should be no issue - } - - public XPath or() { - if (!requiresBinOp) - throw new IllegalStateException("Received 'or' but no binary operator was expected"); - return append(" or ").requireBinOp(false); - } - - public XPath and() { - if (!requiresBinOp) - throw new IllegalStateException("Received 'and' but no binary operator was expected"); - return append(" and ").requireBinOp(false); - } - - public XPath not() { - autoInsertAnd(); - closeStack.push(")"); - return append(" not(").requireBinOp(false); - } - - private void assertOdd(Object[] stuff) { - if (stuff == null || stuff.length == 0 || stuff.length % 2 == 0) - throw new IllegalArgumentException("Expected an odd number of xpath path parts"); - } - - private void assertEven(Object[] stuff) { - if (stuff == null || stuff.length == 0 || stuff.length % 2 == 1) - throw new IllegalArgumentException("Expected an even number of xpath path parts"); - } - - public XPath append(String s) { - builder.append(s); - return this; - } - - public String getXPath() { - if (builder.length() > 0) - return "//" + entity + "[" + builder + "]"; - return "//" + entity; - } - - private void assertEmptyStack() throws IllegalStateException { - if (!closeStack.isEmpty()) - throw new IllegalStateException("Invalid xpath expression, not all items where closed"); - } - - public long count() throws CoreException { - assertEmptyStack(); - - return Core.retrieveXPathQueryAggregate(context, "count(" + getXPath() + ")"); - } - - public IMendixObject firstMendixObject() throws CoreException { - assertEmptyStack(); - - List result = Core.retrieveXPathQuery(context, getXPath(), 1, offset, sorting); - if (result.isEmpty()) - return null; - return result.get(0); - } - - public T first() throws CoreException { - return createProxy(context, proxyClass, firstMendixObject()); - } - - /** - * Given a set of attribute names and values, tries to find the first object - * that matches all conditions, or creates one - * - * @param keysAndValues - * @return - * @throws CoreException - */ - public T findOrCreateNoCommit(Object... keysAndValues) throws CoreException { - T res = findFirst(keysAndValues); - - return res != null ? res : constructInstance(false, keysAndValues); - } - - public T findOrCreate(Object... keysAndValues) throws CoreException { - T res = findFirst(keysAndValues); - - return res != null ? res : constructInstance(true, keysAndValues); - - } - - public T findOrCreateSynchronized(Object... keysAndValues) throws CoreException, InterruptedException { - T res = findFirst(keysAndValues); - - if (res != null) { - return res; - } else { - synchronized (Core.getMetaObject(entity)) { - IContext synchronizedContext = context.getSession().createContext().createSudoClone(); - try { - synchronizedContext.startTransaction(); - res = createProxy(synchronizedContext, proxyClass, - XPath.create(synchronizedContext, entity).findOrCreate(keysAndValues)); - synchronizedContext.endTransaction(); - return res; - } catch (CoreException e) { - if (synchronizedContext.isInTransaction()) { - synchronizedContext.rollbackTransaction(); - } - throw e; - } - } - } - } - - public T findFirst(Object... keysAndValues) - throws IllegalStateException, CoreException { - if (builder.length() > 0) - throw new IllegalStateException("FindFirst can only be used on XPath which do not have constraints already"); - - assertEven(keysAndValues); - for (int i = 0; i < keysAndValues.length; i += 2) - eq(keysAndValues[i], keysAndValues[i + 1]); - - return first(); - } - - /** - * Creates one instance of the type of this XPath query, and initializes the - * provided attributes to the provided values. - * - * @param keysAndValues AttributeName, AttributeValue, AttributeName2, - * AttributeValue2... list. - * @return - * @throws CoreException - */ - public T constructInstance(boolean autoCommit, Object... keysAndValues) throws CoreException { - assertEven(keysAndValues); - IMendixObject newObj = Core.instantiate(context, entity); - - for (int i = 0; i < keysAndValues.length; i += 2) - newObj.setValue(context, String.valueOf(keysAndValues[i]), toMemberValue(keysAndValues[i + 1])); - - if (autoCommit) - Core.commit(context, newObj); - - return createProxy(context, proxyClass, newObj); - } - - /** - * Given a current collection of primitive values, checks if for each value in - * the collection an object in the database exists. - * It creates a new object if needed, and removes any superfluos objects in the - * database that are no longer in the collection. - * - * @param currentCollection The collection that act as reference for the - * objects that should be in this database in the - * end. - * @param comparisonAttribute The attribute that should store the value as - * decribed in the collection - * @param autoDelete Automatically remove any superfluous objects form - * the database - * @param keysAndValues Constraints that should hold for the set of - * objects that are deleted or created. Objects - * outside this constraint are not processed. - * - * @return A pair of lists. The first list contains the newly created objects, - * the second list contains the objects that (should be or are) removed. - * @throws CoreException - */ - public ImmutablePair, List> syncDatabaseWithCollection(Collection currentCollection, - Object comparisonAttribute, boolean autoDelete, Object... keysAndValues) throws CoreException { - if (builder.length() > 0) - throw new IllegalStateException( - "syncDatabaseWithCollection can only be used on XPath which do not have constraints already"); - - List added = new ArrayList(); - List removed = new ArrayList(); - - Set col = new HashSet(currentCollection); - - for (int i = 0; i < keysAndValues.length; i += 2) - eq(keysAndValues[i], keysAndValues[i + 1]); - - for (IMendixObject existingItem : allMendixObjects()) { - // Item is still available - if (col.remove(existingItem.getValue(context, String.valueOf(comparisonAttribute)))) - continue; - - // No longer available - removed.add(createProxy(context, proxyClass, existingItem)); - if (autoDelete) - Core.delete(context, existingItem); - } - - // Some items where not found in the database - for (U value : col) { - - // In apache lang3, this would just be: ArrayUtils.addAll(keysAndValues, - // comparisonAttribute, value) - Object[] args = new Object[keysAndValues.length + 2]; - for (int i = 0; i < keysAndValues.length; i++) - args[i] = keysAndValues[i]; - args[keysAndValues.length] = comparisonAttribute; - args[keysAndValues.length + 1] = value; - - T newItem = constructInstance(true, args); - added.add(newItem); - } - - // Oké, stupid, Pair is also only available in apache lang3, so lets use a - // simple pair implementation for now - return ImmutablePair.of(added, removed); - } - - public T firstOrWait(long timeoutMSecs) throws CoreException, InterruptedException { - IMendixObject result = null; - - long start = System.currentTimeMillis(); - int sleepamount = 200; - int loopcount = 0; - - while (result == null) { - loopcount += 1; - result = firstMendixObject(); - - long now = System.currentTimeMillis(); - - if (start + timeoutMSecs < now) // Time expired - break; - - if (loopcount % 5 == 0) - sleepamount *= 1.5; - - // not expired, wait a bit - if (result == null) - Thread.sleep(sleepamount); - } - - return createProxy(context, proxyClass, result); - } - - public List allMendixObjects() throws CoreException { - assertEmptyStack(); - - return Core.retrieveXPathQuery(context, getXPath(), limit, offset, sorting); - } - - public List all() throws CoreException { - List res = new ArrayList(); - for (IMendixObject o : allMendixObjects()) - res.add(createProxy(context, proxyClass, o)); - - return res; - } - - @Override - public String toString() { - return getXPath(); - } - - /* Static utility functions */ - - // Cache for proxy constructors. Reflection is slow, so reuse as much as - // possible - private static Map initializers = new HashMap(); - - public static List createProxyList(IContext c, Class proxieClass, List objects) { - List res = new ArrayList(); - if (objects == null || objects.size() == 0) - return res; - - for (IMendixObject o : objects) - res.add(createProxy(c, proxieClass, o)); - - return res; - } - - public static T createProxy(IContext c, Class proxieClass, IMendixObject object) { - // Borrowed from nl.mweststrate.pages.MxQ package - - if (object == null) - return null; - - if (c == null || proxieClass == null) - throw new IllegalArgumentException("[CreateProxy] No context or proxieClass provided. "); - - // jeuj, we expect IMendixObject's. Thats nice.. - if (proxieClass == IMendixObject.class) - return proxieClass.cast(object); // .. since we can do a direct cast - - try { - String entityType = object.getType(); - - if (!initializers.containsKey(entityType)) { - - String[] entType = object.getType().split("\\."); - Class realClass = Class.forName(entType[0].toLowerCase() + ".proxies." + entType[1]); - - initializers.put(entityType, realClass.getMethod("initialize", IContext.class, IMendixObject.class)); - } - - // find constructor - Method m = initializers.get(entityType); - - // create proxy object - Object result = m.invoke(null, c, object); - - // cast, but check first is needed because the actual type might be a subclass - // of the requested type - if (!proxieClass.isAssignableFrom(result.getClass())) - throw new IllegalArgumentException("The type of the object ('" + object.getType() - + "') is not (a subclass) of '" + proxieClass.getName() + "'"); - - T proxie = proxieClass.cast(result); - return proxie; - } catch (Exception e) { - throw new RuntimeException("Unable to instantiate proxie: " + e.getMessage(), e); - } - } - - public static String valueToXPathValue(Object value) { - if (value == null) - return NULL; - - // Complex objects - if (value instanceof IMendixIdentifier) - return "'" + String.valueOf(((IMendixIdentifier) value).toLong()) + "'"; - if (value instanceof IMendixObject) - return valueToXPathValue(((IMendixObject) value).getId()); - if (value instanceof List) - throw new IllegalArgumentException("List based values are not supported!"); - - // Primitives - if (value instanceof Date) - return String.valueOf(((Date) value).getTime()); - if (value instanceof Long || value instanceof Integer) - return String.valueOf(value); - if (value instanceof Double || value instanceof Float) { - // make sure xpath understands our number formatting - NumberFormat format = NumberFormat.getNumberInstance(Locale.ENGLISH); - format.setMaximumFractionDigits(10); - format.setGroupingUsed(false); - return format.format(value); - } - if (value instanceof Boolean) { - return value.toString() + "()"; // xpath boolean, you know.. - } - if (value instanceof String) { - return "'" + ESCAPE_XML.translate(String.valueOf(value)) + "'"; - } - - // Object, assume its a proxy and deproxiefy - try { - IMendixObject mo = proxyToMendixObject(value); - return valueToXPathValue(mo); - } catch (NoSuchMethodException e) { - // This is O.K. just not a proxy object... - } catch (Exception e) { - throw new RuntimeException("Failed to retrieve MendixObject from proxy: " + e.getMessage(), e); - } - - // assume some string representation - return "'" + ESCAPE_XML.translate(String.valueOf(value)) + "'"; - } - - public static IMendixObject proxyToMendixObject(Object value) - throws NoSuchMethodException, SecurityException, IllegalAccessException, - IllegalArgumentException, InvocationTargetException { - Method m = value.getClass().getMethod("getMendixObject"); - IMendixObject mo = (IMendixObject) m.invoke(value); - return mo; - } - - public static List proxyListToMendixObjectList( - List objects) throws SecurityException, IllegalArgumentException, NoSuchMethodException, - IllegalAccessException, InvocationTargetException { - ArrayList res = new ArrayList(objects.size()); - for (T i : objects) - res.add(proxyToMendixObject(i)); - return res; - } - - public static Object toMemberValue(Object value) { - if (value == null) - return null; - - // Complex objects - if (value instanceof IMendixIdentifier) - return value; - if (value instanceof IMendixObject) - return ((IMendixObject) value).getId(); - - if (value instanceof List) - throw new IllegalArgumentException("List based values are not supported!"); - - // Primitives - if (value instanceof Date - || value instanceof Long - || value instanceof Integer - || value instanceof Double - || value instanceof Float - || value instanceof Boolean - || value instanceof String) { - return value; - } - - if (value.getClass().isEnum()) - return value.toString(); - - // Object, assume its a proxy and deproxiefy - try { - Method m = value.getClass().getMethod("getMendixObject"); - IMendixObject mo = (IMendixObject) m.invoke(value); - return toMemberValue(mo); - } catch (NoSuchMethodException e) { - // This is O.K. just not a proxy object... - } catch (Exception e) { - throw new RuntimeException( - "Failed to convert object to IMendixMember compatible value '" + value + "': " + e.getMessage(), e); - } - - throw new RuntimeException("Failed to convert object to IMendixMember compatible value: " + value); - } - - public static interface IBatchProcessor { - public void onItem(T item, long offset, long total) throws Exception; - } - - private static final class ParallelJobRunner implements Callable { - private final XPath self; - private final IBatchProcessor batchProcessor; - private final IMendixObject item; - private long index; - private long count; - - ParallelJobRunner(XPath self, IBatchProcessor batchProcessor, IMendixObject item, long index, long count) { - this.self = self; - this.batchProcessor = batchProcessor; - this.item = item; - this.index = index; - this.count = count; - } - - @Override - public Boolean call() { - try { - batchProcessor.onItem(XPath.createProxy(Core.createSystemContext(), self.proxyClass, item), index, count); - return true; - } catch (Exception e) { - throw new RuntimeException(String.format("Failed to execute batch on '%s' offset %d: %s", self.toString(), - self.offset, e.getMessage()), e); - } - } - } - - /** - * Retreives all items in this xpath query in batches of a limited size. - * Not that this function does not start a new transaction for all the batches, - * rather, it just limits the number of objects being retrieved and kept in - * memory at the same time. - * - * So it only batches the retrieve process, not the optional manipulations done - * in the onItem method. - * - * @param batchsize - * @param batchProcessor - * @throws CoreException - */ - public void batch(int batchsize, IBatchProcessor batchProcessor) throws CoreException { - if (sorting.isEmpty()) - addSortingAsc(XPath.ID); - - final long itemcount = count(); - - int baseoffset = offset; - int baselimit = limit; - - boolean useBaseLimit = baselimit > -1; - - offset(baseoffset); - List data; - - long i = 0; - - do { - int newlimit = useBaseLimit ? Math.min(batchsize, baseoffset + baselimit - offset) : batchsize; - if (newlimit == 0) - break; // where done, no more data is needed - - limit(newlimit); - data = all(); - - for (T item : data) { - i += 1; - try { - batchProcessor.onItem(item, i, Math.max(i, itemcount)); - } catch (Exception e) { - throw new RuntimeException(String.format("Failed to execute batch on '%s' offset %d: %s", this, - offset, e.getMessage()), e); - } - } - - offset(offset + data.size()); - } while (data.size() > 0); - } - - /** - * Batch with parallelization. - * - * IMPORTANT NOTE: DO NOT USE THE CONTEXT OF THE XPATH OBJECT ITSELF INSIDE THE - * BATCH PROCESSOR! - * - * Instead, use: Item.getContext(); !! - * - * - * @param batchsize - * @param threads - * @param batchProcessor - * @throws CoreException - * @throws InterruptedException - * @throws ExecutionException - */ - public void batch(int batchsize, int threads, final IBatchProcessor batchProcessor) - throws CoreException, InterruptedException, ExecutionException { - if (sorting.isEmpty()) - addSortingAsc(XPath.ID); - - ExecutorService pool = Executors.newFixedThreadPool(threads); - - final long itemcount = count(); - - int progress = 0; - List> futures = new ArrayList>(batchsize); // no need to synchronize - - offset(0); - limit(batchsize); - - List data = allMendixObjects(); - - while (data.size() > 0) { - for (final IMendixObject item : data) { - futures.add(pool.submit(new ParallelJobRunner(this, batchProcessor, item, progress, itemcount))); - progress += 1; - } - - while (!futures.isEmpty()) - futures.remove(0).get(); // wait for all futures before proceeding to next iteration - - offset(offset + data.size()); - data = allMendixObjects(); - } - - if (pool.shutdownNow().size() > 0) - throw new IllegalStateException("Not all tasks where finished!"); - } - - public static Class getProxyClassForEntityName(String entityname) { - { - String[] parts = entityname.split("\\."); - try { - return Class.forName(parts[0].toLowerCase() + ".proxies." + parts[1]); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Cannot find class for entity: " + entityname + ": " + e.getMessage(), e); - } - } - } - - public boolean deleteAll() throws CoreException { - limit(1000); - List objs = allMendixObjects(); - while (!objs.isEmpty()) { - if (!Core.delete(context, objs.toArray(new IMendixObject[objs.size()]))) - return false; // TODO: throw? - - objs = allMendixObjects(); - } - return true; - } - - // Implement our own ESCAPE_XML because the original got deprecated and we - // originally translated only a very small - // subset of characters. - private static final CharSequenceTranslator ESCAPE_XML = new AggregateTranslator( - new LookupTranslator(EntityArrays.BASIC_ESCAPE), - new LookupTranslator(EntityArrays.APOS_ESCAPE)); -} +package communitycommons; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.translate.AggregateTranslator; +import org.apache.commons.text.translate.CharSequenceTranslator; +import org.apache.commons.text.translate.EntityArrays; +import org.apache.commons.text.translate.LookupTranslator; + +import com.mendix.core.Core; +import com.mendix.core.CoreException; +import com.mendix.datastorage.XPathQuery; +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.IMendixIdentifier; +import com.mendix.systemwideinterfaces.core.IMendixObject; + +public class XPath { + /** + * Built-in tokens, see: + * https://docs.mendix.com/refguide/xpath-keywords-and-system-variables/ + */ + + /* Keywords */ + public static final String ID = "id"; + public static final String NULL = "NULL"; + public static final String Empty = "empty"; + + /* Object related */ + public static final String CurrentUser = "[%CurrentUser%]"; + public static final String CurrentObject = "[%CurrentObject%]"; + + /* Time related */ + public static final String CurrentDateTime = "[%CurrentDateTime%]"; + public static final String BeginOfCurrentMinute = "[%BeginOfCurrentMinute%]"; + public static final String BeginOfCurrentMinuteUTC = "[%BeginOfCurrentMinuteUTC%]"; + public static final String EndOfCurrentMinute = "[%EndOfCurrentMinute%]"; + public static final String EndOfCurrentMinuteUTC = "[%EndOfCurrentMinuteUTC%]"; + public static final String BeginOfCurrentHour = "[%BeginOfCurrentHour%]"; + public static final String BeginOfCurrentHourUTC = "[%BeginOfCurrentHourUTC%]"; + public static final String EndOfCurrentHour = "[%EndOfCurrentHour%]"; + public static final String EndOfCurrentHourUTC = "[%EndOfCurrentHourUTC%]"; + public static final String BeginOfCurrentDay = "[%BeginOfCurrentDay%]"; + public static final String BeginOfCurrentDayUTC = "[%BeginOfCurrentDayUTC%]"; + public static final String EndOfCurrentDay = "[%EndOfCurrentDay%]"; + public static final String EndOfCurrentDayUTC = "[%EndOfCurrentDayUTC%]"; + public static final String BeginOfYesterday = "[%BeginOfYesterday%]"; + public static final String BeginOfYesterdayUTC = "[%BeginOfYesterdayUTC%]"; + public static final String EndOfYesterday = "[%EndOfYesterday%]"; + public static final String EndOfYesterdayUTC = "[%EndOfYesterdayUTC%]"; + public static final String BeginOfTomorrow = "[%BeginOfTomorrow%]"; + public static final String BeginOfTomorrowUTC = "[%BeginOfTomorrowUTC%]"; + public static final String EndOfTomorrow = "[%EndOfTomorrow%]"; + public static final String EndOfTomorrowUTC = "[%EndOfTomorrowUTC%]"; + public static final String BeginOfCurrentWeek = "[%BeginOfCurrentWeek%]"; + public static final String BeginOfCurrentWeekUTC = "[%BeginOfCurrentWeekUTC%]"; + public static final String EndOfCurrentWeek = "[%EndOfCurrentWeek%]"; + public static final String EndOfCurrentWeekUTC = "[%EndOfCurrentWeekUTC%]"; + public static final String BeginOfCurrentMonth = "[%BeginOfCurrentMonth%]"; + public static final String BeginOfCurrentMonthUTC = "[%BeginOfCurrentMonthUTC%]"; + public static final String EndOfCurrentMonth = "[%EndOfCurrentMonth%]"; + public static final String EndOfCurrentMonthUTC = "[%EndOfCurrentMonthUTC%]"; + public static final String BeginOfCurrentYear = "[%BeginOfCurrentYear%]"; + public static final String BeginOfCurrentYearUTC = "[%BeginOfCurrentYearUTC%]"; + public static final String EndOfCurrentYear = "[%EndOfCurrentYear%]"; + public static final String EndOfCurrentYearUTC = "[%EndOfCurrentYearUTC%]"; + + public static final String DayLength = "[%DayLength%]"; + public static final String HourLength = "[%HourLength%]"; + public static final String MinuteLength = "[%MinuteLength%]"; + public static final String SecondLength = "[%SecondLength%]"; + public static final String WeekLength = "[%WeekLength%]"; + public static final String MonthLength = "[%MonthLength%]"; + public static final String YearLength = "[%YearLength%]"; + + private String entity; + private int offset = 0; + private int limit = -1; + // important, linked map, insertion order is relevant! + private LinkedHashMap sorting = new LinkedHashMap(); + private LinkedList closeStack = new LinkedList(); + private StringBuilder builder = new StringBuilder(); + private IContext context; + private Class proxyClass; + // state property, indicates whether 'and' needs to be inserted before the next + // constraint + private boolean requiresBinOp = false; + + public static XPath create(IContext c, String entityType) { + XPath res = new XPath(c, IMendixObject.class); + res.entity = entityType; + return res; + } + + public static XPath create(IContext c, Class proxyClass) { + return new XPath(c, proxyClass); + } + + private XPath(IContext c, Class proxyClass) { + try { + if (proxyClass != IMendixObject.class) + entity = (String) proxyClass.getMethod("getType").invoke(null); + } catch (Exception e) { + throw new IllegalArgumentException( + "Failed to determine entity type of proxy class. Did you provide a valid proxy class? '" + + proxyClass.getName() + "'"); + } + + this.proxyClass = proxyClass; + this.context = c; + } + + private XPath autoInsertAnd() { + if (requiresBinOp) + and(); + return this; + } + + private XPath requireBinOp(boolean requires) { + requiresBinOp = requires; + return this; + } + + public XPath offset(int offset) { + if (offset < 0) + throw new IllegalArgumentException("Offset should not be negative"); + + this.offset = offset; + return this; + } + + public XPath limit(int limit) { + if (limit < -1 || limit == 0) + throw new IllegalArgumentException("Limit should be larger than zero or -1. "); + + this.limit = limit; + return this; + } + + public XPath addSortingAsc(Object... sortparts) { + assertOdd(sortparts); + sorting.put(StringUtils.join(sortparts, '/'), "asc"); + return this; + } + + public XPath addSortingDesc(Object... sortparts) { + sorting.put(StringUtils.join(sortparts, "/"), "desc"); + return this; + } + + public XPath eq(Object attr, Object valuecomparison) { + return compare(attr, "=", valuecomparison); + } + + public XPath eq(Object... pathAndValue) { + return compare("=", pathAndValue); + } + + public XPath equalsIgnoreCase(Object attr, String value) { + // (contains(Name, $email) and length(Name) = length($email) + return subconstraint() + .contains(attr, value) + .and() + .append(" length(" + attr + ") = ").append(value == null ? "0" : valueToXPathValue(value.length())) + .close(); + } + + public XPath notEq(Object attr, Object valuecomparison) { + return compare(attr, "!=", valuecomparison); + } + + public XPath notEq(Object... pathAndValue) { + return compare("!=", pathAndValue); + } + + public XPath gt(Object attr, Object valuecomparison) { + return compare(attr, ">", valuecomparison); + } + + public XPath gt(Object... pathAndValue) { + return compare(">", pathAndValue); + } + + public XPath gte(Object attr, Object valuecomparison) { + return compare(attr, ">=", valuecomparison); + } + + public XPath gte(Object... pathAndValue) { + return compare(">=", pathAndValue); + } + + public XPath lt(Object attr, Object valuecomparison) { + return compare(attr, "<", valuecomparison); + } + + public XPath lt(Object... pathAndValue) { + return compare("<", pathAndValue); + } + + public XPath lte(Object attr, Object valuecomparison) { + return compare(attr, "<=", valuecomparison); + } + + public XPath lte(Object... pathAndValue) { + return compare("<=", pathAndValue); + } + + public XPath contains(Object attr, String value) { + return functionCall("contains", String.valueOf(attr), valueToXPathValue(value)); + } + + public XPath startsWith(Object attr, String value) { + return functionCall("starts-with", String.valueOf(attr), valueToXPathValue(value)); + } + + public XPath endsWith(Object attr, String value) { + return functionCall("ends-with", String.valueOf(attr), valueToXPathValue(value)); + } + + private XPath functionCall(String functionName, String... args) { + autoInsertAnd(); + append(" " + functionName + "("); + + if (args.length > 0) { + append(args[0]); + for (int i = 1; i < args.length; i++) { + append(","); + append(args[i]); + } + } + append(") "); + return requireBinOp(true); + } + + public XPath compare(Object attr, String operator, Object value) { + return compare(new Object[] { attr }, operator, value); + } + + private XPath compare(String operator, Object[] pathAndValue) { + assertEven(pathAndValue); + int lastIndex = pathAndValue.length - 1; + return compare(Arrays.copyOf(pathAndValue, lastIndex), operator, pathAndValue[lastIndex]); + } + + public XPath compare(Object[] path, String operator, Object value) { + assertOdd(path); + autoInsertAnd().append(StringUtils.join(path, '/')).append(" ").append(operator).append(" ") + .append(valueToXPathValue(value)); + return requireBinOp(true); + } + + public XPath hasReference(Object... path) { + assertEven(path); // Reference + entity type + autoInsertAnd().append(StringUtils.join(path, '/')); + return requireBinOp(true); + } + + public XPath subconstraint(Object... path) { + assertEven(path); + autoInsertAnd().append(StringUtils.join(path, '/')).append("["); + closeStack.push("]"); + return requireBinOp(false); + } + + public XPath subconstraint() { + autoInsertAnd().append("("); + closeStack.push(")"); + return requireBinOp(false); + } + + public XPath addConstraint() { + if (!closeStack.isEmpty() && !closeStack.peek().equals("]")) + throw new IllegalStateException("Cannot add a constraint while in the middle of something else.."); + + return append("][").requireBinOp(false); + } + + public XPath close() { + if (closeStack.isEmpty()) + throw new IllegalStateException("XPathbuilder close stack is empty!"); + append(closeStack.pop()); + return requireBinOp(true); + // MWE: note that a close does not necessary require a binary operator, for + // example with two subsequent block([bla][boe]) constraints, + // but openening a binary constraint reset the flag, so that should be no issue + } + + public XPath or() { + if (!requiresBinOp) + throw new IllegalStateException("Received 'or' but no binary operator was expected"); + return append(" or ").requireBinOp(false); + } + + public XPath and() { + if (!requiresBinOp) + throw new IllegalStateException("Received 'and' but no binary operator was expected"); + return append(" and ").requireBinOp(false); + } + + public XPath not() { + autoInsertAnd(); + closeStack.push(")"); + return append(" not(").requireBinOp(false); + } + + private void assertOdd(Object[] stuff) { + if (stuff == null || stuff.length == 0 || stuff.length % 2 == 0) + throw new IllegalArgumentException("Expected an odd number of xpath path parts"); + } + + private void assertEven(Object[] stuff) { + if (stuff == null || stuff.length == 0 || stuff.length % 2 == 1) + throw new IllegalArgumentException("Expected an even number of xpath path parts"); + } + + public XPath append(String s) { + builder.append(s); + return this; + } + + public String getXPath() { + if (builder.length() > 0) + return "//" + entity + "[" + builder + "]"; + return "//" + entity; + } + + private void assertEmptyStack() throws IllegalStateException { + if (!closeStack.isEmpty()) + throw new IllegalStateException("Invalid xpath expression, not all items where closed"); + } + + public long count() throws CoreException { + assertEmptyStack(); + + return Core.createXPathQuery("count(" + getXPath() + ")").executeAggregateLong(context); + } + + public IMendixObject firstMendixObject() throws CoreException { + assertEmptyStack(); + + XPathQuery query = (XPathQuery) Core.createXPathQuery(getXPath()).setAmount(1).setOffset(offset); + for (Map.Entry sort : sorting.entrySet()) + query.addSort(sort.getKey(), sort.getValue() == "asc"); + List result = query.execute(context); + + if (result.isEmpty()) + return null; + return result.get(0); + } + + public T first() throws CoreException { + return createProxy(context, proxyClass, firstMendixObject()); + } + + /** + * Given a set of attribute names and values, tries to find the first object + * that matches all conditions, or creates one + * + * @param keysAndValues + * @return + * @throws CoreException + */ + public T findOrCreateNoCommit(Object... keysAndValues) throws CoreException { + T res = findFirst(keysAndValues); + + return res != null ? res : constructInstance(false, keysAndValues); + } + + public T findOrCreate(Object... keysAndValues) throws CoreException { + T res = findFirst(keysAndValues); + + return res != null ? res : constructInstance(true, keysAndValues); + + } + + public T findOrCreateSynchronized(Object... keysAndValues) throws CoreException, InterruptedException { + T res = findFirst(keysAndValues); + + if (res != null) { + return res; + } else { + synchronized (Core.getMetaObject(entity)) { + IContext synchronizedContext = context.getSession().createContext().createSudoClone(); + try { + synchronizedContext.startTransaction(); + res = createProxy(synchronizedContext, proxyClass, + XPath.create(synchronizedContext, entity).findOrCreate(keysAndValues)); + synchronizedContext.endTransaction(); + return res; + } catch (CoreException e) { + if (synchronizedContext.isInTransaction()) { + synchronizedContext.rollbackTransaction(); + } + throw e; + } + } + } + } + + public T findFirst(Object... keysAndValues) + throws IllegalStateException, CoreException { + if (builder.length() > 0) + throw new IllegalStateException("FindFirst can only be used on XPath which do not have constraints already"); + + assertEven(keysAndValues); + for (int i = 0; i < keysAndValues.length; i += 2) + eq(keysAndValues[i], keysAndValues[i + 1]); + + return first(); + } + + /** + * Creates one instance of the type of this XPath query, and initializes the + * provided attributes to the provided values. + * + * @param keysAndValues AttributeName, AttributeValue, AttributeName2, + * AttributeValue2... list. + * @return + * @throws CoreException + */ + public T constructInstance(boolean autoCommit, Object... keysAndValues) throws CoreException { + assertEven(keysAndValues); + IMendixObject newObj = Core.instantiate(context, entity); + + for (int i = 0; i < keysAndValues.length; i += 2) + newObj.setValue(context, String.valueOf(keysAndValues[i]), toMemberValue(keysAndValues[i + 1])); + + if (autoCommit) + Core.commit(context, newObj); + + return createProxy(context, proxyClass, newObj); + } + + /** + * Given a current collection of primitive values, checks if for each value in + * the collection an object in the database exists. + * It creates a new object if needed, and removes any superfluos objects in the + * database that are no longer in the collection. + * + * @param currentCollection The collection that act as reference for the + * objects that should be in this database in the + * end. + * @param comparisonAttribute The attribute that should store the value as + * decribed in the collection + * @param autoDelete Automatically remove any superfluous objects form + * the database + * @param keysAndValues Constraints that should hold for the set of + * objects that are deleted or created. Objects + * outside this constraint are not processed. + * + * @return A pair of lists. The first list contains the newly created objects, + * the second list contains the objects that (should be or are) removed. + * @throws CoreException + */ + public ImmutablePair, List> syncDatabaseWithCollection(Collection currentCollection, + Object comparisonAttribute, boolean autoDelete, Object... keysAndValues) throws CoreException { + if (builder.length() > 0) + throw new IllegalStateException( + "syncDatabaseWithCollection can only be used on XPath which do not have constraints already"); + + List added = new ArrayList(); + List removed = new ArrayList(); + + Set col = new HashSet(currentCollection); + + for (int i = 0; i < keysAndValues.length; i += 2) + eq(keysAndValues[i], keysAndValues[i + 1]); + + for (IMendixObject existingItem : allMendixObjects()) { + // Item is still available + if (col.remove(existingItem.getValue(context, String.valueOf(comparisonAttribute)))) + continue; + + // No longer available + removed.add(createProxy(context, proxyClass, existingItem)); + if (autoDelete) + Core.delete(context, existingItem); + } + + // Some items where not found in the database + for (U value : col) { + + // In apache lang3, this would just be: ArrayUtils.addAll(keysAndValues, + // comparisonAttribute, value) + Object[] args = new Object[keysAndValues.length + 2]; + for (int i = 0; i < keysAndValues.length; i++) + args[i] = keysAndValues[i]; + args[keysAndValues.length] = comparisonAttribute; + args[keysAndValues.length + 1] = value; + + T newItem = constructInstance(true, args); + added.add(newItem); + } + + // Oké, stupid, Pair is also only available in apache lang3, so lets use a + // simple pair implementation for now + return ImmutablePair.of(added, removed); + } + + public T firstOrWait(long timeoutMSecs) throws CoreException, InterruptedException { + IMendixObject result = null; + + long start = System.currentTimeMillis(); + int sleepamount = 200; + int loopcount = 0; + + while (result == null) { + loopcount += 1; + result = firstMendixObject(); + + long now = System.currentTimeMillis(); + + if (start + timeoutMSecs < now) // Time expired + break; + + if (loopcount % 5 == 0) + sleepamount = (int)(sleepamount * 1.5); + + // not expired, wait a bit + if (result == null) + Thread.sleep(sleepamount); + } + + return createProxy(context, proxyClass, result); + } + + public List allMendixObjects() throws CoreException { + assertEmptyStack(); + + XPathQuery query = (XPathQuery) Core.createXPathQuery(getXPath()).setAmount(limit).setOffset(offset); + for (Map.Entry sort : sorting.entrySet()) + query.addSort(sort.getKey(), sort.getValue() == "asc"); + return query.execute(context); + } + + public List all() throws CoreException { + List res = new ArrayList(); + for (IMendixObject o : allMendixObjects()) + res.add(createProxy(context, proxyClass, o)); + + return res; + } + + @Override + public String toString() { + return getXPath(); + } + + /* Static utility functions */ + + // Cache for proxy constructors. Reflection is slow, so reuse as much as + // possible + private static Map initializers = new HashMap(); + + public static List createProxyList(IContext c, Class proxieClass, List objects) { + List res = new ArrayList(); + if (objects == null || objects.size() == 0) + return res; + + for (IMendixObject o : objects) + res.add(createProxy(c, proxieClass, o)); + + return res; + } + + public static T createProxy(IContext c, Class proxieClass, IMendixObject object) { + // Borrowed from nl.mweststrate.pages.MxQ package + + if (object == null) + return null; + + if (c == null || proxieClass == null) + throw new IllegalArgumentException("[CreateProxy] No context or proxieClass provided. "); + + // jeuj, we expect IMendixObject's. Thats nice.. + if (proxieClass == IMendixObject.class) + return proxieClass.cast(object); // .. since we can do a direct cast + + try { + String entityType = object.getType(); + + if (!initializers.containsKey(entityType)) { + + String[] entType = object.getType().split("\\."); + Class realClass = Class.forName(entType[0].toLowerCase() + ".proxies." + entType[1]); + + initializers.put(entityType, realClass.getMethod("initialize", IContext.class, IMendixObject.class)); + } + + // find constructor + Method m = initializers.get(entityType); + + // create proxy object + Object result = m.invoke(null, c, object); + + // cast, but check first is needed because the actual type might be a subclass + // of the requested type + if (!proxieClass.isAssignableFrom(result.getClass())) + throw new IllegalArgumentException("The type of the object ('" + object.getType() + + "') is not (a subclass) of '" + proxieClass.getName() + "'"); + + T proxie = proxieClass.cast(result); + return proxie; + } catch (Exception e) { + throw new RuntimeException("Unable to instantiate proxie: " + e.getMessage(), e); + } + } + + public static String valueToXPathValue(Object value) { + if (value == null) + return NULL; + + // Complex objects + if (value instanceof IMendixIdentifier) + return "'" + String.valueOf(((IMendixIdentifier) value).toLong()) + "'"; + if (value instanceof IMendixObject) + return valueToXPathValue(((IMendixObject) value).getId()); + if (value instanceof List) + throw new IllegalArgumentException("List based values are not supported!"); + + // Primitives + if (value instanceof Date) + return String.valueOf(((Date) value).getTime()); + if (value instanceof Long || value instanceof Integer) + return String.valueOf(value); + if (value instanceof Double || value instanceof Float) { + // make sure xpath understands our number formatting + NumberFormat format = NumberFormat.getNumberInstance(Locale.ENGLISH); + format.setMaximumFractionDigits(10); + format.setGroupingUsed(false); + return format.format(value); + } + if (value instanceof Boolean) { + return value.toString() + "()"; // xpath boolean, you know.. + } + if (value instanceof String) { + return "'" + ESCAPE_XML.translate(String.valueOf(value)) + "'"; + } + + // Object, assume its a proxy and deproxiefy + try { + IMendixObject mo = proxyToMendixObject(value); + return valueToXPathValue(mo); + } catch (NoSuchMethodException e) { + // This is O.K. just not a proxy object... + } catch (Exception e) { + throw new RuntimeException("Failed to retrieve MendixObject from proxy: " + e.getMessage(), e); + } + + // assume some string representation + return "'" + ESCAPE_XML.translate(String.valueOf(value)) + "'"; + } + + public static IMendixObject proxyToMendixObject(Object value) + throws NoSuchMethodException, SecurityException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException { + Method m = value.getClass().getMethod("getMendixObject"); + IMendixObject mo = (IMendixObject) m.invoke(value); + return mo; + } + + public static List proxyListToMendixObjectList( + List objects) throws SecurityException, IllegalArgumentException, NoSuchMethodException, + IllegalAccessException, InvocationTargetException { + ArrayList res = new ArrayList(objects.size()); + for (T i : objects) + res.add(proxyToMendixObject(i)); + return res; + } + + public static Object toMemberValue(Object value) { + if (value == null) + return null; + + // Complex objects + if (value instanceof IMendixIdentifier) + return value; + if (value instanceof IMendixObject) + return ((IMendixObject) value).getId(); + + if (value instanceof List) + throw new IllegalArgumentException("List based values are not supported!"); + + // Primitives + if (value instanceof Date + || value instanceof Long + || value instanceof Integer + || value instanceof Double + || value instanceof Float + || value instanceof Boolean + || value instanceof String) { + return value; + } + + if (value.getClass().isEnum()) + return value.toString(); + + // Object, assume its a proxy and deproxiefy + try { + Method m = value.getClass().getMethod("getMendixObject"); + IMendixObject mo = (IMendixObject) m.invoke(value); + return toMemberValue(mo); + } catch (NoSuchMethodException e) { + // This is O.K. just not a proxy object... + } catch (Exception e) { + throw new RuntimeException( + "Failed to convert object to IMendixMember compatible value '" + value + "': " + e.getMessage(), e); + } + + throw new RuntimeException("Failed to convert object to IMendixMember compatible value: " + value); + } + + public static interface IBatchProcessor { + public void onItem(T item, long offset, long total) throws Exception; + } + + private static final class ParallelJobRunner implements Callable { + private final XPath self; + private final IBatchProcessor batchProcessor; + private final IMendixObject item; + private long index; + private long count; + + ParallelJobRunner(XPath self, IBatchProcessor batchProcessor, IMendixObject item, long index, long count) { + this.self = self; + this.batchProcessor = batchProcessor; + this.item = item; + this.index = index; + this.count = count; + } + + @Override + public Boolean call() { + try { + batchProcessor.onItem(XPath.createProxy(Core.createSystemContext(), self.proxyClass, item), index, count); + return true; + } catch (Exception e) { + throw new RuntimeException(String.format("Failed to execute batch on '%s' offset %d: %s", self.toString(), + self.offset, e.getMessage()), e); + } + } + } + + /** + * Retreives all items in this xpath query in batches of a limited size. + * Not that this function does not start a new transaction for all the batches, + * rather, it just limits the number of objects being retrieved and kept in + * memory at the same time. + * + * So it only batches the retrieve process, not the optional manipulations done + * in the onItem method. + * + * @param batchsize + * @param batchProcessor + * @throws CoreException + */ + public void batch(int batchsize, IBatchProcessor batchProcessor) throws CoreException { + if (sorting.isEmpty()) + addSortingAsc(XPath.ID); + + final long itemcount = count(); + + int baseoffset = offset; + int baselimit = limit; + + boolean useBaseLimit = baselimit > -1; + + offset(baseoffset); + List data; + + long i = 0; + + do { + int newlimit = useBaseLimit ? Math.min(batchsize, baseoffset + baselimit - offset) : batchsize; + if (newlimit == 0) + break; // where done, no more data is needed + + limit(newlimit); + data = all(); + + for (T item : data) { + i += 1; + try { + batchProcessor.onItem(item, i, Math.max(i, itemcount)); + } catch (Exception e) { + throw new RuntimeException(String.format("Failed to execute batch on '%s' offset %d: %s", this, + offset, e.getMessage()), e); + } + } + + offset(offset + data.size()); + } while (data.size() > 0); + } + + /** + * Batch with parallelization. + * + * IMPORTANT NOTE: DO NOT USE THE CONTEXT OF THE XPATH OBJECT ITSELF INSIDE THE + * BATCH PROCESSOR! + * + * Instead, use: Item.getContext(); !! + * + * + * @param batchsize + * @param threads + * @param batchProcessor + * @throws CoreException + * @throws InterruptedException + * @throws ExecutionException + */ + public void batch(int batchsize, int threads, final IBatchProcessor batchProcessor) + throws CoreException, InterruptedException, ExecutionException { + if (sorting.isEmpty()) + addSortingAsc(XPath.ID); + + ExecutorService pool = Executors.newFixedThreadPool(threads); + + final long itemcount = count(); + + int progress = 0; + List> futures = new ArrayList>(batchsize); // no need to synchronize + + offset(0); + limit(batchsize); + + List data = allMendixObjects(); + + while (data.size() > 0) { + for (final IMendixObject item : data) { + futures.add(pool.submit(new ParallelJobRunner(this, batchProcessor, item, progress, itemcount))); + progress += 1; + } + + while (!futures.isEmpty()) + futures.remove(0).get(); // wait for all futures before proceeding to next iteration + + offset(offset + data.size()); + data = allMendixObjects(); + } + + if (pool.shutdownNow().size() > 0) + throw new IllegalStateException("Not all tasks where finished!"); + } + + public static Class getProxyClassForEntityName(String entityname) { + { + String[] parts = entityname.split("\\."); + try { + return Class.forName(parts[0].toLowerCase() + ".proxies." + parts[1]); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Cannot find class for entity: " + entityname + ": " + e.getMessage(), e); + } + } + } + + public boolean deleteAll() throws CoreException { + limit(1000); + List objs = allMendixObjects(); + while (!objs.isEmpty()) { + if (!Core.delete(context, objs.toArray(new IMendixObject[objs.size()]))) + return false; // TODO: throw? + + objs = allMendixObjects(); + } + return true; + } + + // Implement our own ESCAPE_XML because the original got deprecated and we + // originally translated only a very small + // subset of characters. + private static final CharSequenceTranslator ESCAPE_XML = new AggregateTranslator( + new LookupTranslator(EntityArrays.BASIC_ESCAPE), + new LookupTranslator(EntityArrays.APOS_ESCAPE)); +} diff --git a/Source/javasource/communitycommons/actions/Base64Decode.java b/Source/javasource/communitycommons/actions/Base64Decode.java index fbf08879..e3e60ad4 100644 --- a/Source/javasource/communitycommons/actions/Base64Decode.java +++ b/Source/javasource/communitycommons/actions/Base64Decode.java @@ -11,12 +11,12 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Converts a base64 encoded string to the plain, original string */ -public class Base64Decode extends CustomJavaAction +public class Base64Decode extends UserAction { private final java.lang.String encoded; diff --git a/Source/javasource/communitycommons/actions/Base64DecodeToFile.java b/Source/javasource/communitycommons/actions/Base64DecodeToFile.java index f87a5d79..96e0c51e 100644 --- a/Source/javasource/communitycommons/actions/Base64DecodeToFile.java +++ b/Source/javasource/communitycommons/actions/Base64DecodeToFile.java @@ -12,14 +12,14 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Stores an base 64 encoded string plain in the provided target file document * * Note that targetFile will be committed. */ -public class Base64DecodeToFile extends CustomJavaAction +public class Base64DecodeToFile extends UserAction { private final java.lang.String encoded; /** @deprecated use targetFile.getMendixObject() instead. */ diff --git a/Source/javasource/communitycommons/actions/Base64Encode.java b/Source/javasource/communitycommons/actions/Base64Encode.java index 2e69dc99..e7f89b96 100644 --- a/Source/javasource/communitycommons/actions/Base64Encode.java +++ b/Source/javasource/communitycommons/actions/Base64Encode.java @@ -11,12 +11,12 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Converts a plain string to a base64 encoded string */ -public class Base64Encode extends CustomJavaAction +public class Base64Encode extends UserAction { private final java.lang.String value; diff --git a/Source/javasource/communitycommons/actions/Base64EncodeFile.java b/Source/javasource/communitycommons/actions/Base64EncodeFile.java index a0d39c8f..3fb6d3e6 100644 --- a/Source/javasource/communitycommons/actions/Base64EncodeFile.java +++ b/Source/javasource/communitycommons/actions/Base64EncodeFile.java @@ -12,12 +12,12 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Converts an unencoded file to a base 64 encoded string. */ -public class Base64EncodeFile extends CustomJavaAction +public class Base64EncodeFile extends UserAction { /** @deprecated use file.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/communitycommons/actions/Clone.java b/Source/javasource/communitycommons/actions/Clone.java index 1ad4bc76..9f3a9196 100644 --- a/Source/javasource/communitycommons/actions/Clone.java +++ b/Source/javasource/communitycommons/actions/Clone.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Clones objects @@ -23,7 +23,7 @@ * * If associated objects need to be cloned as well, use deepClone, this function only copies the references, not the reffered objects. Target is not committed automatically. */ -public class Clone extends CustomJavaAction +public class Clone extends UserAction { private final IMendixObject source; private final IMendixObject target; diff --git a/Source/javasource/communitycommons/actions/CreateLogNode.java b/Source/javasource/communitycommons/actions/CreateLogNode.java index 1105e3e2..2506ceb8 100644 --- a/Source/javasource/communitycommons/actions/CreateLogNode.java +++ b/Source/javasource/communitycommons/actions/CreateLogNode.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Logging; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Initializes a log node for later use. Useful to set logging to a more detailed log level before the first time a certain log action is executed. */ -public class CreateLogNode extends CustomJavaAction +public class CreateLogNode extends UserAction { private final java.lang.String logNodeParameter; diff --git a/Source/javasource/communitycommons/actions/DateTimeToLong.java b/Source/javasource/communitycommons/actions/DateTimeToLong.java index 36ee960d..a44fc752 100644 --- a/Source/javasource/communitycommons/actions/DateTimeToLong.java +++ b/Source/javasource/communitycommons/actions/DateTimeToLong.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.DateTime; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Converts a DateTime to a Unix timestamps. (Milliseconds since 1-1-1970) */ -public class DateTimeToLong extends CustomJavaAction +public class DateTimeToLong extends UserAction { private final java.util.Date dateObject; diff --git a/Source/javasource/communitycommons/actions/DeepClone.java b/Source/javasource/communitycommons/actions/DeepClone.java index 5a547961..0c47ddb8 100644 --- a/Source/javasource/communitycommons/actions/DeepClone.java +++ b/Source/javasource/communitycommons/actions/DeepClone.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Clones objects, their associations and even referred objects. @@ -35,7 +35,7 @@ * * Note that DeepClone does commit all objects, where Clone does not. */ -public class DeepClone extends CustomJavaAction +public class DeepClone extends UserAction { private final IMendixObject source; private final IMendixObject target; diff --git a/Source/javasource/communitycommons/actions/Delay.java b/Source/javasource/communitycommons/actions/Delay.java index 733b54dc..e23adf49 100644 --- a/Source/javasource/communitycommons/actions/Delay.java +++ b/Source/javasource/communitycommons/actions/Delay.java @@ -11,14 +11,14 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Causes this request to sleep for a while. Useful to prevent brute force attacks or to simulate latency delays. * * Delaytime : time in ms */ -public class Delay extends CustomJavaAction +public class Delay extends UserAction { private final java.lang.Long delaytime; diff --git a/Source/javasource/communitycommons/actions/DuplicateFileDocument.java b/Source/javasource/communitycommons/actions/DuplicateFileDocument.java index 301b279b..7a9beb57 100644 --- a/Source/javasource/communitycommons/actions/DuplicateFileDocument.java +++ b/Source/javasource/communitycommons/actions/DuplicateFileDocument.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Clones the contents of one file document into another. @@ -22,7 +22,7 @@ * Returns true if copied, returns file if the source had no contents, throws exception in any other case. * Pre condition: HasContents of the 'fileToClone' need to be set to true, otherwise the action will not copy anything. */ -public class DuplicateFileDocument extends CustomJavaAction +public class DuplicateFileDocument extends UserAction { /** @deprecated use fileToClone.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/communitycommons/actions/DuplicateImageDocument.java b/Source/javasource/communitycommons/actions/DuplicateImageDocument.java index 1cfd9fd7..f62c1563 100644 --- a/Source/javasource/communitycommons/actions/DuplicateImageDocument.java +++ b/Source/javasource/communitycommons/actions/DuplicateImageDocument.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Clones the contents of one image document into another, and generates a thumbnail as well. @@ -22,7 +22,7 @@ * Returns true if copied, returns file if the source had no contents, throws exception in any other case. * Pre condition: HasContents of the 'fileToClone' need to be set to true, otherwise the action will not copy anything. */ -public class DuplicateImageDocument extends CustomJavaAction +public class DuplicateImageDocument extends UserAction { /** @deprecated use fileToClone.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/communitycommons/actions/EndTransaction.java b/Source/javasource/communitycommons/actions/EndTransaction.java index f120fcf6..5b2d0f7c 100644 --- a/Source/javasource/communitycommons/actions/EndTransaction.java +++ b/Source/javasource/communitycommons/actions/EndTransaction.java @@ -10,12 +10,12 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Commit the transaction, this will end this transaction or remove a save point from the queue if the transaction is nested */ -public class EndTransaction extends CustomJavaAction +public class EndTransaction extends UserAction { public EndTransaction(IContext context) { diff --git a/Source/javasource/communitycommons/actions/EnumerationFromString.java b/Source/javasource/communitycommons/actions/EnumerationFromString.java index 80164655..9a9aacd3 100644 --- a/Source/javasource/communitycommons/actions/EnumerationFromString.java +++ b/Source/javasource/communitycommons/actions/EnumerationFromString.java @@ -10,17 +10,17 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; import communitycommons.proxies.LogLevel; import java.util.Optional; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Use this Java action as a template for your own String-to-Enumeration conversions. * Studio Pro requires specifying the exact Enumeration to return in the definition of a Java action so we cannot provide a generic implementation. * This implementation will throw a NoSuchElementException if an invalid toConvert parameter is given, so remember to handle this error gracefully. */ -public class EnumerationFromString extends CustomJavaAction +public class EnumerationFromString extends UserAction { private final java.lang.String toConvert; diff --git a/Source/javasource/communitycommons/actions/EscapeHTML.java b/Source/javasource/communitycommons/actions/EscapeHTML.java index 3e5dc7db..6c3ecbe7 100644 --- a/Source/javasource/communitycommons/actions/EscapeHTML.java +++ b/Source/javasource/communitycommons/actions/EscapeHTML.java @@ -10,8 +10,8 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Given a, escapes it to html codes, for example @@ -19,7 +19,7 @@ * "< Joe & John >" will be converted to * "< Joe & John >" */ -public class EscapeHTML extends CustomJavaAction +public class EscapeHTML extends UserAction { private final java.lang.String rawString; diff --git a/Source/javasource/communitycommons/actions/FileDocumentFromFile.java b/Source/javasource/communitycommons/actions/FileDocumentFromFile.java index 143e1d94..337eed04 100644 --- a/Source/javasource/communitycommons/actions/FileDocumentFromFile.java +++ b/Source/javasource/communitycommons/actions/FileDocumentFromFile.java @@ -13,13 +13,13 @@ import java.io.FileInputStream; import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Loads a file from the local (server) storage and stores it inside a FileDocument. */ -public class FileDocumentFromFile extends CustomJavaAction +public class FileDocumentFromFile extends UserAction { private final java.lang.String file; /** @deprecated use fileDocument.getMendixObject() instead. */ diff --git a/Source/javasource/communitycommons/actions/FileFromFileDocument.java b/Source/javasource/communitycommons/actions/FileFromFileDocument.java index 042f1e58..59b22637 100644 --- a/Source/javasource/communitycommons/actions/FileFromFileDocument.java +++ b/Source/javasource/communitycommons/actions/FileFromFileDocument.java @@ -15,13 +15,13 @@ import org.apache.commons.io.IOUtils; import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Reads contents from a FileDocument and stores it in a file on the local (server) storage. */ -public class FileFromFileDocument extends CustomJavaAction +public class FileFromFileDocument extends UserAction { private final java.lang.String targetFile; /** @deprecated use fileDocument.getMendixObject() instead. */ diff --git a/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256.java b/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256.java index 3c01fcfb..75b7e3e0 100644 --- a/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256.java +++ b/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Generates and asymmetric hexadecimal hash using the HMAC_SHA256 hash algorithm */ -public class GenerateHMAC_SHA256 extends CustomJavaAction +public class GenerateHMAC_SHA256 extends UserAction { private final java.lang.String key; private final java.lang.String valueToEncrypt; diff --git a/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256_hash.java b/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256_hash.java index fec9b15c..b889a7de 100644 --- a/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256_hash.java +++ b/Source/javasource/communitycommons/actions/GenerateHMAC_SHA256_hash.java @@ -11,12 +11,12 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Generates an asymmetric hash using the HMAC_SHA256 hash algorithm */ -public class GenerateHMAC_SHA256_hash extends CustomJavaAction +public class GenerateHMAC_SHA256_hash extends UserAction { private final java.lang.String key; private final java.lang.String valueToEncrypt; diff --git a/Source/javasource/communitycommons/actions/GetApplicationUrl.java b/Source/javasource/communitycommons/actions/GetApplicationUrl.java index ab61b183..8f9c68e0 100644 --- a/Source/javasource/communitycommons/actions/GetApplicationUrl.java +++ b/Source/javasource/communitycommons/actions/GetApplicationUrl.java @@ -11,12 +11,12 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the runtime URL of this application. */ -public class GetApplicationUrl extends CustomJavaAction +public class GetApplicationUrl extends UserAction { public GetApplicationUrl(IContext context) { diff --git a/Source/javasource/communitycommons/actions/GetCFInstanceIndex.java b/Source/javasource/communitycommons/actions/GetCFInstanceIndex.java index 9181ae27..fd5b3ff6 100644 --- a/Source/javasource/communitycommons/actions/GetCFInstanceIndex.java +++ b/Source/javasource/communitycommons/actions/GetCFInstanceIndex.java @@ -10,8 +10,8 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the Cloud Foundry Instance Index that is set during deployment of the application in a Cloud native environment. Based on the Cloud Foundry Instance Index, Mendix determines what is the leader instance (index 0 executes scheduled events, db sync, session management etc.) or slave instance. @@ -20,7 +20,7 @@ * * Make sure emulate cloud security is disabled. Otherwise, the policy restrictions will prevent the method to be executed. Action is tested in Mendix Cloud on 19-12-2018. */ -public class GetCFInstanceIndex extends CustomJavaAction +public class GetCFInstanceIndex extends UserAction { public GetCFInstanceIndex(IContext context) { diff --git a/Source/javasource/communitycommons/actions/GetDefaultLanguage.java b/Source/javasource/communitycommons/actions/GetDefaultLanguage.java index 52c54a9e..4dbca97c 100644 --- a/Source/javasource/communitycommons/actions/GetDefaultLanguage.java +++ b/Source/javasource/communitycommons/actions/GetDefaultLanguage.java @@ -11,14 +11,14 @@ import system.proxies.Language; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Get default language */ -public class GetDefaultLanguage extends CustomJavaAction +public class GetDefaultLanguage extends UserAction { public GetDefaultLanguage(IContext context) { diff --git a/Source/javasource/communitycommons/actions/GetFileContentsFromResource.java b/Source/javasource/communitycommons/actions/GetFileContentsFromResource.java index ea41c8e9..d05566af 100644 --- a/Source/javasource/communitycommons/actions/GetFileContentsFromResource.java +++ b/Source/javasource/communitycommons/actions/GetFileContentsFromResource.java @@ -13,13 +13,13 @@ import java.io.FileInputStream; import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Set the contents of a FileDocument with the contents of a file which is a resource. */ -public class GetFileContentsFromResource extends CustomJavaAction +public class GetFileContentsFromResource extends UserAction { private final java.lang.String filename; /** @deprecated use fileDocument.getMendixObject() instead. */ diff --git a/Source/javasource/communitycommons/actions/GetImageDimensions.java b/Source/javasource/communitycommons/actions/GetImageDimensions.java index 44134fce..ee173f1e 100644 --- a/Source/javasource/communitycommons/actions/GetImageDimensions.java +++ b/Source/javasource/communitycommons/actions/GetImageDimensions.java @@ -14,11 +14,11 @@ import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; import communitycommons.proxies.ImageDimensions; import java.io.InputStream; +import com.mendix.systemwideinterfaces.core.UserAction; -public class GetImageDimensions extends CustomJavaAction +public class GetImageDimensions extends UserAction { /** @deprecated use ImageParameter.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) @@ -42,8 +42,10 @@ public IMendixObject executeAction() throws Exception ImageDimensions imageDimensions = new ImageDimensions(getContext()); try (InputStream inputStream = Core.getImage(getContext(), this.ImageParameter.getMendixObject(), false)) { BufferedImage bimg = ImageIO.read(inputStream); - imageDimensions.setHeight(bimg.getHeight()); - imageDimensions.setWidth(bimg.getWidth()); + if (bimg != null) { + imageDimensions.setHeight(bimg.getHeight()); + imageDimensions.setWidth(bimg.getWidth()); + } } return imageDimensions.getMendixObject(); diff --git a/Source/javasource/communitycommons/actions/GetIntFromDateTime.java b/Source/javasource/communitycommons/actions/GetIntFromDateTime.java index ad59f3d0..c03b41ff 100644 --- a/Source/javasource/communitycommons/actions/GetIntFromDateTime.java +++ b/Source/javasource/communitycommons/actions/GetIntFromDateTime.java @@ -10,8 +10,8 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.DateTime; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Converts a datetime to an integer based on the selector used. @@ -21,7 +21,7 @@ * - month (returns 1-12) * - day (returns 1-31) */ -public class GetIntFromDateTime extends CustomJavaAction +public class GetIntFromDateTime extends UserAction { private final java.util.Date dateObj; private final communitycommons.proxies.DatePartSelector selectorObj; diff --git a/Source/javasource/communitycommons/actions/GetModelVersion.java b/Source/javasource/communitycommons/actions/GetModelVersion.java index d9894816..abf7637e 100644 --- a/Source/javasource/communitycommons/actions/GetModelVersion.java +++ b/Source/javasource/communitycommons/actions/GetModelVersion.java @@ -9,14 +9,14 @@ package communitycommons.actions; +import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; -import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the model version of the deployed application. */ -public class GetModelVersion extends CustomJavaAction +public class GetModelVersion extends UserAction { public GetModelVersion(IContext context) { @@ -27,7 +27,7 @@ public GetModelVersion(IContext context) public java.lang.String executeAction() throws Exception { // BEGIN USER CODE - return Misc.getModelVersion(); + return Core.getModelVersion(); // END USER CODE } diff --git a/Source/javasource/communitycommons/actions/GetRuntimeVersion.java b/Source/javasource/communitycommons/actions/GetRuntimeVersion.java index e36291e4..51d7b9ba 100644 --- a/Source/javasource/communitycommons/actions/GetRuntimeVersion.java +++ b/Source/javasource/communitycommons/actions/GetRuntimeVersion.java @@ -9,14 +9,14 @@ package communitycommons.actions; -import communitycommons.Misc; +import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the runtime version of this application. */ -public class GetRuntimeVersion extends CustomJavaAction +public class GetRuntimeVersion extends UserAction { public GetRuntimeVersion(IContext context) { @@ -27,7 +27,7 @@ public GetRuntimeVersion(IContext context) public java.lang.String executeAction() throws Exception { // BEGIN USER CODE - return Misc.getRuntimeVersion(); + return Core.getRuntimeVersion(); // END USER CODE } diff --git a/Source/javasource/communitycommons/actions/HTMLEncode.java b/Source/javasource/communitycommons/actions/HTMLEncode.java index b63e002d..d41d0ceb 100644 --- a/Source/javasource/communitycommons/actions/HTMLEncode.java +++ b/Source/javasource/communitycommons/actions/HTMLEncode.java @@ -11,7 +11,7 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Encodes a string to HTML Entities, so that they can be displayed in the browser without breaking any layout. @@ -21,7 +21,7 @@ * * Returns the encoded string. */ -public class HTMLEncode extends CustomJavaAction +public class HTMLEncode extends UserAction { private final java.lang.String value; diff --git a/Source/javasource/communitycommons/actions/HTMLToPlainText.java b/Source/javasource/communitycommons/actions/HTMLToPlainText.java index 11d21ac4..17927e8a 100644 --- a/Source/javasource/communitycommons/actions/HTMLToPlainText.java +++ b/Source/javasource/communitycommons/actions/HTMLToPlainText.java @@ -11,13 +11,13 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Use this function to convert HTML text to plain text. * It will preserve linebreaks but strip all other markup. including html entity decoding. */ -public class HTMLToPlainText extends CustomJavaAction +public class HTMLToPlainText extends UserAction { private final java.lang.String html; diff --git a/Source/javasource/communitycommons/actions/Hash.java b/Source/javasource/communitycommons/actions/Hash.java index 93954ea1..140cee38 100644 --- a/Source/javasource/communitycommons/actions/Hash.java +++ b/Source/javasource/communitycommons/actions/Hash.java @@ -11,17 +11,16 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Hashes a value using the SHA-256 hash algorithm. * * - value : the value to hash - * - length : the desired length of the hash. * - * Returns a SHA-256 hash of 'value', with length 'length' + * Returns a SHA-256 hash of 'value' */ -public class Hash extends CustomJavaAction +public class Hash extends UserAction { private final java.lang.String value; private final java.lang.Long length; @@ -41,7 +40,7 @@ public Hash( public java.lang.String executeAction() throws Exception { // BEGIN USER CODE - return StringUtils.hash(value, length.intValue()); + return StringUtils.hash(value); // END USER CODE } diff --git a/Source/javasource/communitycommons/actions/IsInDevelopment.java b/Source/javasource/communitycommons/actions/IsInDevelopment.java index 51ea6a54..33002ecc 100644 --- a/Source/javasource/communitycommons/actions/IsInDevelopment.java +++ b/Source/javasource/communitycommons/actions/IsInDevelopment.java @@ -11,12 +11,12 @@ import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns true if the environment is a development environment. Calls Core.getConfiguration().isInDevelopment(). */ -public class IsInDevelopment extends CustomJavaAction +public class IsInDevelopment extends UserAction { public IsInDevelopment(IContext context) { diff --git a/Source/javasource/communitycommons/actions/IsStringSimplified.java b/Source/javasource/communitycommons/actions/IsStringSimplified.java index d863041f..7fd91023 100644 --- a/Source/javasource/communitycommons/actions/IsStringSimplified.java +++ b/Source/javasource/communitycommons/actions/IsStringSimplified.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * True if a string can be simplified by the removal of diacritics. */ -public class IsStringSimplified extends CustomJavaAction +public class IsStringSimplified extends UserAction { private final java.lang.String value; diff --git a/Source/javasource/communitycommons/actions/ListTop.java b/Source/javasource/communitycommons/actions/ListTop.java index 533ed9d1..b0725c8a 100644 --- a/Source/javasource/communitycommons/actions/ListTop.java +++ b/Source/javasource/communitycommons/actions/ListTop.java @@ -11,13 +11,13 @@ import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Takes the top n items of a given list and returns the resulting list. */ -public class ListTop extends CustomJavaAction> +public class ListTop extends UserAction> { private final java.util.List ObjectList; private final java.lang.Long Top; diff --git a/Source/javasource/communitycommons/actions/LongToDateTime.java b/Source/javasource/communitycommons/actions/LongToDateTime.java index 18f9072a..3f1e103c 100644 --- a/Source/javasource/communitycommons/actions/LongToDateTime.java +++ b/Source/javasource/communitycommons/actions/LongToDateTime.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.DateTime; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Converts a Unix timestamp to a dateTime object */ -public class LongToDateTime extends CustomJavaAction +public class LongToDateTime extends UserAction { private final java.lang.Long value; diff --git a/Source/javasource/communitycommons/actions/MergeMultiplePdfs.java b/Source/javasource/communitycommons/actions/MergeMultiplePdfs.java index f0ce142f..bd3757fd 100644 --- a/Source/javasource/communitycommons/actions/MergeMultiplePdfs.java +++ b/Source/javasource/communitycommons/actions/MergeMultiplePdfs.java @@ -11,13 +11,13 @@ import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Restricted to 10 files at once for Mendix Cloud v4 compatibility. If you need to merge more than 10 files at once merge recursively instead or change the MergeMultiplePdfs_MaxAtOnce constant. */ -public class MergeMultiplePdfs extends CustomJavaAction +public class MergeMultiplePdfs extends UserAction { /** @deprecated use com.mendix.utils.ListUtils.map(FilesToMerge, com.mendix.systemwideinterfaces.core.IEntityProxy::getMendixObject) instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/communitycommons/actions/MonthsBetween.java b/Source/javasource/communitycommons/actions/MonthsBetween.java index 60d98809..cba194eb 100644 --- a/Source/javasource/communitycommons/actions/MonthsBetween.java +++ b/Source/javasource/communitycommons/actions/MonthsBetween.java @@ -10,19 +10,19 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.DateTime; import communitycommons.Logging; import communitycommons.proxies.LogLevel; import communitycommons.proxies.LogNodes; import java.util.Date; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Calculates the number of months between two dates. * - dateTime : the original (oldest) dateTime * - compareDate: the second date. If EMPTY, the current datetime will be used. Effectively this means that the age of the dateTime is calculated. */ -public class MonthsBetween extends CustomJavaAction +public class MonthsBetween extends UserAction { private final java.util.Date date1; private final java.util.Date date2; diff --git a/Source/javasource/communitycommons/actions/OverlayPdfDocument.java b/Source/javasource/communitycommons/actions/OverlayPdfDocument.java index 7cfff3ea..d2cc4ef1 100644 --- a/Source/javasource/communitycommons/actions/OverlayPdfDocument.java +++ b/Source/javasource/communitycommons/actions/OverlayPdfDocument.java @@ -10,14 +10,14 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Overlay a generated PDF document with another PDF (containing the company stationary for example) */ -public class OverlayPdfDocument extends CustomJavaAction +public class OverlayPdfDocument extends UserAction { /** @deprecated use generatedDocument.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/communitycommons/actions/ParseDateTimeWithTimezone.java b/Source/javasource/communitycommons/actions/ParseDateTimeWithTimezone.java index 41525260..3383db57 100644 --- a/Source/javasource/communitycommons/actions/ParseDateTimeWithTimezone.java +++ b/Source/javasource/communitycommons/actions/ParseDateTimeWithTimezone.java @@ -12,17 +12,17 @@ import java.text.SimpleDateFormat; import java.util.TimeZone; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Logging; import communitycommons.proxies.LogLevel; import communitycommons.proxies.LogNodes; import java.text.ParseException; +import com.mendix.systemwideinterfaces.core.UserAction; /** * This method parses a date from a string with a given pattern according to a specific timezone. * The timezone has to be a valid timezone id http://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html (e.g. one of https://garygregory.wordpress.com/2013/06/18/what-are-the-java-timezone-ids/) */ -public class ParseDateTimeWithTimezone extends CustomJavaAction +public class ParseDateTimeWithTimezone extends UserAction { private final java.lang.String date; private final java.lang.String pattern; diff --git a/Source/javasource/communitycommons/actions/RandomHash.java b/Source/javasource/communitycommons/actions/RandomHash.java index 06470354..788844f7 100644 --- a/Source/javasource/communitycommons/actions/RandomHash.java +++ b/Source/javasource/communitycommons/actions/RandomHash.java @@ -11,12 +11,12 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Generates a random hash, perfectly to use as random but unique identifier */ -public class RandomHash extends CustomJavaAction +public class RandomHash extends UserAction { public RandomHash(IContext context) { diff --git a/Source/javasource/communitycommons/actions/RandomString.java b/Source/javasource/communitycommons/actions/RandomString.java index af36b1d3..06e76444 100644 --- a/Source/javasource/communitycommons/actions/RandomString.java +++ b/Source/javasource/communitycommons/actions/RandomString.java @@ -11,12 +11,12 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Generates a random alphanumeric string of the desired length. */ -public class RandomString extends CustomJavaAction +public class RandomString extends UserAction { private final java.lang.Long length; diff --git a/Source/javasource/communitycommons/actions/RandomStrongPassword.java b/Source/javasource/communitycommons/actions/RandomStrongPassword.java index bf596f1b..8c8ef81c 100644 --- a/Source/javasource/communitycommons/actions/RandomStrongPassword.java +++ b/Source/javasource/communitycommons/actions/RandomStrongPassword.java @@ -10,20 +10,19 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns a random strong password containing a specified minimum number of digits, uppercase and special characters. * * Note:Minimumlength should be equal or larger than NrOfCapitalizedCharacters, NrOfDigits and NrOfSpecialCharacters */ -public class RandomStrongPassword extends CustomJavaAction +public class RandomStrongPassword extends UserAction { private final java.lang.Long MinLength; private final java.lang.Long MaxLength; private final java.lang.Long NrOfCapitalizedCharacters; - private final java.lang.Long NrOfLowercaseCharacters; private final java.lang.Long NrOfDigits; private final java.lang.Long NrOfSpecialCharacters; @@ -32,7 +31,6 @@ public RandomStrongPassword( java.lang.Long _minLength, java.lang.Long _maxLength, java.lang.Long _nrOfCapitalizedCharacters, - java.lang.Long _nrOfLowercaseCharacters, java.lang.Long _nrOfDigits, java.lang.Long _nrOfSpecialCharacters ) @@ -41,7 +39,6 @@ public RandomStrongPassword( this.MinLength = _minLength; this.MaxLength = _maxLength; this.NrOfCapitalizedCharacters = _nrOfCapitalizedCharacters; - this.NrOfLowercaseCharacters = _nrOfLowercaseCharacters; this.NrOfDigits = _nrOfDigits; this.NrOfSpecialCharacters = _nrOfSpecialCharacters; } @@ -54,7 +51,7 @@ public java.lang.String executeAction() throws Exception safeLongToInt(MinLength), safeLongToInt(MaxLength), safeLongToInt(NrOfCapitalizedCharacters), - safeLongToInt(NrOfLowercaseCharacters), + 0, safeLongToInt(NrOfDigits), safeLongToInt(NrOfSpecialCharacters) ); diff --git a/Source/javasource/communitycommons/actions/RandomStrongPasswordWithLowercase.java b/Source/javasource/communitycommons/actions/RandomStrongPasswordWithLowercase.java new file mode 100644 index 00000000..955cdf06 --- /dev/null +++ b/Source/javasource/communitycommons/actions/RandomStrongPasswordWithLowercase.java @@ -0,0 +1,83 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package communitycommons.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; + +/** + * Returns a random strong password containing a specified minimum number of digits, uppercase, lowercase and special characters. + * + * Note:Minimumlength should be equal or larger than NrOfCapitalizedCharacters, NrOfLowercaseCharacters, NrOfDigits and NrOfSpecialCharacters + */ +public class RandomStrongPasswordWithLowercase extends UserAction +{ + private final java.lang.Long MinLength; + private final java.lang.Long MaxLength; + private final java.lang.Long NrOfCapitalizedCharacters; + private final java.lang.Long NrOfLowercaseCharacters; + private final java.lang.Long NrOfDigits; + private final java.lang.Long NrOfSpecialCharacters; + + public RandomStrongPasswordWithLowercase( + IContext context, + java.lang.Long _minLength, + java.lang.Long _maxLength, + java.lang.Long _nrOfCapitalizedCharacters, + java.lang.Long _nrOfLowercaseCharacters, + java.lang.Long _nrOfDigits, + java.lang.Long _nrOfSpecialCharacters + ) + { + super(context); + this.MinLength = _minLength; + this.MaxLength = _maxLength; + this.NrOfCapitalizedCharacters = _nrOfCapitalizedCharacters; + this.NrOfLowercaseCharacters = _nrOfLowercaseCharacters; + this.NrOfDigits = _nrOfDigits; + this.NrOfSpecialCharacters = _nrOfSpecialCharacters; + } + + @java.lang.Override + public java.lang.String executeAction() throws Exception + { + // BEGIN USER CODE + return StringUtils.randomStrongPassword( + safeLongToInt(MinLength), + safeLongToInt(MaxLength), + safeLongToInt(NrOfCapitalizedCharacters), + safeLongToInt(NrOfLowercaseCharacters), + safeLongToInt(NrOfDigits), + safeLongToInt(NrOfSpecialCharacters) + ); + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "RandomStrongPasswordWithLowercase"; + } + + // BEGIN EXTRA CODE + public static int safeLongToInt(Long l) { + if (l == null) return 0; + if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { + throw new IllegalArgumentException(l + " cannot be cast to int without changing its value."); + } + return l.intValue(); + } + // END EXTRA CODE +} diff --git a/Source/javasource/communitycommons/actions/RegexQuote.java b/Source/javasource/communitycommons/actions/RegexQuote.java index 545de1e1..8ad891a0 100644 --- a/Source/javasource/communitycommons/actions/RegexQuote.java +++ b/Source/javasource/communitycommons/actions/RegexQuote.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Escapes a string value so that it can be used literally with Mendix build-in regex replacement functions. (Otherwise the dollar sign would be interpreted as back reference to a match for example). */ -public class RegexQuote extends CustomJavaAction +public class RegexQuote extends UserAction { private final java.lang.String unquotedLiteral; diff --git a/Source/javasource/communitycommons/actions/RegexReplaceAll.java b/Source/javasource/communitycommons/actions/RegexReplaceAll.java index 60e4c71f..b1bc81aa 100644 --- a/Source/javasource/communitycommons/actions/RegexReplaceAll.java +++ b/Source/javasource/communitycommons/actions/RegexReplaceAll.java @@ -11,7 +11,7 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Performs a regular expression. Similar to the replaceAll microflow function, but supports more advanced usages such as capture variables. @@ -22,7 +22,7 @@ * A decent regexp tester can be found at: * http://www.fileformat.info/tool/regex.htm */ -public class RegexReplaceAll extends CustomJavaAction +public class RegexReplaceAll extends UserAction { private final java.lang.String haystack; private final java.lang.String needleRegex; diff --git a/Source/javasource/communitycommons/actions/RemoveEnd.java b/Source/javasource/communitycommons/actions/RemoveEnd.java index 42877d3a..64405edb 100644 --- a/Source/javasource/communitycommons/actions/RemoveEnd.java +++ b/Source/javasource/communitycommons/actions/RemoveEnd.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Removes a string (if present) from the end of an input string, */ -public class RemoveEnd extends CustomJavaAction +public class RemoveEnd extends UserAction { private final java.lang.String input; private final java.lang.String toRemove; diff --git a/Source/javasource/communitycommons/actions/RunMicroflowAsyncInQueue.java b/Source/javasource/communitycommons/actions/RunMicroflowAsyncInQueue.java index 1363ecd3..b644a4e5 100644 --- a/Source/javasource/communitycommons/actions/RunMicroflowAsyncInQueue.java +++ b/Source/javasource/communitycommons/actions/RunMicroflowAsyncInQueue.java @@ -11,14 +11,14 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Runs a microflow asynchronous, that is, this action immediately returns but schedules the microflow to be run in the near future. The queue guarantees a first come first serve order of the microflows, and only one action is served at a time. * * The microflow is run with system rights in its own transaction, and is very useful to run heavy microflows on the background. */ -public class RunMicroflowAsyncInQueue extends CustomJavaAction +public class RunMicroflowAsyncInQueue extends UserAction { private final java.lang.String microflow; diff --git a/Source/javasource/communitycommons/actions/StartTransaction.java b/Source/javasource/communitycommons/actions/StartTransaction.java index 37d5cc27..7ed5304e 100644 --- a/Source/javasource/communitycommons/actions/StartTransaction.java +++ b/Source/javasource/communitycommons/actions/StartTransaction.java @@ -10,12 +10,12 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Start a transaction, if a transaction is already started for this context, a savepoint will be added */ -public class StartTransaction extends CustomJavaAction +public class StartTransaction extends UserAction { public StartTransaction(IContext context) { diff --git a/Source/javasource/communitycommons/actions/StringFromFile.java b/Source/javasource/communitycommons/actions/StringFromFile.java index 73cd9fdc..6ead9814 100644 --- a/Source/javasource/communitycommons/actions/StringFromFile.java +++ b/Source/javasource/communitycommons/actions/StringFromFile.java @@ -14,12 +14,12 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Reads the contents form the provided file document, using the specified encoding, and returns it as string. */ -public class StringFromFile extends CustomJavaAction +public class StringFromFile extends UserAction { /** @deprecated use source.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/communitycommons/actions/StringLeftPad.java b/Source/javasource/communitycommons/actions/StringLeftPad.java index 5f22313b..e3cbb913 100644 --- a/Source/javasource/communitycommons/actions/StringLeftPad.java +++ b/Source/javasource/communitycommons/actions/StringLeftPad.java @@ -10,7 +10,7 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Pads a string on the left to a certain length. @@ -22,7 +22,7 @@ * StringLeftPad("hello", 8, "-") returns "---hello" * StringLeftPad("hello", 2, "-") returns "hello" */ -public class StringLeftPad extends CustomJavaAction +public class StringLeftPad extends UserAction { private final java.lang.String value; private final java.lang.Long amount; diff --git a/Source/javasource/communitycommons/actions/StringRightPad.java b/Source/javasource/communitycommons/actions/StringRightPad.java index 1e2c4b69..eeb00fbf 100644 --- a/Source/javasource/communitycommons/actions/StringRightPad.java +++ b/Source/javasource/communitycommons/actions/StringRightPad.java @@ -10,7 +10,7 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Pads a string on the right to a certain length. @@ -22,7 +22,7 @@ * StringRightPad("hello", 8, "-") returns "hello---" * StringLeftpad("hello", 2, "-") returns "hello" */ -public class StringRightPad extends CustomJavaAction +public class StringRightPad extends UserAction { private final java.lang.String value; private final java.lang.Long amount; diff --git a/Source/javasource/communitycommons/actions/StringSimplify.java b/Source/javasource/communitycommons/actions/StringSimplify.java index e18f234f..1889ed8f 100644 --- a/Source/javasource/communitycommons/actions/StringSimplify.java +++ b/Source/javasource/communitycommons/actions/StringSimplify.java @@ -11,12 +11,12 @@ import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Remove diacritics from a string. */ -public class StringSimplify extends CustomJavaAction +public class StringSimplify extends UserAction { private final java.lang.String value; diff --git a/Source/javasource/communitycommons/actions/StringSplit.java b/Source/javasource/communitycommons/actions/StringSplit.java index be95de75..ac8604aa 100644 --- a/Source/javasource/communitycommons/actions/StringSplit.java +++ b/Source/javasource/communitycommons/actions/StringSplit.java @@ -14,10 +14,10 @@ import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; import communitycommons.proxies.SplitItem; +import com.mendix.systemwideinterfaces.core.UserAction; -public class StringSplit extends CustomJavaAction> +public class StringSplit extends UserAction> { private final java.lang.String inputString; private final java.lang.String splitParameter; diff --git a/Source/javasource/communitycommons/actions/StringToFile.java b/Source/javasource/communitycommons/actions/StringToFile.java index e299b42a..ec76e711 100644 --- a/Source/javasource/communitycommons/actions/StringToFile.java +++ b/Source/javasource/communitycommons/actions/StringToFile.java @@ -14,13 +14,13 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Stores a string into the provided FileDocument, using the specified encoding. * Note that destination will be committed. */ -public class StringToFile extends CustomJavaAction +public class StringToFile extends UserAction { private final java.lang.String value; /** @deprecated use destination.getMendixObject() instead. */ diff --git a/Source/javasource/communitycommons/actions/StringTrim.java b/Source/javasource/communitycommons/actions/StringTrim.java index 4f261da1..f16077ba 100644 --- a/Source/javasource/communitycommons/actions/StringTrim.java +++ b/Source/javasource/communitycommons/actions/StringTrim.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Left and right trims a string (that is; removes all surrounding whitespace characters such as tabs, spaces and returns). * Returns the empty string if value is the empty value. Returns the trimmed string otherwise. */ -public class StringTrim extends CustomJavaAction +public class StringTrim extends UserAction { private final java.lang.String value; diff --git a/Source/javasource/communitycommons/actions/SubstituteTemplate.java b/Source/javasource/communitycommons/actions/SubstituteTemplate.java index 0315ae4a..a7607166 100644 --- a/Source/javasource/communitycommons/actions/SubstituteTemplate.java +++ b/Source/javasource/communitycommons/actions/SubstituteTemplate.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Given an object and a template, substitutes all fields in the template. Supports attributes, references, referencesets and constants. @@ -32,7 +32,7 @@ * * datetimeformat identifies a format string which is applied to date/time based attributes. Can be left empty. Defaults to "EEE dd MMM yyyy, HH:mm" */ -public class SubstituteTemplate extends CustomJavaAction +public class SubstituteTemplate extends UserAction { private final java.lang.String template; private final IMendixObject substitute; diff --git a/Source/javasource/communitycommons/actions/SubstituteTemplate2.java b/Source/javasource/communitycommons/actions/SubstituteTemplate2.java index eedb7c73..5dd4901d 100644 --- a/Source/javasource/communitycommons/actions/SubstituteTemplate2.java +++ b/Source/javasource/communitycommons/actions/SubstituteTemplate2.java @@ -12,14 +12,14 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.StringUtils; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Identical to SubstituteTemplate, but adds an datetimeformat argument * * DateTimeFormat identifies a format string which is applied to date/time based attributes. Can be left empty. Defaults to "EEE dd MMM yyyy, HH:mm" */ -public class SubstituteTemplate2 extends CustomJavaAction +public class SubstituteTemplate2 extends UserAction { private final java.lang.String template; private final IMendixObject substitute; diff --git a/Source/javasource/communitycommons/actions/SubstringAfter.java b/Source/javasource/communitycommons/actions/SubstringAfter.java index 376b77fb..01e0766f 100644 --- a/Source/javasource/communitycommons/actions/SubstringAfter.java +++ b/Source/javasource/communitycommons/actions/SubstringAfter.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Gets the substring after the first occurrence of a separator. */ -public class SubstringAfter extends CustomJavaAction +public class SubstringAfter extends UserAction { private final java.lang.String str; private final java.lang.String separator; diff --git a/Source/javasource/communitycommons/actions/SubstringAfterLast.java b/Source/javasource/communitycommons/actions/SubstringAfterLast.java index eb5af262..53fdf2ec 100644 --- a/Source/javasource/communitycommons/actions/SubstringAfterLast.java +++ b/Source/javasource/communitycommons/actions/SubstringAfterLast.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Gets the substring after the last occurrence of a separator. */ -public class SubstringAfterLast extends CustomJavaAction +public class SubstringAfterLast extends UserAction { private final java.lang.String str; private final java.lang.String separator; diff --git a/Source/javasource/communitycommons/actions/SubstringBefore.java b/Source/javasource/communitycommons/actions/SubstringBefore.java index bf3db706..48b93cb1 100644 --- a/Source/javasource/communitycommons/actions/SubstringBefore.java +++ b/Source/javasource/communitycommons/actions/SubstringBefore.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Gets the substring before the first occurrence of a separator. */ -public class SubstringBefore extends CustomJavaAction +public class SubstringBefore extends UserAction { private final java.lang.String str; private final java.lang.String separator; diff --git a/Source/javasource/communitycommons/actions/SubstringBeforeLast.java b/Source/javasource/communitycommons/actions/SubstringBeforeLast.java index f73c6c6a..cb2f797e 100644 --- a/Source/javasource/communitycommons/actions/SubstringBeforeLast.java +++ b/Source/javasource/communitycommons/actions/SubstringBeforeLast.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Gets the substring before the last occurrence of a separator. */ -public class SubstringBeforeLast extends CustomJavaAction +public class SubstringBeforeLast extends UserAction { private final java.lang.String str; private final java.lang.String separator; diff --git a/Source/javasource/communitycommons/actions/ThrowException.java b/Source/javasource/communitycommons/actions/ThrowException.java index 9315fb4e..26a8276c 100644 --- a/Source/javasource/communitycommons/actions/ThrowException.java +++ b/Source/javasource/communitycommons/actions/ThrowException.java @@ -11,7 +11,7 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * This action always throws an exception (of type communityutils.UserThrownError), which is, in combination with custom error handling, quite useful to end a microflow prematurely or to bail out to the calling action/ microflow. @@ -20,7 +20,7 @@ * * Example usuage: In general, if an Event (before commit especially) returns false, it should call this action and then return true instead. If an Before commit returns false, the object will not be committed, but there is no easy way for the calling Microflow/ action to detect this! An exception on the other hand, will be noticed. */ -public class ThrowException extends CustomJavaAction +public class ThrowException extends UserAction { private final java.lang.String message; diff --git a/Source/javasource/communitycommons/actions/ThrowWebserviceException.java b/Source/javasource/communitycommons/actions/ThrowWebserviceException.java index 19f4986b..720e7c7c 100644 --- a/Source/javasource/communitycommons/actions/ThrowWebserviceException.java +++ b/Source/javasource/communitycommons/actions/ThrowWebserviceException.java @@ -11,7 +11,7 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * (Behavior has changed since version 3.2. The exception is now properly propagated to the cient). @@ -20,7 +20,7 @@ * * If debug level of community commons is set to 'debug' the errors will be locally visible as well, otherwise not. Throwing a webservice exception states that the webservice invocation was incorrect, not the webservice implementation. */ -public class ThrowWebserviceException extends CustomJavaAction +public class ThrowWebserviceException extends UserAction { private final java.lang.String faultstring; diff --git a/Source/javasource/communitycommons/actions/TimeMeasureEnd.java b/Source/javasource/communitycommons/actions/TimeMeasureEnd.java index cc782fb3..6a929546 100644 --- a/Source/javasource/communitycommons/actions/TimeMeasureEnd.java +++ b/Source/javasource/communitycommons/actions/TimeMeasureEnd.java @@ -11,7 +11,7 @@ import communitycommons.Logging; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * End timing something, and print the result to the log. @@ -19,7 +19,7 @@ * - LogLevel. The loglevel used to print the result. * - The message to be printed in the log. */ -public class TimeMeasureEnd extends CustomJavaAction +public class TimeMeasureEnd extends UserAction { private final java.lang.String TimerName; private final communitycommons.proxies.LogLevel Loglevel; diff --git a/Source/javasource/communitycommons/actions/TimeMeasureStart.java b/Source/javasource/communitycommons/actions/TimeMeasureStart.java index 27df22bb..e485a792 100644 --- a/Source/javasource/communitycommons/actions/TimeMeasureStart.java +++ b/Source/javasource/communitycommons/actions/TimeMeasureStart.java @@ -11,7 +11,7 @@ import communitycommons.Logging; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Start timing something, and print the result to the log. @@ -19,7 +19,7 @@ * * Note that multiple timers can run at once. Existing timers can be restarted using this function as well. */ -public class TimeMeasureStart extends CustomJavaAction +public class TimeMeasureStart extends UserAction { private final java.lang.String TimerName; diff --git a/Source/javasource/communitycommons/actions/XSSSanitize.java b/Source/javasource/communitycommons/actions/XSSSanitize.java index 0f6fb447..3a147e6b 100644 --- a/Source/javasource/communitycommons/actions/XSSSanitize.java +++ b/Source/javasource/communitycommons/actions/XSSSanitize.java @@ -11,13 +11,13 @@ import com.mendix.systemwideinterfaces.MendixRuntimeException; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.proxies.SanitizerPolicy; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Removes all potential dangerous HTML from a string so that it can be safely displayed in a browser. @@ -38,7 +38,7 @@ * * http://javadoc.io/doc/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer/20180219.1 */ -public class XSSSanitize extends CustomJavaAction +public class XSSSanitize extends UserAction { private final java.lang.String html; private final communitycommons.proxies.SanitizerPolicy policy1; diff --git a/Source/javasource/communitycommons/actions/YearsBetween.java b/Source/javasource/communitycommons/actions/YearsBetween.java index 960d37be..cd1cd381 100644 --- a/Source/javasource/communitycommons/actions/YearsBetween.java +++ b/Source/javasource/communitycommons/actions/YearsBetween.java @@ -10,19 +10,19 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.DateTime; import communitycommons.Logging; import communitycommons.proxies.LogLevel; import communitycommons.proxies.LogNodes; import java.util.Date; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Calculates the number of years between two dates. * - dateTime : the original (oldest) dateTime * - compareDate: the second date. If EMPTY, the current datetime will be used. Effectively this means that the age of the dateTime is calculated. */ -public class YearsBetween extends CustomJavaAction +public class YearsBetween extends UserAction { private final java.util.Date dateTime; private final java.util.Date compareDate; diff --git a/Source/javasource/communitycommons/actions/commitInSeparateDatabaseTransaction.java b/Source/javasource/communitycommons/actions/commitInSeparateDatabaseTransaction.java index 8e4108d8..b5c20c2e 100644 --- a/Source/javasource/communitycommons/actions/commitInSeparateDatabaseTransaction.java +++ b/Source/javasource/communitycommons/actions/commitInSeparateDatabaseTransaction.java @@ -12,13 +12,13 @@ import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.ISession; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * This function commits an object in a seperate context and transaction, making sure it gets persisted in the database (regarding which exception happens after invocation). */ -public class commitInSeparateDatabaseTransaction extends CustomJavaAction +public class commitInSeparateDatabaseTransaction extends UserAction { private final IMendixObject mxObject; diff --git a/Source/javasource/communitycommons/actions/commitWithoutEvents.java b/Source/javasource/communitycommons/actions/commitWithoutEvents.java index 03bd8f7f..8329dbaf 100644 --- a/Source/javasource/communitycommons/actions/commitWithoutEvents.java +++ b/Source/javasource/communitycommons/actions/commitWithoutEvents.java @@ -12,14 +12,14 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Commits an object, but without events. * * N.B. This function is not very useful when called from the model, but it is useful when called from custom Java code. */ -public class commitWithoutEvents extends CustomJavaAction +public class commitWithoutEvents extends UserAction { private final IMendixObject subject; diff --git a/Source/javasource/communitycommons/actions/copyAttributes.java b/Source/javasource/communitycommons/actions/copyAttributes.java index 181511c4..1469f25a 100644 --- a/Source/javasource/communitycommons/actions/copyAttributes.java +++ b/Source/javasource/communitycommons/actions/copyAttributes.java @@ -10,16 +10,16 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Copies all common primitive attributes from source to target, which are not necessarily of the same type. This is useful to, for example, translate database object into view objects. * * Note that no automatic type conversion is done. */ -public class copyAttributes extends CustomJavaAction +public class copyAttributes extends UserAction { private final IMendixObject source; private final IMendixObject target; diff --git a/Source/javasource/communitycommons/actions/deleteAll.java b/Source/javasource/communitycommons/actions/deleteAll.java index e018d4b6..a1a3dfae 100644 --- a/Source/javasource/communitycommons/actions/deleteAll.java +++ b/Source/javasource/communitycommons/actions/deleteAll.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.XPath; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Removes ALL instances of a certain domain object type using batches. */ -public class deleteAll extends CustomJavaAction +public class deleteAll extends UserAction { private final java.lang.String entityType; diff --git a/Source/javasource/communitycommons/actions/executeMicroflowAsUser.java b/Source/javasource/communitycommons/actions/executeMicroflowAsUser.java index dca5aefd..18994f57 100644 --- a/Source/javasource/communitycommons/actions/executeMicroflowAsUser.java +++ b/Source/javasource/communitycommons/actions/executeMicroflowAsUser.java @@ -11,7 +11,7 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Executes the given microflow as if the $currentuser is the provided user (delegation). Use sudoContext to determine if 'apply entity access' should be used @@ -20,7 +20,7 @@ * - username: The user that should be used to execute the microflow * - sudoContext: whether entity access should be applied. */ -public class executeMicroflowAsUser extends CustomJavaAction +public class executeMicroflowAsUser extends UserAction { private final java.lang.String microflow; private final java.lang.String username; diff --git a/Source/javasource/communitycommons/actions/executeMicroflowAsUser_1.java b/Source/javasource/communitycommons/actions/executeMicroflowAsUser_1.java index fbdce957..dce94995 100644 --- a/Source/javasource/communitycommons/actions/executeMicroflowAsUser_1.java +++ b/Source/javasource/communitycommons/actions/executeMicroflowAsUser_1.java @@ -12,12 +12,12 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Identical to executeMicroflowAsUser, but takes 1 argument */ -public class executeMicroflowAsUser_1 extends CustomJavaAction +public class executeMicroflowAsUser_1 extends UserAction { private final java.lang.String microflow; private final java.lang.String username; diff --git a/Source/javasource/communitycommons/actions/executeMicroflowAsUser_2.java b/Source/javasource/communitycommons/actions/executeMicroflowAsUser_2.java index 1d6f7d91..c0462067 100644 --- a/Source/javasource/communitycommons/actions/executeMicroflowAsUser_2.java +++ b/Source/javasource/communitycommons/actions/executeMicroflowAsUser_2.java @@ -10,14 +10,14 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Identical to executeMicroflowAsUser, but takes 2 arguments */ -public class executeMicroflowAsUser_2 extends CustomJavaAction +public class executeMicroflowAsUser_2 extends UserAction { private final java.lang.String microflow; private final java.lang.String username; diff --git a/Source/javasource/communitycommons/actions/executeMicroflowInBackground.java b/Source/javasource/communitycommons/actions/executeMicroflowInBackground.java index 4f0a1067..733093db 100644 --- a/Source/javasource/communitycommons/actions/executeMicroflowInBackground.java +++ b/Source/javasource/communitycommons/actions/executeMicroflowInBackground.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * This action allows an microflow to be executed independently from this microflow. @@ -29,7 +29,7 @@ * * Returns true if scheduled successfully. */ -public class executeMicroflowInBackground extends CustomJavaAction +public class executeMicroflowInBackground extends UserAction { private final java.lang.String microflow; private final IMendixObject contextObject; diff --git a/Source/javasource/communitycommons/actions/executeMicroflowInBatches.java b/Source/javasource/communitycommons/actions/executeMicroflowInBatches.java index a6d42f06..164a610b 100644 --- a/Source/javasource/communitycommons/actions/executeMicroflowInBatches.java +++ b/Source/javasource/communitycommons/actions/executeMicroflowInBatches.java @@ -11,7 +11,7 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Invokes a microflow in batches. The microflow is invoked for each individual item returned by the xpath query. @@ -31,7 +31,7 @@ * * Note, if new objects are added to the dataset while the batch is still running, those objects will be processed as well. */ -public class executeMicroflowInBatches extends CustomJavaAction +public class executeMicroflowInBatches extends UserAction { private final java.lang.String xpath; private final java.lang.String microflow; diff --git a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser.java b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser.java index 638bc7e1..a2f783d3 100644 --- a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser.java +++ b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser.java @@ -10,8 +10,8 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Executes the given microflow as if the $currentuser is the provided user (delegation). Use sudoContext to determine if 'apply entity access' should be used @@ -20,7 +20,7 @@ * - username: The user that should be used to execute the microflow * - sudoContext: whether entity access should be applied. */ -public class executeUnverifiedMicroflowAsUser extends CustomJavaAction +public class executeUnverifiedMicroflowAsUser extends UserAction { private final java.lang.String microflowName; private final java.lang.String username; diff --git a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_1.java b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_1.java index cae906c9..ff233145 100644 --- a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_1.java +++ b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_1.java @@ -10,14 +10,14 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Identical to executeMicroflowAsUser, but takes 1 argument */ -public class executeUnverifiedMicroflowAsUser_1 extends CustomJavaAction +public class executeUnverifiedMicroflowAsUser_1 extends UserAction { private final java.lang.String microflowName; private final java.lang.String username; diff --git a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_2.java b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_2.java index ab91e651..a7886461 100644 --- a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_2.java +++ b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowAsUser_2.java @@ -12,12 +12,12 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Identical to executeMicroflowAsUser, but takes 2 arguments */ -public class executeUnverifiedMicroflowAsUser_2 extends CustomJavaAction +public class executeUnverifiedMicroflowAsUser_2 extends UserAction { private final java.lang.String microflowName; private final java.lang.String username; diff --git a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBackground.java b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBackground.java index da369c6e..83092147 100644 --- a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBackground.java +++ b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBackground.java @@ -10,9 +10,9 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * This action allows an microflow to be executed independently from this microflow. @@ -29,7 +29,7 @@ * * Returns true if scheduled successfully. */ -public class executeUnverifiedMicroflowInBackground extends CustomJavaAction +public class executeUnverifiedMicroflowInBackground extends UserAction { private final java.lang.String microflowName; private final IMendixObject contextObject; diff --git a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBatches.java b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBatches.java index c579ead1..3ed89f67 100644 --- a/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBatches.java +++ b/Source/javasource/communitycommons/actions/executeUnverifiedMicroflowInBatches.java @@ -10,8 +10,8 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import communitycommons.Misc; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Invokes a microflow in batches. The microflow is invoked for each individual item returned by the xpath query. @@ -31,7 +31,7 @@ * * Note, if new objects are added to the dataset while the batch is still running, those objects will be processed as well. */ -public class executeUnverifiedMicroflowInBatches extends CustomJavaAction +public class executeUnverifiedMicroflowInBatches extends UserAction { private final java.lang.String xpath; private final java.lang.String microflowName; diff --git a/Source/javasource/communitycommons/actions/getCreatedByUser.java b/Source/javasource/communitycommons/actions/getCreatedByUser.java index b25c964e..bac0f005 100644 --- a/Source/javasource/communitycommons/actions/getCreatedByUser.java +++ b/Source/javasource/communitycommons/actions/getCreatedByUser.java @@ -12,14 +12,14 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the user that created an object * * (or empty if not applicable). */ -public class getCreatedByUser extends CustomJavaAction +public class getCreatedByUser extends UserAction { private final IMendixObject thing; diff --git a/Source/javasource/communitycommons/actions/getFileSize.java b/Source/javasource/communitycommons/actions/getFileSize.java index c3703f1c..408b51b7 100644 --- a/Source/javasource/communitycommons/actions/getFileSize.java +++ b/Source/javasource/communitycommons/actions/getFileSize.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the filesize of a file document in bytes. @@ -22,7 +22,7 @@ * NOTE: * before 2.1, this functioned returned the size in kilobytes, although this documentation mentioned bytes */ -public class getFileSize extends CustomJavaAction +public class getFileSize extends UserAction { /** @deprecated use document.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/communitycommons/actions/getGUID.java b/Source/javasource/communitycommons/actions/getGUID.java index 002d2f74..ce5c1c24 100644 --- a/Source/javasource/communitycommons/actions/getGUID.java +++ b/Source/javasource/communitycommons/actions/getGUID.java @@ -12,12 +12,12 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * returns the Global Unique Identifier (GUID, or id) of an object. */ -public class getGUID extends CustomJavaAction +public class getGUID extends UserAction { private final IMendixObject item; diff --git a/Source/javasource/communitycommons/actions/getLastChangedByUser.java b/Source/javasource/communitycommons/actions/getLastChangedByUser.java index 0bda1319..1d888397 100644 --- a/Source/javasource/communitycommons/actions/getLastChangedByUser.java +++ b/Source/javasource/communitycommons/actions/getLastChangedByUser.java @@ -12,14 +12,14 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the user that last changed this object as System.User * * (or empty if not applicable). */ -public class getLastChangedByUser extends CustomJavaAction +public class getLastChangedByUser extends UserAction { private final IMendixObject thing; diff --git a/Source/javasource/communitycommons/actions/getOriginalValueAsString.java b/Source/javasource/communitycommons/actions/getOriginalValueAsString.java index 2d56d4f9..e35fccda 100644 --- a/Source/javasource/communitycommons/actions/getOriginalValueAsString.java +++ b/Source/javasource/communitycommons/actions/getOriginalValueAsString.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the original value of an object member, that is, the last committed value. @@ -23,7 +23,7 @@ * * The function is applicable for non-String members as well, but always returns a String representation of the previous value. */ -public class getOriginalValueAsString extends CustomJavaAction +public class getOriginalValueAsString extends UserAction { private final IMendixObject item; private final java.lang.String member; diff --git a/Source/javasource/communitycommons/actions/getTypeAsString.java b/Source/javasource/communitycommons/actions/getTypeAsString.java index b420fbd4..52497e4a 100644 --- a/Source/javasource/communitycommons/actions/getTypeAsString.java +++ b/Source/javasource/communitycommons/actions/getTypeAsString.java @@ -11,12 +11,12 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns the actual type of an Entity. Useful as alternative way to split upon inheritance, or as input of other functions in this module. */ -public class getTypeAsString extends CustomJavaAction +public class getTypeAsString extends UserAction { private final IMendixObject instance; diff --git a/Source/javasource/communitycommons/actions/memberHasChanged.java b/Source/javasource/communitycommons/actions/memberHasChanged.java index 765e0127..88735ece 100644 --- a/Source/javasource/communitycommons/actions/memberHasChanged.java +++ b/Source/javasource/communitycommons/actions/memberHasChanged.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Checks whether a member has changed since the last commit. Useful in combination with getOriginalValueAsString. @@ -22,7 +22,7 @@ * * Returns true if changed. */ -public class memberHasChanged extends CustomJavaAction +public class memberHasChanged extends UserAction { private final IMendixObject item; private final java.lang.String member; diff --git a/Source/javasource/communitycommons/actions/objectHasChanged.java b/Source/javasource/communitycommons/actions/objectHasChanged.java index 9282991f..dfa9988f 100644 --- a/Source/javasource/communitycommons/actions/objectHasChanged.java +++ b/Source/javasource/communitycommons/actions/objectHasChanged.java @@ -12,14 +12,14 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.ORM; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns true if at least one member (including owned associations) of this object has changed. * * For Mendix < 9.5 this action keeps track of changes to the object except when 'changing to the same value'. For Mendix >= 9.5 this action keeps track of all changes. This is a result of a change of the underlying Mendix runtime-server behaviour. */ -public class objectHasChanged extends CustomJavaAction +public class objectHasChanged extends UserAction { private final IMendixObject item; diff --git a/Source/javasource/communitycommons/actions/objectIsNew.java b/Source/javasource/communitycommons/actions/objectIsNew.java index 615af852..a1c8fdc3 100644 --- a/Source/javasource/communitycommons/actions/objectIsNew.java +++ b/Source/javasource/communitycommons/actions/objectIsNew.java @@ -10,13 +10,13 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Returns true if this object is new (not committed in the database). */ -public class objectIsNew extends CustomJavaAction +public class objectIsNew extends UserAction { private final IMendixObject mxObject; diff --git a/Source/javasource/communitycommons/actions/recommitInBatches.java b/Source/javasource/communitycommons/actions/recommitInBatches.java index c873254b..38ae4023 100644 --- a/Source/javasource/communitycommons/actions/recommitInBatches.java +++ b/Source/javasource/communitycommons/actions/recommitInBatches.java @@ -11,9 +11,9 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class recommitInBatches extends CustomJavaAction +public class recommitInBatches extends UserAction { private final java.lang.String xpath; private final java.lang.Long batchsize; diff --git a/Source/javasource/communitycommons/actions/refreshClass.java b/Source/javasource/communitycommons/actions/refreshClass.java index ef32165f..483d7317 100644 --- a/Source/javasource/communitycommons/actions/refreshClass.java +++ b/Source/javasource/communitycommons/actions/refreshClass.java @@ -10,8 +10,8 @@ package communitycommons.actions; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; import com.mendix.webui.FeedbackHelper; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Refreshes a certain domain object type in the client. Useful to enforce a datagrid to refresh for example. @@ -19,7 +19,7 @@ * -objectType : Type of the domain objects to refresh, such as System.User or MyModule.MyFirstEntity. * (you can use getTypeAsString to determine this dynamically, so that the invoke of this action is not be sensitive to domain model changes). */ -public class refreshClass extends CustomJavaAction +public class refreshClass extends UserAction { private final java.lang.String objectType; diff --git a/Source/javasource/communitycommons/actions/refreshClassByObject.java b/Source/javasource/communitycommons/actions/refreshClassByObject.java index 65b21e32..9bc34abd 100644 --- a/Source/javasource/communitycommons/actions/refreshClassByObject.java +++ b/Source/javasource/communitycommons/actions/refreshClassByObject.java @@ -11,15 +11,15 @@ import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; import com.mendix.webui.FeedbackHelper; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Refreshes a certain domain object type in the client. Useful to enforce a datagrid to refresh for example. * * - instance : This object is used to identify the type of objects that need to be refreshed. For example passing $currentUser will refresh all System.Account's. */ -public class refreshClassByObject extends CustomJavaAction +public class refreshClassByObject extends UserAction { private final IMendixObject instance; diff --git a/Source/javasource/communitycommons/actions/retrieveURL.java b/Source/javasource/communitycommons/actions/retrieveURL.java index 72845679..6b70186f 100644 --- a/Source/javasource/communitycommons/actions/retrieveURL.java +++ b/Source/javasource/communitycommons/actions/retrieveURL.java @@ -11,7 +11,7 @@ import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Retrieves data (such as an HTML page) from an URL using the HTTP protocol, and returns it as string. @@ -26,7 +26,7 @@ * Example post data: * 'ipSearchTag=url&x=0&y=0' */ -public class retrieveURL extends CustomJavaAction +public class retrieveURL extends UserAction { private final java.lang.String url; private final java.lang.String postdata; diff --git a/Source/javasource/communitycommons/actions/storeURLToFileDocument.java b/Source/javasource/communitycommons/actions/storeURLToFileDocument.java index da3a5bd4..ce3e1f62 100644 --- a/Source/javasource/communitycommons/actions/storeURLToFileDocument.java +++ b/Source/javasource/communitycommons/actions/storeURLToFileDocument.java @@ -12,7 +12,7 @@ import com.mendix.systemwideinterfaces.core.IMendixObject; import communitycommons.Misc; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Retrieve a document from an URL using a HTTP GET request. @@ -24,7 +24,7 @@ * * NOTE: For images, no thumbnail will be generated. */ -public class storeURLToFileDocument extends CustomJavaAction +public class storeURLToFileDocument extends UserAction { private final java.lang.String url; /** @deprecated use document.getMendixObject() instead. */ diff --git a/Source/javasource/taskqueuehelpers/actions/GetProcessedQueueCount.java b/Source/javasource/taskqueuehelpers/actions/GetProcessedQueueCount.java index 4dcb6264..7f4b141f 100644 --- a/Source/javasource/taskqueuehelpers/actions/GetProcessedQueueCount.java +++ b/Source/javasource/taskqueuehelpers/actions/GetProcessedQueueCount.java @@ -14,16 +14,16 @@ import com.mendix.systemwideinterfaces.connectionbus.requests.types.IOQLTextGetRequest; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; import system.proxies.ProcessedQueueTask; import system.proxies.QueueTaskStatus; import taskqueuehelpers.proxies.ProcessedQueueCount; import java.util.stream.Collectors; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Creates a List of ProcessedQueueCount entities grouped by queue name. The grouping will aggregate the comlpeted and non-completed count of each queue based on status. */ -public class GetProcessedQueueCount extends CustomJavaAction> +public class GetProcessedQueueCount extends UserAction> { public GetProcessedQueueCount(IContext context) { diff --git a/Source/javasource/taskqueuehelpers/actions/GetQueueCounts.java b/Source/javasource/taskqueuehelpers/actions/GetQueueCounts.java index f61f3539..c734112a 100644 --- a/Source/javasource/taskqueuehelpers/actions/GetQueueCounts.java +++ b/Source/javasource/taskqueuehelpers/actions/GetQueueCounts.java @@ -14,15 +14,15 @@ import com.mendix.systemwideinterfaces.connectionbus.requests.types.IOQLTextGetRequest; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; import system.proxies.QueuedTask; import taskqueuehelpers.proxies.QueueCount; import java.util.stream.Collectors; +import com.mendix.systemwideinterfaces.core.UserAction; /** * Creates a List of QueueCount entities grouped by queue name. The grouping will aggregate the open count and running count of each queue. */ -public class GetQueueCounts extends CustomJavaAction> +public class GetQueueCounts extends UserAction> { public GetQueueCounts(IContext context) { diff --git a/Source/javasource/unittesting/AbstractUnitTest.java b/Source/javasource/unittesting/AbstractUnitTest.java index 075ca15e..1bdc5599 100644 --- a/Source/javasource/unittesting/AbstractUnitTest.java +++ b/Source/javasource/unittesting/AbstractUnitTest.java @@ -1,22 +1,22 @@ -package unittesting; - -public class AbstractUnitTest { - private static long startTime; - private static long endTime; - - public static long getTestRunTime() { - return endTime - startTime; - } - - public void startTimeMeasure() { - startTime = System.currentTimeMillis(); - } - - public void endTimeMeasure() { - endTime = System.currentTimeMillis(); - } - - public void reportStep(String lastStep1) { - TestManager.instance().reportStep(lastStep1); - } -} +package unittesting; + +public class AbstractUnitTest { + private static long startTime; + private static long endTime; + + public static long getTestRunTime() { + return endTime - startTime; + } + + public void startTimeMeasure() { + startTime = System.currentTimeMillis(); + } + + public void endTimeMeasure() { + endTime = System.currentTimeMillis(); + } + + public void reportStep(String lastStep1) { + TestManager.instance().reportStep(lastStep1); + } +} diff --git a/Source/javasource/unittesting/ConfigurationManager.java b/Source/javasource/unittesting/ConfigurationManager.java new file mode 100644 index 00000000..741b08a8 --- /dev/null +++ b/Source/javasource/unittesting/ConfigurationManager.java @@ -0,0 +1,70 @@ +package unittesting; + +import org.apache.commons.lang3.SystemUtils; + +import com.mendix.core.Core; +import com.mendix.logging.ILogNode; + +import unittesting.proxies.constants.Constants; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class ConfigurationManager { + enum IsEnabled { + UNDETERMINED, TRUE, FALSE + } + + public static final ILogNode LOG = Core.getLogger("UnitTestRunner"); + + private static IsEnabled isEnabled = IsEnabled.UNDETERMINED; + private static boolean isInitialized = false; + + public static boolean isLocalDevelopment() { + if (!(SystemUtils.IS_OS_WINDOWS || SystemUtils.IS_OS_MAC_OSX)) + return false; + + String modelerPath = String.join(File.separator, + new String[] { Core.getConfiguration().getRuntimePath().getParent(), "modeler" }); + + if (!Files.exists(Paths.get(modelerPath))) { + LOG.trace("Could not find modeler path: " + modelerPath); + return false; + } + + return true; + } + + public static boolean verifyModuleIsEnabled() { + if (isEnabled()) return true; + + LOG.warn("Unit testing is disabled on this environment. Read the module documentation for more details"); + return false; + } + + public static boolean isEnabled() { + if (isEnabled.equals(IsEnabled.UNDETERMINED)) { + if (isLocalDevelopment()) { + LOG.debug("Unit testing is enabled for local development on OS: " + SystemUtils.OS_NAME); + isEnabled = IsEnabled.TRUE; + } else if (Constants.getEnabled()) { + LOG.debug("Unit testing is enabled for this environment on OS: " + SystemUtils.OS_NAME); + isEnabled = IsEnabled.TRUE; + } else { + LOG.debug("Unit testing is disabled for this environment on OS: " + SystemUtils.OS_NAME); + isEnabled = IsEnabled.FALSE; + } + } + + return isEnabled.equals(IsEnabled.TRUE); + } + + public static void initialize() { + isInitialized = true; + } + + public static boolean isInitialized() { + return isInitialized; + } +} diff --git a/Source/javasource/unittesting/UnittestingUnitTest1.java b/Source/javasource/unittesting/JUnitExample1.java similarity index 76% rename from Source/javasource/unittesting/UnittestingUnitTest1.java rename to Source/javasource/unittesting/JUnitExample1.java index b0574e54..4325f5e2 100644 --- a/Source/javasource/unittesting/UnittestingUnitTest1.java +++ b/Source/javasource/unittesting/JUnitExample1.java @@ -1,31 +1,31 @@ -package unittesting; - -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; - -public class UnittestingUnitTest1 { - private boolean state; - - @Before - public void setup() throws InterruptedException { - this.state = false; - Thread.sleep(1000); - } - - @Test - public void testOfOneSecondSetupAndOneSecundRun() throws InterruptedException { - this.state = true; - TestManager.instance().reportStep("Sleeping a while"); - Thread.sleep(1000); - TestManager.instance().reportStep("Sleeping done!"); - assertTrue(state); - } - - @Test(expected = IllegalStateException.class) - public void testThatThrowsException() { - TestManager.instance().reportStep("Going to throw exception"); - throw new IllegalStateException("This exception was to be expected.."); - } -} +package unittesting; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +public class JUnitExample1 { + private boolean state; + + @Before + public void setup() throws InterruptedException { + this.state = false; + Thread.sleep(1); + } + + @Test + public void testOfOneMsSetupAndOneMsRun() throws InterruptedException { + this.state = true; + TestManager.instance().reportStep("Sleeping a while"); + Thread.sleep(1); + TestManager.instance().reportStep("Sleeping done!"); + assertTrue(state); + } + + @Test(expected = IllegalStateException.class) + public void testThatThrowsException() { + TestManager.instance().reportStep("Going to throw exception"); + throw new IllegalStateException("This exception was to be expected.."); + } +} diff --git a/Source/javasource/unittesting/UnittestingUnitTest2.java b/Source/javasource/unittesting/JUnitExample2.java similarity index 62% rename from Source/javasource/unittesting/UnittestingUnitTest2.java rename to Source/javasource/unittesting/JUnitExample2.java index d509a098..dbec060c 100644 --- a/Source/javasource/unittesting/UnittestingUnitTest2.java +++ b/Source/javasource/unittesting/JUnitExample2.java @@ -1,34 +1,33 @@ -package unittesting; - -import static org.junit.Assert.*; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class UnittestingUnitTest2 extends AbstractUnitTest { - - @Before - public void setup() throws InterruptedException { - Thread.sleep(500); - } - - @After - public void tearDown() throws InterruptedException { - Thread.sleep(500); - } - - @Test - public void evenMoreUnitTests() throws InterruptedException { - this.startTimeMeasure(); - - this.reportStep( - "By inheriting from AbstractUnitTest some utility methods are provided and time can be tracted in a more reliable way (without counting setup and teardown)"); - Thread.sleep(1000); - - assertTrue(true); - - this.endTimeMeasure(); - } - -} +package unittesting; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class JUnitExample2 extends AbstractUnitTest { + + @Before + public void setup() throws InterruptedException { + Thread.sleep(10); + } + + @After + public void tearDown() throws InterruptedException { + Thread.sleep(10); + } + + @Test + public void testWithTimeMeasurement() { + this.startTimeMeasure(); + + this.reportStep( + "By inheriting from AbstractUnitTest some utility methods are provided and time can be tracked in a more reliable way (without counting setup and teardown)"); + + assertTrue(true); + + this.endTimeMeasure(); + } + +} diff --git a/Source/javasource/unittesting/JavaTestDiscovery.java b/Source/javasource/unittesting/JavaTestDiscovery.java new file mode 100644 index 00000000..069358f4 --- /dev/null +++ b/Source/javasource/unittesting/JavaTestDiscovery.java @@ -0,0 +1,140 @@ +package unittesting; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import com.mendix.core.Core; +import com.mendix.logging.ILogNode; + +import org.junit.Test; +import org.junit.runners.JUnit4; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; + +import unittesting.proxies.TestSuite; + +public class JavaTestDiscovery { + private static final Map[]> classCache = new HashMap<>(); + private static final ILogNode LOG = ConfigurationManager.LOG; + + public static List findJUnitTests(TestSuite testSuite) { + List junitTests = new ArrayList<>(); + + try { + Class[] classes = getUnitTestClasses(testSuite); + + if (classes != null && classes.length > 0) { + for (Class clazz : classes) { + + // From + // https://github.com/KentBeck/junit/blob/master/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java + // method computeTestMethods + try { + List methods = new JUnit4(clazz).getTestClass() + .getAnnotatedMethods(Test.class); + + if (methods != null && !methods.isEmpty()) + for (FrameworkMethod method : methods) + junitTests.add(clazz.getName() + "/" + method.getName()); + } catch (InitializationError e2) { + StringBuilder errors = new StringBuilder(); + + for (Throwable cause : e2.getCauses()) + errors.append("\n").append(cause.getMessage()); + + LOG.error("Failed to recognize class '" + clazz + "' as unitTestClass: " + errors.toString()); + } + } + } + } catch (Exception e) { + LOG.error("Unable to find JUnit test classes or methods: " + e.getMessage(), e); + } + + return junitTests; + } + + public static Class[] getUnitTestClasses(TestSuite testRun) throws IOException { + if (!classCache.containsKey(testRun.getModule().toLowerCase())) { + ArrayList> classList = getClassesForPackage(testRun.getModule()); + Class[] classes = classList.toArray(new Class[classList.size()]); + classCache.put(testRun.getModule().toLowerCase(), classes); + } + + return classCache.get(testRun.getModule().toLowerCase()); + } + + private static ArrayList> getClassesForPackage(String path) throws IOException { + ArrayList> classes = new ArrayList<>(); + + // Lowercased Mendix module names equals their package names + String packageName = path.toLowerCase(); + + // Get a File object containing the classes. This file is expected to be + // located at [deploymentdir]/model/bundles/project.jar + File projectJar = new File(Core.getConfiguration().getBasePath() + File.separator + "model" + + File.separator + "bundles" + File.separator + "project.jar"); + + processProjectJar(projectJar, packageName, classes); + + return classes; + } + + /** + * Find runnable classes + * https://github.com/ddopson/java-class-enumerator/blob/master/src/pro/ddopson/ClassEnumerator.java + */ + + private static Class loadClass(String className) { + try { + return TestManager.instance().getClass().getClassLoader().loadClass(className); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Unexpected ClassNotFoundException loading class '" + className + "'"); + } + } + + private static void processProjectJar(File projectJar, String packageName, ArrayList> classes) + throws IOException { + ZipFile zipFile = new ZipFile(projectJar); + + // Get the list of the files contained in the package + Enumeration entries = zipFile.entries(); + + while (entries.hasMoreElements()) { + ZipEntry zipEntry = entries.nextElement(); + String fileName = zipEntry.getName(); + + String className = null; + + if (fileName.startsWith(packageName.concat("/")) && fileName.endsWith(".class")) { + fileName = fileName.replace("/", "."); + + // Remove the .class extension + className = fileName.substring(0, fileName.length() - 6); + } + + if (className != null) { + Class clazz = loadClass(className); + if (isProperUnitTest(clazz)) + classes.add(clazz); + } + } + + zipFile.close(); + } + + private static boolean isProperUnitTest(Class clazz) { + for (Method m : clazz.getMethods()) + if (m.getAnnotation(org.junit.Test.class) != null) + return true; + + return false; + } +} diff --git a/Source/javasource/unittesting/ModelUpdateSubscriber.java b/Source/javasource/unittesting/ModelUpdateSubscriber.java new file mode 100644 index 00000000..72077721 --- /dev/null +++ b/Source/javasource/unittesting/ModelUpdateSubscriber.java @@ -0,0 +1,49 @@ +package unittesting; + +import com.mendix.core.Core; +import com.mendix.logging.ILogNode; +import com.mendix.logging.LogLevel; +import com.mendix.logging.LogMessage; +import com.mendix.logging.LogSubscriber; + +public class ModelUpdateSubscriber extends LogSubscriber { + private static ModelUpdateSubscriber instance = null; + private boolean refreshRequired = false; + + private static final ILogNode LOG = ConfigurationManager.LOG; + private static final String LOG_NODE = "Core"; + private static final LogLevel LOG_LEVEL = LogLevel.INFO; + private static final String MODEL_UPDATE_MESSAGE = "Application model has been updated, application is now available."; + + public ModelUpdateSubscriber() { + super(ModelUpdateSubscriber.class.getName(), LogLevel.NONE); + } + + public static synchronized ModelUpdateSubscriber getInstance() { + if (instance == null) + instance = new ModelUpdateSubscriber(); + + return instance; + } + + public void start() { + Core.getLogger(LOG_NODE).subscribe(this, LOG_LEVEL); + LOG.debug("Subscribed to model updates"); + } + + public boolean getRefreshRequired() { + return this.refreshRequired; + } + + public void setRefreshRequired(boolean refreshRequired) { + this.refreshRequired = refreshRequired; + } + + @Override + public void processMessage(LogMessage logMessage) { + if (MODEL_UPDATE_MESSAGE.equals(logMessage.message)) { + LOG.debug("Model has been updated; require refresh of unit tests"); + this.setRefreshRequired(true); + } + } +} diff --git a/Source/javasource/unittesting/RemoteApiServlet.java b/Source/javasource/unittesting/RemoteApiServlet.java index 508a2f57..be0fd782 100644 --- a/Source/javasource/unittesting/RemoteApiServlet.java +++ b/Source/javasource/unittesting/RemoteApiServlet.java @@ -1,205 +1,205 @@ -package unittesting; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.io.IOUtils; -import org.apache.hc.client5.http.auth.InvalidCredentialsException; - -import com.mendix.core.Core; -import com.mendix.core.CoreException; -import com.mendix.externalinterface.connector.RequestHandler; -import com.mendix.logging.ILogNode; -import com.mendix.m2ee.api.IMxRuntimeRequest; -import com.mendix.m2ee.api.IMxRuntimeResponse; -import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.thirdparty.org.json.JSONArray; -import com.mendix.thirdparty.org.json.JSONObject; - -import unittesting.proxies.TestSuite; -import unittesting.proxies.UnitTest; -import unittesting.proxies.UnitTestResult; - -public class RemoteApiServlet extends RequestHandler { - - private static final Object COMMAND_START = "start"; - private static final Object COMMAND_STATUS = "status"; - private static final String PARAM_PASSWORD = "password"; - - private final String password; - private boolean detectedUnitTests = false; - - private final static ILogNode LOG = TestManager.LOG; - private volatile TestSuiteRunner testSuiteRunner; - - public RemoteApiServlet(String password) { - this.password = password; - } - - @Override - protected void processRequest(IMxRuntimeRequest req, IMxRuntimeResponse resp, String path) throws Exception { - - HttpServletRequest request = req.getHttpServletRequest(); - HttpServletResponse response = resp.getHttpServletResponse(); - - try { - if (!"POST".equals(request.getMethod())) - response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); - else if (COMMAND_START.equals(path)) - serveRunStart(request, response, path); - else if (COMMAND_STATUS.equals(path)) - serveRunStatus(request, response, path); - else - response.setStatus(HttpServletResponse.SC_NOT_FOUND); - } catch (IllegalArgumentException e) { - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - write(response, e.getMessage()); - } catch (InvalidCredentialsException e) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - write(response, "Invalid password provided"); - } - } - - private void write(HttpServletResponse response, String data) { - try { - response.getOutputStream().write(data.getBytes("UTF-8")); - } catch (Exception e) { - throw new RuntimeException(e); - } - - } - - private synchronized void serveRunStatus(HttpServletRequest request, HttpServletResponse response, String path) - throws Exception { - JSONObject input = parseInput(request); - verifyPassword(input); - - if (testSuiteRunner == null) { - throw new IllegalArgumentException("No testrun was started yet"); - } - - response.setStatus(HttpServletResponse.SC_OK); - response.setHeader("Content-Type", "application/json"); - write(response, testSuiteRunner.getStatus().toString(4)); - } - - private synchronized void serveRunStart(HttpServletRequest request, HttpServletResponse response, String path) - throws IOException, CoreException, InvalidCredentialsException { - JSONObject input = parseInput(request); - verifyPassword(input); - - IContext context = Core.createSystemContext(); - if (!detectedUnitTests) { - TestManager.instance().findAllTests(context); - detectedUnitTests = true; - } - - if (testSuiteRunner != null && !testSuiteRunner.isFinished()) { - throw new IllegalArgumentException("Cannot start a test run while another test run is still running"); - } - - LOG.info("[remote api] starting new test run"); - testSuiteRunner = new TestSuiteRunner(); - - Thread t = new Thread() { - @Override - public void run() { - testSuiteRunner.run(); - } - }; - - t.start(); - response.setStatus(HttpServletResponse.SC_NO_CONTENT); - } - - private void verifyPassword(JSONObject input) throws InvalidCredentialsException { - if (!input.has(PARAM_PASSWORD)) { - LOG.warn("[remote api] Missing password"); - throw new IllegalArgumentException( - "No '" + PARAM_PASSWORD + "' attribute found in the JSON body. Please provide a password"); - } - - if (!password.equals(input.getString(PARAM_PASSWORD))) { - LOG.warn("[remote api] Invalid password"); - throw new InvalidCredentialsException(); - } - } - - private JSONObject parseInput(HttpServletRequest request) throws IOException { - String data = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); - return new JSONObject(data); - } - - private class TestSuiteRunner { - boolean finished = false; - long startTime = System.currentTimeMillis(); - long totalTime = -1; - - public void run() { - try { - TestManager.instance().runTestSuites(); - } catch (CoreException e) { - LOG.error("[remote api] error while running test suite: " + e.getMessage(), e); - } finally { - totalTime = System.currentTimeMillis() - startTime; - finished = true; - LOG.info("[remote api] finished test run"); - } - } - - public synchronized boolean isFinished() { - return finished; - } - - public synchronized JSONObject getStatus() throws CoreException { - JSONObject result = new JSONObject(); - result.put("completed", this.finished); - result.put("runtime", totalTime); - - IContext context = Core.createSystemContext(); - long count = 0l; - long failures = 0l; - - List testSuites = Core.retrieveXPathQuery(context, - String.format("//%s", TestSuite.entityName)); - - for (IMendixObject mxObject : testSuites) { - TestSuite testSuite = TestSuite.initialize(context, mxObject); - count += testSuite.getTestCount(); - failures += testSuite.getTestFailedCount(); - } - - result.put("tests", count); - result.put("failures", failures); - - JSONArray failedTests = new JSONArray(); - result.put("failed_tests", failedTests); - - StringBuilder query = new StringBuilder(); - query.append(String.format("//%s", UnitTest.entityName)); - // Failed tests - query.append("[" + UnitTest.MemberNames.Result + "=\"" + UnitTestResult._2_Failed + "\"]"); - // In test suites that are not running anymore - query.append("[" + UnitTest.MemberNames.UnitTest_TestSuite + "/" + TestSuite.entityName + "/" - + TestSuite.MemberNames.Result + "=\"" + UnitTestResult._2_Failed + "\"]"); - - List unitTests = Core.retrieveXPathQuery(context, query.toString()); - - for (IMendixObject mxObject : unitTests) { - UnitTest test = UnitTest.initialize(context, mxObject); - JSONObject i = new JSONObject(); - i.put("name", test.getName()); - i.put("error", test.getResultMessage()); - i.put("step", test.getLastStep()); - failedTests.put(i); - } - - return result; - } - } -} +package unittesting; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.apache.hc.client5.http.auth.InvalidCredentialsException; + +import com.mendix.core.Core; +import com.mendix.core.CoreException; +import com.mendix.externalinterface.connector.RequestHandler; +import com.mendix.logging.ILogNode; +import com.mendix.m2ee.api.IMxRuntimeRequest; +import com.mendix.m2ee.api.IMxRuntimeResponse; +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.thirdparty.org.json.JSONArray; +import com.mendix.thirdparty.org.json.JSONObject; + +import unittesting.proxies.ENUM_UnitTestResult; +import unittesting.proxies.TestSuite; +import unittesting.proxies.UnitTest; + +public class RemoteApiServlet extends RequestHandler { + + private static final Object COMMAND_START = "start"; + private static final Object COMMAND_STATUS = "status"; + private static final String PARAM_PASSWORD = "password"; + + private final String password; + private boolean detectedUnitTests = false; + + private static final ILogNode LOG = ConfigurationManager.LOG; + private volatile TestSuiteRunner testSuiteRunner; + + public RemoteApiServlet(String password) { + this.password = password; + } + + @Override + protected void processRequest(IMxRuntimeRequest req, IMxRuntimeResponse resp, String path) throws Exception { + + HttpServletRequest request = req.getHttpServletRequest(); + HttpServletResponse response = resp.getHttpServletResponse(); + + try { + if (!"POST".equals(request.getMethod())) + response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); + else if (COMMAND_START.equals(path)) + serveRunStart(request, response, path); + else if (COMMAND_STATUS.equals(path)) + serveRunStatus(request, response, path); + else + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } catch (IllegalArgumentException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + write(response, e.getMessage()); + } catch (InvalidCredentialsException e) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + write(response, "Invalid password provided"); + } + } + + private void write(HttpServletResponse response, String data) { + try { + response.getOutputStream().write(data.getBytes("UTF-8")); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + private synchronized void serveRunStatus(HttpServletRequest request, HttpServletResponse response, String path) + throws Exception { + JSONObject input = parseInput(request); + verifyPassword(input); + + if (testSuiteRunner == null) { + throw new IllegalArgumentException("No testrun was started yet"); + } + + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("Content-Type", "application/json"); + write(response, testSuiteRunner.getStatus().toString(4)); + } + + private synchronized void serveRunStart(HttpServletRequest request, HttpServletResponse response, String path) + throws IOException, CoreException, InvalidCredentialsException { + JSONObject input = parseInput(request); + verifyPassword(input); + + IContext context = Core.createSystemContext(); + if (!detectedUnitTests) { + TestManager.instance().findAllTests(context); + detectedUnitTests = true; + } + + if (testSuiteRunner != null && !testSuiteRunner.isFinished()) { + throw new IllegalArgumentException("Cannot start a test run while another test run is still running"); + } + + LOG.info("[remote api] starting new test run"); + testSuiteRunner = new TestSuiteRunner(); + + Thread t = new Thread() { + @Override + public void run() { + testSuiteRunner.run(); + } + }; + + t.start(); + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + } + + private void verifyPassword(JSONObject input) throws InvalidCredentialsException { + if (!input.has(PARAM_PASSWORD)) { + LOG.warn("[remote api] Missing password"); + throw new IllegalArgumentException( + "No '" + PARAM_PASSWORD + "' attribute found in the JSON body. Please provide a password"); + } + + if (!password.equals(input.getString(PARAM_PASSWORD))) { + LOG.warn("[remote api] Invalid password"); + throw new InvalidCredentialsException(); + } + } + + private JSONObject parseInput(HttpServletRequest request) throws IOException { + String data = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); + return new JSONObject(data); + } + + private class TestSuiteRunner { + boolean finished = false; + long startTime = System.currentTimeMillis(); + long totalTime = -1; + + public void run() { + try { + TestManager.instance().runTestSuites(); + } catch (CoreException e) { + LOG.error("[remote api] error while running test suite: " + e.getMessage(), e); + } finally { + totalTime = System.currentTimeMillis() - startTime; + finished = true; + LOG.info("[remote api] finished test run"); + } + } + + public synchronized boolean isFinished() { + return finished; + } + + public synchronized JSONObject getStatus() throws CoreException { + JSONObject result = new JSONObject(); + result.put("completed", this.finished); + result.put("runtime", totalTime); + + IContext context = Core.createSystemContext(); + long count = 0l; + long failures = 0l; + + List testSuites = Core.createXPathQuery(String.format("//%s", TestSuite.entityName)) + .execute(context); + + for (IMendixObject mxObject : testSuites) { + TestSuite testSuite = TestSuite.initialize(context, mxObject); + count += testSuite.getTestCount(); + failures += testSuite.getTestFailedCount(); + } + + result.put("tests", count); + result.put("failures", failures); + + JSONArray failedTests = new JSONArray(); + result.put("failed_tests", failedTests); + + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", UnitTest.entityName)); + // Failed tests + query.append("[" + UnitTest.MemberNames.Result + "=\"" + ENUM_UnitTestResult._2_Failed + "\"]"); + // In test suites that are not running anymore + query.append("[" + UnitTest.MemberNames.UnitTest_TestSuite + "/" + TestSuite.entityName + "/" + + TestSuite.MemberNames.Result + "=\"" + ENUM_UnitTestResult._2_Failed + "\"]"); + + List unitTests = Core.createXPathQuery(query.toString()).execute(context); + + for (IMendixObject mxObject : unitTests) { + UnitTest test = UnitTest.initialize(context, mxObject); + JSONObject i = new JSONObject(); + i.put("name", test.getName()); + i.put("error", test.getResultMessage()); + i.put("step", test.getLastStep()); + failedTests.put(i); + } + + return result; + } + } +} diff --git a/Source/javasource/unittesting/TestExecutionContext.java b/Source/javasource/unittesting/TestExecutionContext.java new file mode 100644 index 00000000..f742324e --- /dev/null +++ b/Source/javasource/unittesting/TestExecutionContext.java @@ -0,0 +1,252 @@ +package unittesting; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import com.mendix.core.Core; +import com.mendix.logging.ILogNode; +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.IMendixObject; + +import unittesting.activities.StartEndExecutionActivity; +import unittesting.activities.StepExecutionActivity; +import unittesting.activities.ExceptionExecutionActivity; + +import unittesting.proxies.*; + +public class TestExecutionContext { + private final UnitTestContext unitTestContext; + private final ArrayList steps = new ArrayList<>(); + + private StartEndExecutionActivity startActivity; + private StartEndExecutionActivity endActivity; + private ExceptionExecutionActivity exceptionActivity; + private int activitySequence = 0; + + private static final ILogNode LOG = ConfigurationManager.LOG; + + public TestExecutionContext(IContext context, String mf) { + UnitTestContext testContext = new UnitTestContext(context); + testContext.setTestName(mf); + + LOG.trace("Created unit test context for " + mf); + this.unitTestContext = testContext; + } + + public UnitTestContext getUnitTestContext() { + return this.unitTestContext; + } + + public void delete() { + if (this.unitTestContext == null) + return; + + this.unitTestContext.delete(); + LOG.trace("Deleted unit test context"); + } + + public void collectStart(boolean result, String message) { + this.startActivity = new StartEndExecutionActivity(getNextSequence(), result, message); + } + + public void collectEnd(boolean result, String message) { + this.endActivity = new StartEndExecutionActivity(getNextSequence(), result, message); + } + + public void collectException(Exception exception) { + this.exceptionActivity = new ExceptionExecutionActivity(getNextSequence(), exception); + } + + public Assertion collectAssertion(IContext context, String name, boolean result, String failureMessage) { + ENUM_UnitTestResult testResult = result ? ENUM_UnitTestResult._3_Success : ENUM_UnitTestResult._2_Failed; + + Assertion assertion = new Assertion(context); + assertion.setAssertion_UnitTestContext(this.unitTestContext); + assertion.setSequence(getNextSequence()); + assertion.setName(name); + assertion.setResult(testResult); + + if (testResult.equals(ENUM_UnitTestResult._2_Failed)) + assertion.setMessage(failureMessage); + + return assertion; + } + + public void collectStep(String message) { + LOG.debug("Report step: " + message); + this.steps.add(new StepExecutionActivity(getNextSequence(), message)); + } + + public StepExecutionActivity getLastStep() { + return !this.steps.isEmpty() ? this.steps.get(this.steps.size() - 1) : null; + } + + public boolean hasFailedAssertion(IContext context) { + List assertionList = Core.retrieveByPath(context, this.unitTestContext.getMendixObject(), + Assertion.MemberNames.Assertion_UnitTestContext.toString()); + + return assertionList.stream().anyMatch(obj -> isFailedAssertion(context, obj)); + } + + private boolean isFailedAssertion(IContext context, IMendixObject object) { + return ENUM_UnitTestResult._2_Failed.equals(Assertion.initialize(context, object).getResult()); + } + + public ArrayList getFailureReasons(IContext context) { + ArrayList failures = new ArrayList<>(); + + if (this.startActivity != null && !this.startActivity.getResult()) + failures.add("Failed to start test"); + + if (this.hasFailedAssertion(context)) + failures.add("One or more assertions failed"); + + if (this.endActivity != null && !this.endActivity.getResult()) + failures.add("Microflow return value is incorrect"); + + if (this.exceptionActivity != null) + failures.add("An uncaught exception occurred"); + + return failures; + } + + public String getResultSummary(IContext context) { + ArrayList failureReasons = this.getFailureReasons(context); + + if (failureReasons.isEmpty()) { + return "Microflow completed successfully"; + } else { + StringBuilder message = new StringBuilder(); + + for (int i = 0; i < failureReasons.size(); i++) { + if (i > 0) message.append("\n"); + message.append(failureReasons.get(i)); + } + + return message.toString(); + } + } + + public void persistTestActivities(IContext context, UnitTest test) { + List activities = this.createTestActivities(context, test); + Core.commit(Core.createSystemContext(), activities); + } + + public List createTestActivities(IContext context, UnitTest test) { + List activities = new ArrayList<>(); + + if (this.startActivity != null) + activities.add(createStartActivity(test)); + + activities.addAll(createAssertionActivities(context, test)); + activities.addAll(createStepActivities(test)); + + if (this.endActivity != null) + activities.add(createEndActivity(test)); + + if (this.exceptionActivity != null) + activities.add(createExceptionActivity(test)); + + return activities; + } + + private List createAssertionActivities(IContext context, UnitTest test) { + List assertionList = Core.retrieveByPath(context, this.unitTestContext.getMendixObject(), + Assertion.MemberNames.Assertion_UnitTestContext.toString()); + + return assertionList.stream() + .map(assertion -> createAssertionActivity(test, assertion)) + .collect(Collectors.toList()); + } + + private List createStepActivities(UnitTest test) { + return this.steps.stream() + .map(step -> createStepActivity(test, step)) + .collect(Collectors.toList()); + } + + private IMendixObject createStartActivity(UnitTest test) { + if (this.startActivity == null) + throw new IllegalStateException("No start activity collected"); + + StartActivity startActivity = new StartActivity(Core.createSystemContext()); + startActivity.setTestActivity_UnitTest(test); + startActivity.setSequence(this.startActivity.getSequence()); + startActivity.setResult(this.startActivity.getResultEnum()); + startActivity.setMessage(this.startActivity.getMessage()); + + return startActivity.getMendixObject(); + } + + private IMendixObject createEndActivity(UnitTest test) { + if (this.endActivity == null) + throw new IllegalStateException("No end activity collected"); + + EndActivity endActivity = new EndActivity(Core.createSystemContext()); + endActivity.setTestActivity_UnitTest(test); + endActivity.setSequence(this.endActivity.getSequence()); + endActivity.setResult(this.endActivity.getResultEnum()); + endActivity.setMessage(this.endActivity.getMessage()); + + return endActivity.getMendixObject(); + } + + private IMendixObject createExceptionActivity(UnitTest test) { + if (this.exceptionActivity == null) + throw new IllegalStateException("No exception collected"); + + Exception exception = this.exceptionActivity.getException(); + Throwable cause = ExceptionUtils.getRootCause(exception); + + ExceptionActivity exceptionActivity = new ExceptionActivity(Core.createSystemContext()); + exceptionActivity.setTestActivity_UnitTest(test); + exceptionActivity.setSequence(this.exceptionActivity.getSequence()); + exceptionActivity.setMessage(cause.getMessage()); + exceptionActivity.setStackTrace(ExceptionUtils.getStackTrace(exception)); + + return exceptionActivity.getMendixObject(); + } + + private IMendixObject createAssertionActivity(UnitTest test, IMendixObject assertionObj) { + IContext systemContext = Core.createSystemContext(); + Assertion assertion = Assertion.initialize(systemContext, assertionObj); + + AssertionActivity assertionActivity = new AssertionActivity(systemContext); + assertionActivity.setTestActivity_UnitTest(test); + assertionActivity.setSequence(assertion.getSequence()); + assertionActivity.setName(assertion.getName()); + assertionActivity.setResult(assertion.getResult()); + assertionActivity.setMessage(assertion.getMessage()); + + return assertionActivity.getMendixObject(); + } + + private IMendixObject createStepActivity(UnitTest test, StepExecutionActivity step) { + StepActivity stepActivity = new StepActivity(Core.createSystemContext()); + stepActivity.setTestActivity_UnitTest(test); + stepActivity.setSequence(step.getSequence()); + stepActivity.setMessage(step.getMessage()); + + return stepActivity.getMendixObject(); + } + + public void clearTestActivities(UnitTest test) { + IContext systemContext = Core.createSystemContext(); + + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", TestActivity.entityName)); + query.append(String.format("[%s=$UnitTest]", TestActivity.MemberNames.TestActivity_UnitTest)); + + List activities = Core.createXPathQuery(query.toString()) + .setVariable("UnitTest", test.getMendixObject().getId().toLong()).execute(systemContext); + + Core.delete(systemContext, activities); + } + + private int getNextSequence() { + return activitySequence++; + } +} diff --git a/Source/javasource/unittesting/TestManager.java b/Source/javasource/unittesting/TestManager.java index 9f8aa3e6..128403d3 100644 --- a/Source/javasource/unittesting/TestManager.java +++ b/Source/javasource/unittesting/TestManager.java @@ -1,689 +1,662 @@ -package unittesting; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; - -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.junit.Test; -import org.junit.runner.Description; -import org.junit.runner.JUnitCore; -import org.junit.runner.Request; -import org.junit.runners.JUnit4; -import org.junit.runners.model.FrameworkMethod; -import org.junit.runners.model.InitializationError; - -import com.mendix.core.Core; -import com.mendix.core.CoreException; -import com.mendix.logging.ILogNode; -import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.systemwideinterfaces.core.IDataType; -import com.mendix.systemwideinterfaces.core.IMendixObject; - -import unittesting.proxies.TestSuite; -import unittesting.proxies.UnitTest; -import unittesting.proxies.UnitTestResult; - -/** - * @author mwe - * - */ -public class TestManager { - /** - * Test manager introduces its own exception, because the AssertionExceptions - * from JUnit are not picked up properly by the runtime in 4.1.1 and escape all - * exception handling defined inside microflows :-S - * - * @author mwe - * - */ - public static class AssertionException extends Exception { - private static final long serialVersionUID = -3115796226784699883L; - - public AssertionException(String message) { - super(message); - } - } - - static final String CLOUD_SECURITY_ERROR = "Unable to find JUnit test classes or methods. \n\n"; - - private static TestManager instance; - public static ILogNode LOG = Core.getLogger("UnitTestRunner"); - - private static final Map[]> classCache = new HashMap[]>(); - - private IContext setupContext; - - private String lastStep; - - public static TestManager instance() { - if (instance == null) - instance = new TestManager(); - return instance; - } - - private static Class[] getUnitTestClasses(TestSuite testRun) throws ZipException, IOException { - if (!classCache.containsKey(testRun.getModule().toLowerCase())) { - - ArrayList> classlist = getClassesForPackage(testRun.getModule()); - Class[] clazzez = classlist.toArray(new Class[classlist.size()]); - classCache.put(testRun.getModule().toLowerCase(), clazzez); - } - - return classCache.get(testRun.getModule().toLowerCase()); - } - - public synchronized void runTest(IContext context, UnitTest unitTest) throws ClassNotFoundException, CoreException { - TestSuite testSuite = unitTest.getUnitTest_TestSuite(); - - /** - * Is Mf - */ - if (unitTest.getIsMf()) { - try { - runMfSetup(testSuite); - runMicroflowTest(unitTest.getName(), unitTest); - } finally { - runMfTearDown(testSuite); - } - } - - /** - * Is java - */ - else { - String[] parts = unitTest.getName().split("/"); - Request request; - if (parts.length == 1) // class-scale test run - request = Request.aClass(Class.forName(parts[0])); - else if (parts.length == 2) // method-scale test run - request = Request.method(Class.forName(parts[0]), parts[1]); - else - throw new CoreException("Invalid test specification: " + unitTest.getName() - + "\nTest method run should be defined in either form $testClass or $testClass/$testMethod."); - - JUnitCore junit = new JUnitCore(); - junit.addListener(new UnitTestRunListener(context, testSuite)); - - junit.run(request); - } - updateTestSuiteFailedCountAndResult(context, testSuite); - } - - private void runMfSetup(TestSuite testSuite) { - if (Core.getMicroflowNames().contains(testSuite.getModule() + ".Setup")) { - try { - LOG.info("Running Setup microflow.."); - if (testSuite.getAutoRollbackMFs()) { - setupContext = Core.createSystemContext(); - setupContext.startTransaction(); - LOG.trace("Start transaction for setup"); - Core.microflowCall(testSuite.getModule() + ".Setup").execute(setupContext); - } else { - Core.microflowCall(testSuite.getModule() + ".Setup").execute(Core.createSystemContext()); - } - } catch (Exception e) { - LOG.error("Exception during SetUp microflow: " + e.getMessage(), e); - throw new RuntimeException(e); - } - } - } - - private void runMfTearDown(TestSuite testSuite) { - IContext tearDownContext = setupContext; - if (Core.getMicroflowNames().contains(testSuite.getModule() + ".TearDown")) { - try { - LOG.info("Running TearDown microflow.."); - if (tearDownContext == null) { - tearDownContext = Core.createSystemContext(); - - if (testSuite.getAutoRollbackMFs()) { - tearDownContext.startTransaction(); - LOG.trace("Start transaction for teardown"); - } - } - - Core.microflowCall(testSuite.getModule() + ".TearDown").execute(tearDownContext); - } catch (Exception e) { - LOG.error("Severe: exception in unittest TearDown microflow '" + testSuite.getModule() + ".TearDown': " - + e.getMessage(), e); - throw new RuntimeException(e); - } - } - - // Rollback teardown and/or setup transaction - if (testSuite.getAutoRollbackMFs() && tearDownContext != null) { - LOG.trace("Rollback transaction for setup and/or teardown"); - tearDownContext.rollbackTransaction(); - } - - // Make sure we clean setupContext after running this test/suite - setupContext = null; - } - - public synchronized void runTestSuites() throws CoreException { - LOG.info("Starting testrun on all suites"); - - // Context without transaction! - IContext context = Core.createSystemContext(); - - List testsuites = Core.retrieveXPathQuery(context, "//" + TestSuite.entityName); - - for (IMendixObject suite : testsuites) { - suite.setValue(context, TestSuite.MemberNames.Result.toString(), null); - ; - } - Core.commit(context, testsuites); - - for (IMendixObject suite : testsuites) { - runTestSuite(context, TestSuite.load(context, suite.getId())); - } - - LOG.info("Finished testrun on all suites"); - } - - public synchronized boolean runTestSuite(IContext context, TestSuite testSuite) throws CoreException { - LOG.info("Starting testrun on " + testSuite.getModule()); - - /** - * Reset state - */ - testSuite.setLastRun(new Date()); - testSuite.setLastRunTime(0L); - testSuite.setTestFailedCount(0L); - testSuite.setResult(UnitTestResult._1_Running); - testSuite.commit(); - - StringBuilder query = new StringBuilder(); - query.append(String.format("//%s", UnitTest.entityName)); - query.append(String.format("[%s=$TestSuite]", UnitTest.MemberNames.UnitTest_TestSuite)); - - List unitTests = Core.createXPathQuery(query.toString()) - .setVariable("TestSuite", testSuite.getMendixObject().getId().toLong()).execute(context); - - for (IMendixObject mxObject : unitTests) { - UnitTest test = UnitTest.initialize(context, mxObject); - test.setResult(null); - test.commit(); - } - - long start = System.currentTimeMillis(); - - /** - * Run java unit tests - */ - if (unittesting.proxies.constants.Constants.getFindJUnitTests()) { - Class[] clazzez = null; - try { - clazzez = getUnitTestClasses(testSuite); - } catch (Exception e) { - LOG.error(CLOUD_SECURITY_ERROR + e.getMessage(), e); - } - - if (clazzez != null && clazzez.length > 0) { - JUnitCore junit = new JUnitCore(); - junit.addListener(new UnitTestRunListener(context, testSuite)); - - junit.run(clazzez); - } - } - /** - * Run microflow tests - * - */ - - try { - runMfSetup(testSuite); - - List mfnames = findMicroflowUnitTests(testSuite); - - for (String mf : mfnames) { - if (!runMicroflowTest(mf, getUnitTest(context, testSuite, mf, true), testSuite)) { - testSuite.setTestFailedCount(testSuite.getTestFailedCount() + 1); - testSuite.commit(); - } - } - - } finally { - runMfTearDown(testSuite); - } - - /** - * Aggregate - */ - testSuite.setLastRunTime((System.currentTimeMillis() - start) / 1000); - testSuite - .setResult(testSuite.getTestFailedCount() == 0L ? UnitTestResult._3_Success : UnitTestResult._2_Failed); - testSuite.commit(); - - LOG.info("Finished testrun on " + testSuite.getModule()); - return true; - } - - public List findMicroflowUnitTests(TestSuite testRun) { - List mfnames = new ArrayList(); - - if (testRun.getPrefix1() == null) { - testRun.setPrefix1("Test_"); - } - if (testRun.getPrefix2() == null) { - testRun.setPrefix2("UT_"); - } - - String basename1 = (testRun.getModule() + "." + testRun.getPrefix1()).toLowerCase(); - String basename2 = (testRun.getModule() + "." + testRun.getPrefix2()).toLowerCase(); - - // Find microflownames - for (String mf : Core.getMicroflowNames()) - if (mf.toLowerCase().startsWith(basename1) || mf.toLowerCase().startsWith(basename2)) - mfnames.add(mf); - - // Sort microflow names - Collections.sort(mfnames); - return mfnames; - } - - private boolean runMicroflowTest(String mf, UnitTest test) throws CoreException { - /** - * Prepare... - */ - TestSuite testSuite = test.getUnitTest_TestSuite(); - - return runMicroflowTest(mf, test, testSuite); - } - - private boolean runMicroflowTest(String mf, UnitTest test, TestSuite testSuite) throws CoreException { - /** - * Prepare... - */ - LOG.info("Starting unittest for microflow " + mf); - - reportStep("Starting microflow test '" + mf + "'"); - - test.setResult(UnitTestResult._1_Running); - test.setName(mf); - test.setResultMessage(""); - test.setLastRun(new Date()); - - if (Core.getInputParameters(mf).size() != 0) { - test.setResultMessage("Unable to start test '" + mf + "', microflow has parameters"); - test.setResult(UnitTestResult._2_Failed); - } else if (Core.getReturnType(mf).getType() != IDataType.DataTypeEnum.Boolean - && Core.getReturnType(mf).getType() != IDataType.DataTypeEnum.String - && Core.getReturnType(mf).getType() != IDataType.DataTypeEnum.Nothing) { - - test.setResultMessage("Unable to start test '" + mf - + "', microflow should return either a boolean or a string or nothing at all"); - - test.setResult(UnitTestResult._2_Failed); - } - - commitSilent(test); - - IContext mfContext = null; - - if (testSuite.getAutoRollbackMFs()) { - if (Core.getMicroflowNames().contains(testSuite.getModule() + ".Setup")) - mfContext = setupContext.clone(); - else - mfContext = Core.createSystemContext(); - - mfContext.startTransaction(); - LOG.trace("Start transaction for unit test"); - } else { - mfContext = Core.createSystemContext(); - } - - long start = System.currentTimeMillis(); - - try { - Object resultObject = Core.microflowCall(mf).execute(mfContext); - - start = System.currentTimeMillis() - start; - boolean res = resultObject == null || Boolean.TRUE.equals(resultObject) || "".equals(resultObject); - - test.setResult(res ? UnitTestResult._3_Success : UnitTestResult._2_Failed); - - if (res) { - test.setResultMessage("Microflow completed successfully"); - } else if (resultObject instanceof String) { - test.setResultMessage((String) resultObject); - } - - return res; - } catch (Exception e) { - start = System.currentTimeMillis() - start; - test.setResult(UnitTestResult._2_Failed); - Throwable cause = ExceptionUtils.getRootCause(e); - if (cause != null && cause instanceof AssertionException) - test.setResultMessage(cause.getMessage()); - else - test.setResultMessage("Exception: " + e.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(e)); - return false; - - } finally { - if (testSuite.getAutoRollbackMFs() && mfContext.isInTransaction()) { - LOG.trace("Rollback transaction for unit test"); - mfContext.rollbackTransaction(); - } - test.setLastStep(lastStep); - test.setReadableTime((start > 10000 ? Math.round(start / 1000) + " seconds" : start + " milliseconds")); - commitSilent(test); - - LOG.info("Finished unittest " + mf + ": " + test.getResult()); - } - } - - private void updateTestSuiteFailedCountAndResult(IContext context, TestSuite testSuite) throws CoreException { - long testSuiteObjectId = testSuite.getMendixObject().getId().toLong(); - - StringBuilder baseQuery = new StringBuilder(); - baseQuery.append(String.format("//%s", UnitTest.entityName)); - baseQuery.append(String.format("[%s=$TestSuite]", UnitTest.MemberNames.UnitTest_TestSuite)); - - long failedCount = Core.createXPathQuery(baseQuery + "[Result = '_2_Failed']") - .setVariable("TestSuite", testSuiteObjectId).execute(context).size(); - - if (failedCount > 0) { - testSuite.setResult(UnitTestResult._2_Failed); - testSuite.setTestFailedCount(failedCount); - testSuite.commit(); - LOG.trace("Update test suite failed count to " + failedCount + " and result to 'Failed'"); - return; - } - - long pendingCount = Core.createXPathQuery(baseQuery + "[(Result = '_1_Running' or Result = empty)]") - .setVariable("TestSuite", testSuiteObjectId).execute(context).size(); - - if (pendingCount > 0) - return; - - testSuite.setResult(UnitTestResult._3_Success); - testSuite.setTestFailedCount(0L); - testSuite.commit(); - LOG.trace("Reset test suite failed count and update result to 'Success'"); - } - - private void commitSilent(UnitTest test) { - try { - test.commit(); - } catch (CoreException e) { - throw new RuntimeException(e); - } - } - - UnitTest getUnitTest(IContext context, TestSuite testSuite, Description description, boolean isMF) { - return getUnitTest(context, testSuite, description.getClassName() + "/" + description.getMethodName(), isMF); - } - - private UnitTest getUnitTest(IContext context, TestSuite testSuite, String name, boolean isMF) { - StringBuilder query = new StringBuilder(); - query.append(String.format("//%s", UnitTest.entityName)); - query.append(String.format("[%s=$TestSuite]", UnitTest.MemberNames.UnitTest_TestSuite)); - query.append(String.format("[%s=$Name]", UnitTest.MemberNames.Name)); - query.append(String.format("[%s=$IsMicroflow]", UnitTest.MemberNames.IsMf)); - - Optional mxObject = Core.createXPathQuery(query.toString()) - .setVariable("TestSuite", testSuite.getMendixObject().getId()).setVariable("Name", name) - .setVariable("IsMicroflow", isMF).execute(context).stream().findAny(); - - if (mxObject.isPresent()) { - return UnitTest.initialize(context, mxObject.get()); - } else { - UnitTest newTest = new UnitTest(context); - newTest.setName(name); - newTest.setUnitTest_TestSuite(testSuite); - newTest.setIsMf(isMF); - - return newTest; - } - } - - /** - * - * - * Find runabble classes - * - * https://github.com/ddopson/java-class-enumerator/blob/master/src/pro/ddopson/ClassEnumerator.java - * - */ - - private static Class loadClass(String className) { - try { - return TestManager.instance().getClass().getClassLoader().loadClass(className); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Unexpected ClassNotFoundException loading class '" + className + "'"); - } - } - - private static void processProjectJar(File projectJar, String pkgname, ArrayList> classes) - throws IOException { - // Get the list of the files contained in the package - - ZipFile zipFile = new ZipFile(projectJar); - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry zipEntry = entries.nextElement(); - String fileName = zipEntry.getName(); - - String className = null; - - if (fileName.startsWith(pkgname.concat("/")) && fileName.endsWith(".class")) { - fileName = fileName.replace("/", "."); - // removes the .class extension - className = fileName.substring(0, fileName.length() - 6); - } - if (className != null) { - Class clazz = loadClass(className); - if (isProperUnitTest(clazz)) - classes.add(clazz); - } - } - zipFile.close(); - } - - private static boolean isProperUnitTest(Class clazz) { - for (Method m : clazz.getMethods()) - if (m.getAnnotation(org.junit.Test.class) != null) - return true; - - return false; - - } - - public static ArrayList> getClassesForPackage(String path /* Package pkg */) - throws ZipException, IOException { - ArrayList> classes = new ArrayList>(); - - // String pkgname = pkg.getName(); - // String relPath = pkgname.replace('.', '/'); - - // Lowercased Mendix Module names equals their package names - String pkgname = path.toLowerCase(); - - // Get a File object containing the classes. This file is expected to be located - // at [deploymentdir]/model/bundles/project.jar - File projectjar = new File(Core.getConfiguration().getBasePath() + File.separator + "model" + File.separator - + "bundles" + File.separator + "project.jar"); - - processProjectJar(projectjar, pkgname, classes); - - return classes; - } - - public void reportStep(String lastStep1) { - lastStep = lastStep1; - LOG.debug("UnitTest reportStep: '" + lastStep1 + "'"); - } - - public synchronized void findAllTests(IContext context) throws CoreException { - /* - * Find modules - */ - Set modules = new HashSet(); - for (String name : Core.getMicroflowNames()) - modules.add(name.split("\\.")[0]); - - /* - * Update modules - */ - for (String module : modules) { - TestSuite testSuite = findOrCreateTestSuite(context, module); - updateUnitTestList(context, testSuite); - } - - /* - * Remove all modules without tests - */ - deleteTestSuitesWithoutTest(context); - } - - private synchronized TestSuite findOrCreateTestSuite(IContext context, String module) throws CoreException { - StringBuilder query = new StringBuilder(); - query.append(String.format("//%s", TestSuite.entityName)); - query.append(String.format("[%s=$Module]", TestSuite.MemberNames.Module)); - - Optional mxObject = Core.createXPathQuery(query.toString()).setVariable("Module", module) - .execute(context).stream().findAny(); - - if (mxObject.isPresent()) { - return TestSuite.initialize(context, mxObject.get()); - } else { - TestSuite newSuite = new TestSuite(context); - newSuite.setModule(module); - newSuite.commit(); - - return newSuite; - } - } - - private synchronized void deleteTestSuitesWithoutTest(IContext context) throws CoreException { - StringBuilder query = new StringBuilder(); - query.append(String.format("//%s", TestSuite.entityName)); - query.append("[not(" + UnitTest.MemberNames.UnitTest_TestSuite + "/" + UnitTest.entityName + ")]"); - - List testSuites = Core.retrieveXPathQuery(context, query.toString()); - Core.delete(context, testSuites); - } - - public synchronized void updateUnitTestList(IContext context, TestSuite testSuite) { - try { - /* - * Mark all dirty - */ - StringBuilder query = new StringBuilder(); - query.append(String.format("//%s", UnitTest.entityName)); - query.append(String.format("[%s=$TestSuite]", UnitTest.MemberNames.UnitTest_TestSuite)); - - List unitTests = Core.createXPathQuery(query.toString()) - .setVariable("TestSuite", testSuite.getMendixObject().getId().toLong()).execute(context); - - for (IMendixObject mxObject : unitTests) { - UnitTest test = UnitTest.initialize(context, mxObject); - test.set_dirty(true); - test.commit(); - } - - /* - * Find microflow tests - */ - for (String mf : findMicroflowUnitTests(testSuite)) { - UnitTest test = getUnitTest(context, testSuite, mf, true); - test.set_dirty(false); - test.setUnitTest_TestSuite(testSuite); - test.commit(); - } - - if (unittesting.proxies.constants.Constants.getFindJUnitTests()) { - /* - * Find Junit tests - */ - for (String jtest : findJUnitTests(testSuite)) { - UnitTest test = getUnitTest(context, testSuite, jtest, false); - test.set_dirty(false); - test.setUnitTest_TestSuite(testSuite); - test.commit(); - } - } - - /* - * Delete dirty tests - */ - StringBuilder deleteQuery = new StringBuilder(); - deleteQuery.append(String.format("//%s", UnitTest.entityName)); - deleteQuery.append(String.format("[%s=true]", UnitTest.MemberNames._dirty)); - - List dirtyTests = Core.retrieveXPathQuery(context, deleteQuery.toString()); - Core.delete(context, dirtyTests); - - /* - * Update count - */ - StringBuilder countQuery = new StringBuilder(); - countQuery.append(String.format("//%s", UnitTest.entityName)); - countQuery.append(String.format("[%s=" + testSuite.getMendixObject().getId().toLong() + "]", - UnitTest.MemberNames.UnitTest_TestSuite)); - Long testCount = Core.retrieveXPathQueryAggregate(context, "count(" + countQuery.toString() + ")"); - - testSuite.setTestCount(testCount); - testSuite.commit(); - - } catch (Exception e) { - LOG.error("Failed to update unit test list: " + e.getMessage(), e); - } - - } - - public List findJUnitTests(TestSuite testSuite) { - List junitTests = new ArrayList(); - try { - Class[] clazzez = getUnitTestClasses(testSuite); - - if (clazzez != null && clazzez.length > 0) { - for (Class clazz : clazzez) { - - // From - // https://github.com/KentBeck/junit/blob/master/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java - // method computeTestMethods - try { - List methods = new JUnit4(clazz).getTestClass() - .getAnnotatedMethods(Test.class); - - if (methods != null && !methods.isEmpty()) - for (FrameworkMethod method : methods) - junitTests.add(clazz.getName() + "/" + method.getName()); - } catch (InitializationError e2) { - StringBuilder errors = new StringBuilder(); - - for (Throwable cause : e2.getCauses()) - errors.append("\n").append(cause.getMessage()); - - LOG.error("Failed to recognize class '" + clazz + "' as unitTestClass: " + errors.toString()); - } - } - } - } catch (Exception e) { - LOG.error(CLOUD_SECURITY_ERROR + e.getMessage(), e); - } - return junitTests; - } - - public String getLastReportedStep() { - // MWE: this system is problematic weird if used from multiple simultanously - // used threads.. - return lastStep; - } -} +package unittesting; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.Request; + +import com.mendix.core.Core; +import com.mendix.core.CoreException; +import com.mendix.core.actionmanagement.MicroflowCallBuilder; +import com.mendix.logging.ILogNode; +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.IDataType; +import com.mendix.systemwideinterfaces.core.IMendixObject; + +import unittesting.proxies.ENUM_UnitTestResult; +import unittesting.proxies.TestSuite; +import unittesting.proxies.UnitTest; + +/** + * @author mwe + * + */ +public class TestManager { + /** + * Test manager introduces its own exception, because the AssertionExceptions + * from JUnit are not picked up properly by the runtime in 4.1.1 and escape all + * exception handling defined inside microflows :-S + * + * @author mwe + * + */ + public static class AssertionException extends Exception { + private static final long serialVersionUID = -3115796226784699883L; + + public AssertionException(String message) { + super(message); + } + } + + private static final ILogNode LOG = ConfigurationManager.LOG; + private static final String TEST_CONTEXT_PARAM_NAME = "UnitTestContext"; + + private static TestManager instance; + + private IContext setupContext; + private TestExecutionContext executionContext; + private String lastStep; // Only applicable for JUnit tests + + public static TestManager instance() { + if (instance == null) + instance = new TestManager(); + return instance; + } + + public TestExecutionContext executionContext() { + if (executionContext == null) + throw new IllegalStateException("No execution context available"); + + return executionContext; + } + + public synchronized void runTest(IContext context, UnitTest unitTest) throws ClassNotFoundException, CoreException { + if (!ConfigurationManager.verifyModuleIsEnabled()) return; + + TestSuite testSuite = unitTest.getUnitTest_TestSuite(); + + /** + * Is Mf + */ + if (unitTest.getIsMf()) { + try { + runMfSetup(testSuite); + runMicroflowTest(unitTest.getName(), unitTest); + } finally { + runMfTearDown(testSuite); + } + } + + /** + * Is java + */ + else { + String[] parts = unitTest.getName().split("/"); + Request request; + if (parts.length == 1) // class-scale test run + request = Request.aClass(Class.forName(parts[0])); + else if (parts.length == 2) // method-scale test run + request = Request.method(Class.forName(parts[0]), parts[1]); + else + throw new CoreException("Invalid test specification: " + unitTest.getName() + + "\nTest method run should be defined in either form $testClass or $testClass/$testMethod."); + + JUnitCore junit = new JUnitCore(); + junit.addListener(new UnitTestRunListener(context, testSuite)); + + junit.run(request); + } + + updateTestSuiteCountersAndResult(context, testSuite, true); + } + + private void runMfSetup(TestSuite testSuite) { + if (hasMfSetup(testSuite)) { + try { + LOG.info("Running Setup microflow.."); + if (testSuite.getAutoRollbackMFs()) { + setupContext = Core.createSystemContext(); + setupContext.startTransaction(); + LOG.trace("Start transaction for setup"); + Core.microflowCall(testSuite.getModule() + ".Setup").execute(setupContext); + } else { + Core.microflowCall(testSuite.getModule() + ".Setup").execute(Core.createSystemContext()); + } + } catch (Exception e) { + LOG.error("Exception during SetUp microflow: " + e.getMessage(), e); + throw new RuntimeException(e); + } + } + } + + private void runMfTearDown(TestSuite testSuite) { + IContext tearDownContext = setupContext; + if (hasMfTearDown(testSuite)) { + try { + LOG.info("Running TearDown microflow.."); + if (tearDownContext == null) { + tearDownContext = Core.createSystemContext(); + + if (testSuite.getAutoRollbackMFs()) { + tearDownContext.startTransaction(); + LOG.trace("Start transaction for teardown"); + } + } + + Core.microflowCall(testSuite.getModule() + ".TearDown").execute(tearDownContext); + } catch (Exception e) { + LOG.error("Severe: exception in unittest TearDown microflow '" + testSuite.getModule() + ".TearDown': " + + e.getMessage(), e); + throw new RuntimeException(e); + } + } + + // Rollback teardown and/or setup transaction + if (testSuite.getAutoRollbackMFs() && tearDownContext != null) { + LOG.trace("Rollback transaction for setup and/or teardown"); + tearDownContext.rollbackTransaction(); + } + + // Make sure we clean setupContext after running this test/suite + setupContext = null; + } + + public synchronized void runTestSuites() throws CoreException { + if (!ConfigurationManager.verifyModuleIsEnabled()) return; + + LOG.info("Starting testrun on all suites"); + + // Context without transaction! + IContext context = Core.createSystemContext(); + + List testSuites = Core.createXPathQuery("//" + TestSuite.entityName).execute(context); + + for (IMendixObject suite : testSuites) { + suite.setValue(context, TestSuite.MemberNames.Result.toString(), null); + } + Core.commit(context, testSuites); + + for (IMendixObject suite : testSuites) { + runTestSuite(context, TestSuite.load(context, suite.getId())); + } + + LOG.info("Finished testrun on all suites"); + } + + public synchronized void runTestSuite(IContext context, TestSuite testSuite) throws CoreException { + if (!ConfigurationManager.verifyModuleIsEnabled()) return; + + LOG.info("Starting testrun on " + testSuite.getModule()); + + /** + * Reset state + */ + testSuite.setLastRun(new Date()); + testSuite.setLastRunTime(0L); + testSuite.setTestPassedCount(0L); + testSuite.setTestFailedCount(0L); + testSuite.setResult(ENUM_UnitTestResult._1_Running); + testSuite.commit(); + + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", UnitTest.entityName)); + query.append(String.format("[%s=$TestSuite]", UnitTest.MemberNames.UnitTest_TestSuite)); + + List unitTests = Core.createXPathQuery(query.toString()) + .setVariable("TestSuite", testSuite.getMendixObject().getId().toLong()).execute(context); + + for (IMendixObject mxObject : unitTests) { + UnitTest test = UnitTest.initialize(context, mxObject); + test.setResult(null); + test.commit(); + } + + long start = System.currentTimeMillis(); + + /** + * Run java unit tests + */ + if (unittesting.proxies.constants.Constants.getFindJUnitTests()) { + Class[] classes = null; + + try { + classes = JavaTestDiscovery.getUnitTestClasses(testSuite); + } catch (Exception e) { + LOG.error("Unable to find JUnit test classes or methods: " + e.getMessage(), e); + } + + if (classes != null && classes.length > 0) { + JUnitCore junit = new JUnitCore(); + junit.addListener(new UnitTestRunListener(context, testSuite)); + junit.run(classes); + } + } + + /** + * Run microflow tests + */ + try { + runMfSetup(testSuite); + + List mfnames = findMicroflowUnitTests(testSuite); + + for (String mf : mfnames) { + if (runMicroflowTest(mf, getUnitTest(context, testSuite, mf, true), testSuite)) { + testSuite.setTestPassedCount(testSuite.getTestPassedCount() + 1); + } else { + testSuite.setTestFailedCount(testSuite.getTestFailedCount() + 1); + } + testSuite.commit(); + } + + } finally { + runMfTearDown(testSuite); + } + + /** + * Aggregate + */ + testSuite.setLastRunTime((System.currentTimeMillis() - start) / 1000); + testSuite.setResult(testSuite.getTestFailedCount() == 0L ? ENUM_UnitTestResult._3_Success + : ENUM_UnitTestResult._2_Failed); + testSuite.commit(); + + LOG.info("Finished testrun on " + testSuite.getModule()); + } + + public List findMicroflowUnitTests(TestSuite testRun) { + List microflowNames = new ArrayList<>(); + + if (testRun.getPrefix1() == null) { + testRun.setPrefix1("Test_"); + } + if (testRun.getPrefix2() == null) { + testRun.setPrefix2("UT_"); + } + + String basename1 = (testRun.getModule() + "." + testRun.getPrefix1()).toLowerCase(); + String basename2 = (testRun.getModule() + "." + testRun.getPrefix2()).toLowerCase(); + + // Find microflow names + for (String mf : Core.getMicroflowNames()) + if (mf.toLowerCase().startsWith(basename1) || mf.toLowerCase().startsWith(basename2)) + microflowNames.add(mf); + + // Sort microflow names + Collections.sort(microflowNames); + return microflowNames; + } + + public boolean hasMfSetup(TestSuite testSuite) { + return Core.getMicroflowNames().contains(testSuite.getModule() + ".Setup"); + } + + public boolean hasMfTearDown(TestSuite testSuite) { + return Core.getMicroflowNames().contains(testSuite.getModule() + ".TearDown"); + } + + private boolean hasTestContextInputParameter(String mf) { + if (!Core.getInputParameters(mf).containsKey(TEST_CONTEXT_PARAM_NAME)) + return false; + + IDataType dataType = Core.getInputParameters(mf).get(TEST_CONTEXT_PARAM_NAME); + return dataType.isMendixObject() + && unittesting.proxies.UnitTestContext.getType().equals(dataType.getObjectType()); + } + + public boolean validateTestMicroflow(String mf) { + if (Core.getReturnType(mf).getType() != IDataType.DataTypeEnum.Boolean + && Core.getReturnType(mf).getType() != IDataType.DataTypeEnum.String + && Core.getReturnType(mf).getType() != IDataType.DataTypeEnum.Nothing) { + + LOG.warn("Invalid test microflow " + mf + + ": Microflow should return either a boolean or a string or nothing at all"); + return false; + } + + if (Core.getInputParameters(mf).size() == 1 && hasTestContextInputParameter(mf)) { + LOG.trace("Identified parameter for unit test context in test microflow " + mf); + } else if (!Core.getInputParameters(mf).isEmpty()) { + LOG.warn("Invalid test microflow " + mf + ": Identified one or more invalid parameter(s)"); + return false; + } + + return true; + } + + private MicroflowCallBuilder buildMicroflowCall(String mf) { + MicroflowCallBuilder builder = Core.microflowCall(mf); + + if (hasTestContextInputParameter(mf)) + builder = builder.withParam(TEST_CONTEXT_PARAM_NAME, executionContext().getUnitTestContext().getMendixObject()); + + return builder; + } + + private boolean runMicroflowTest(String mf, UnitTest test) throws CoreException { + /** + * Prepare... + */ + TestSuite testSuite = test.getUnitTest_TestSuite(); + + return runMicroflowTest(mf, test, testSuite); + } + + private boolean runMicroflowTest(String mf, UnitTest test, TestSuite testSuite) { + /** + * Prepare... + */ + LOG.info("Starting unit test for microflow " + mf); + + test.setName(mf); + test.setResultMessage(""); + test.setLastRun(new Date()); + + IContext mfContext = null; + + if (testSuite.getAutoRollbackMFs()) { + if (Core.getMicroflowNames().contains(testSuite.getModule() + ".Setup")) + mfContext = setupContext.createClone(); + else + mfContext = Core.createSystemContext(); + + mfContext.startTransaction(); + LOG.trace("Start transaction for unit test"); + } else { + mfContext = Core.createSystemContext(); + } + + executionContext = new TestExecutionContext(mfContext, mf); + executionContext().clearTestActivities(test); + + long duration = 0L; + long startTimestamp = System.currentTimeMillis(); + + try { + if (!validateTestMicroflow(mf)) { + test.setResult(ENUM_UnitTestResult._2_Failed); + commitSilent(test); + + executionContext().collectStart(false, "Unable to start test, invalid microflow"); + return false; + } + + executionContext().collectStart(true, null); + test.setResult(ENUM_UnitTestResult._1_Running); + commitSilent(test); + + Object mfReturnValue = buildMicroflowCall(mf).execute(mfContext); + duration = System.currentTimeMillis() - startTimestamp; + + boolean returnValueResult = mfReturnValue == null || Boolean.TRUE.equals(mfReturnValue) || "".equals(mfReturnValue); + + if (returnValueResult) { + executionContext().collectEnd(true, null); + } else if (mfReturnValue instanceof String) { + executionContext().collectEnd(false, "Microflow returned string: " + mfReturnValue); + } else if (mfReturnValue instanceof Boolean) { + executionContext().collectEnd(false, "Microflow returned false"); + } + + boolean testResult = returnValueResult && !executionContext().hasFailedAssertion(mfContext); + test.setResult(testResult ? ENUM_UnitTestResult._3_Success : ENUM_UnitTestResult._2_Failed); + + return testResult; + } catch (Exception e) { + duration = System.currentTimeMillis() - startTimestamp; + test.setResult(ENUM_UnitTestResult._2_Failed); + Throwable cause = ExceptionUtils.getRootCause(e); + + if (!(cause instanceof AssertionException)) { + test.setStackTrace(ExceptionUtils.getStackTrace(e)); + executionContext().collectException(e); + } + + return false; + } finally { + executionContext().persistTestActivities(mfContext, test); + + if (testSuite.getAutoRollbackMFs() && mfContext.isInTransaction()) { + LOG.trace("Rollback transaction for unit test"); + mfContext.rollbackTransaction(); + } + + test.setResultMessage(executionContext().getResultSummary(mfContext)); + test.setReadableTime(formatAsReadableTime(duration)); + if (executionContext().getLastStep() != null) + test.setLastStep(executionContext().getLastStep().getMessage()); + + commitSilent(test); + + executionContext().delete(); + + LOG.info("Finished unit test " + mf + ": " + test.getResult()); + } + } + + public static String formatAsReadableTime(long ms) { + return (ms > 10000 ? Math.round(ms / 1000) + " seconds" : + (ms == 0 ? "<1" : ms) + " milliseconds"); + } + + private long getTestSuiteCount(IContext context, TestSuite testSuite, String constraint) { + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", UnitTest.entityName)); + query.append(String.format("[%s=%d]", UnitTest.MemberNames.UnitTest_TestSuite, + testSuite.getMendixObject().getId().toLong())); + if (constraint != null) query.append(constraint); + + return Core.createXPathQuery(String.format("COUNT(%s)", query)).executeAggregateLong(context); + } + + public void updateTestSuiteCountersAndResult(IContext context, TestSuite testSuite, boolean commit) + throws CoreException { + long testCount = getTestSuiteCount(context, testSuite, null); + long succeededCount = getTestSuiteCount(context, testSuite, "[Result = '_3_Success']"); + long failedCount = getTestSuiteCount(context, testSuite, "[Result = '_2_Failed']"); + long pendingCount = getTestSuiteCount(context, testSuite, "[Result = '_1_Running' or Result = empty]"); + + testSuite.setTestCount(testCount); + LOG.trace("Updated test count to " + succeededCount); + + testSuite.setTestPassedCount(succeededCount); + LOG.trace("Updated test suite succeeded count to " + succeededCount); + + testSuite.setTestFailedCount(failedCount); + LOG.trace("Updated test suite failed count to " + failedCount); + + if (failedCount > 0) { + testSuite.setResult(ENUM_UnitTestResult._2_Failed); + LOG.trace("Updated test suite result to 'Failed'"); + } else if (pendingCount > 0 || testCount == 0) { + testSuite.setResult(null); + LOG.trace("Updated test suite result to empty"); + } else { + testSuite.setResult(ENUM_UnitTestResult._3_Success); + LOG.trace("Updated test suite result to 'Success'"); + } + + if (commit) testSuite.commit(); + } + + private void commitSilent(UnitTest test) { + try { + test.commit(); + } catch (CoreException e) { + throw new RuntimeException(e); + } + } + + UnitTest getJUnitTest(IContext context, TestSuite testSuite, Description description) { + return getUnitTest(context, testSuite, description.getClassName() + "/" + description.getMethodName(), false); + } + + private UnitTest getUnitTest(IContext context, TestSuite testSuite, String name, boolean isMF) { + String displayName = name.substring(testSuite.getModule().length() + 1); + + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", UnitTest.entityName)); + query.append(String.format("[%s=$TestSuite]", UnitTest.MemberNames.UnitTest_TestSuite)); + query.append(String.format("[%s=$Name]", UnitTest.MemberNames.Name)); + query.append(String.format("[%s=$DisplayName]", UnitTest.MemberNames.DisplayName)); + query.append(String.format("[%s=$IsMicroflow]", UnitTest.MemberNames.IsMf)); + + Optional mxObject = Core.createXPathQuery(query.toString()) + .setVariable("TestSuite", testSuite.getMendixObject().getId()) + .setVariable("Name", name) + .setVariable("DisplayName", displayName) + .setVariable("IsMicroflow", isMF) + .execute(context).stream().findAny(); + + if (mxObject.isPresent()) { + return UnitTest.initialize(context, mxObject.get()); + } else { + UnitTest newTest = new UnitTest(context); + newTest.setName(name); + newTest.setDisplayName(displayName); + newTest.setUnitTest_TestSuite(testSuite); + newTest.setIsMf(isMF); + + return newTest; + } + } + + public void reportStep(String message) { + LOG.debug("Report step: " + message); + lastStep = message; + } + + public synchronized void findAllTests(IContext context) throws CoreException { + if (!ConfigurationManager.verifyModuleIsEnabled()) return; + + /* + * Find modules + */ + Set modules = new HashSet(); + for (String name : Core.getMicroflowNames()) + modules.add(name.split("\\.")[0]); + + /* + * Update modules + */ + for (String module : modules) { + TestSuite testSuite = findOrCreateTestSuite(context, module); + updateUnitTestList(context, testSuite); + } + + /* + * Remove all modules without tests + */ + deleteTestSuitesWithoutTest(context); + + /* + * Reset refresh required flag + */ + ModelUpdateSubscriber.getInstance().setRefreshRequired(false); + } + + public synchronized Optional findTestSuite(IContext context, String module) { + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", TestSuite.entityName)); + query.append(String.format("[%s=$Module]", TestSuite.MemberNames.Module)); + + Optional mxObject = Core.createXPathQuery(query.toString()).setVariable("Module", module) + .execute(context).stream().findAny(); + + return mxObject.map(obj -> TestSuite.initialize(context, obj)); + } + + private synchronized TestSuite findOrCreateTestSuite(IContext context, String module) throws CoreException { + Optional testSuite = findTestSuite(context, module); + + if (testSuite.isPresent()) { + return testSuite.get(); + } else { + TestSuite newSuite = new TestSuite(context); + newSuite.setModule(module); + newSuite.commit(); + + return newSuite; + } + } + + private synchronized void deleteTestSuitesWithoutTest(IContext context) throws CoreException { + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", TestSuite.entityName)); + query.append("[not(" + UnitTest.MemberNames.UnitTest_TestSuite + "/" + UnitTest.entityName + ")]"); + + List testSuites = Core.createXPathQuery(query.toString()).execute(context); + Core.delete(context, testSuites); + } + + public synchronized void updateUnitTestList(IContext context, TestSuite testSuite) { + try { + /* + * Mark all dirty + */ + StringBuilder query = new StringBuilder(); + query.append(String.format("//%s", UnitTest.entityName)); + query.append(String.format("[%s=$TestSuite]", UnitTest.MemberNames.UnitTest_TestSuite)); + + List unitTests = Core.createXPathQuery(query.toString()) + .setVariable("TestSuite", testSuite.getMendixObject().getId().toLong()).execute(context); + + for (IMendixObject mxObject : unitTests) { + UnitTest test = UnitTest.initialize(context, mxObject); + test.set_dirty(true); + test.commit(); + } + + /* + * Find microflow tests + */ + for (String mf : findMicroflowUnitTests(testSuite)) { + UnitTest test = getUnitTest(context, testSuite, mf, true); + test.set_dirty(false); + test.setUnitTest_TestSuite(testSuite); + test.commit(); + } + + if (unittesting.proxies.constants.Constants.getFindJUnitTests()) { + /* + * Find Junit tests + */ + for (String jtest : JavaTestDiscovery.findJUnitTests(testSuite)) { + UnitTest test = getUnitTest(context, testSuite, jtest, false); + test.set_dirty(false); + test.setUnitTest_TestSuite(testSuite); + test.commit(); + } + } + + /* + * Delete dirty tests + */ + StringBuilder deleteQuery = new StringBuilder(); + deleteQuery.append(String.format("//%s", UnitTest.entityName)); + deleteQuery.append(String.format("[%s=true]", UnitTest.MemberNames._dirty)); + + List dirtyTests = Core.createXPathQuery(deleteQuery.toString()).execute(context); + Core.delete(context, dirtyTests); + + /* + * Update counters + result + */ + updateTestSuiteCountersAndResult(context, testSuite, false); + + /* + * Update setup/teardown + */ + testSuite.setHasSetup(hasMfSetup(testSuite)); + testSuite.setHasTearDown(hasMfTearDown(testSuite)); + testSuite.commit(); + + } catch (Exception e) { + LOG.error("Failed to update unit test list: " + e.getMessage(), e); + } + } + + public String getLastReportedStep() { + // MWE: this system is problematic weird if used from multiple simultanously + // used threads.. + return lastStep; + } +} diff --git a/Source/javasource/unittesting/UnitTestRunListener.java b/Source/javasource/unittesting/UnitTestRunListener.java index d6b5fc5c..4e385cf3 100644 --- a/Source/javasource/unittesting/UnitTestRunListener.java +++ b/Source/javasource/unittesting/UnitTestRunListener.java @@ -1,123 +1,130 @@ -package unittesting; - -import java.lang.reflect.InvocationTargetException; -import java.security.AccessControlException; -import java.util.Date; - -import org.junit.runner.Description; -import org.junit.runner.Result; -import org.junit.runner.notification.Failure; -import org.junit.runner.notification.RunListener; - -import com.mendix.systemwideinterfaces.core.IContext; - -import unittesting.proxies.TestSuite; -import unittesting.proxies.UnitTest; -import unittesting.proxies.UnitTestResult; - -public class UnitTestRunListener extends RunListener { - - private IContext context; - private TestSuite testSuite; - - public UnitTestRunListener(IContext context, TestSuite testSuite) { - this.context = context; - this.testSuite = testSuite; - } - - @Override - public void testRunStarted(Description description) throws java.lang.Exception { - TestManager.LOG.info("Starting test run"); - } - - @Override - public void testRunFinished(Result result) throws java.lang.Exception { - TestManager.LOG.info("Test run finished"); - } - - @Override - public void testStarted(Description description) throws java.lang.Exception { - String message = "Starting JUnit test " + description.getClassName() + "." + description.getMethodName(); - TestManager.LOG.info(message); - TestManager.instance().reportStep(message); - - UnitTest t = getUnitTest(description); - t.setResult(UnitTestResult._1_Running); - t.setResultMessage(""); - t.setLastRun(new Date()); - t.commit(); - } - - private UnitTest getUnitTest(Description description) { - return TestManager.instance().getUnitTest(context, testSuite, description, false); - } - - @Override - public void testFinished(Description description) throws Exception { - TestManager.LOG.info("Finished test " + description.getClassName() + "." + description.getMethodName()); - - UnitTest t = getUnitTest(description); - - if (t.getResult() == UnitTestResult._1_Running) { - t.setResult(UnitTestResult._3_Success); - - long delta = getUnitTestInnerTime(description, t); - - t.setResultMessage("JUnit test completed successfully"); - t.setReadableTime((delta > 10000 ? Math.round(delta / 1000) + " seconds" : delta + " milliseconds")); - } - - t.setLastStep(TestManager.instance().getLastReportedStep()); - t.commit(); - } - - @Override - public void testFailure(Failure failure) throws java.lang.Exception { - boolean isCloudSecurityError = failure.getException() != null - && failure.getException() instanceof AccessControlException - && ((AccessControlException) failure.getException()).getPermission().getName() - .equals("accessDeclaredMembers"); - - UnitTest t = getUnitTest(failure.getDescription()); - - /** - * Test itself failed - */ - TestManager.LOG.error("Failed test (at step '" + TestManager.instance().getLastReportedStep() + "') " - + failure.getDescription().getClassName() + "." + failure.getDescription().getMethodName() + " : " - + failure.getMessage(), failure.getException()); - - testSuite.setTestFailedCount(testSuite.getTestFailedCount() + 1); - testSuite.commit(); - - t.setResult(UnitTestResult._2_Failed); - t.setResultMessage(String.format("%s %s: %s\n\n:%s", - isCloudSecurityError ? "CLOUD SECURITY EXCEPTION \n\n" + TestManager.CLOUD_SECURITY_ERROR : "FAILED", - findProperExceptionLine(failure.getTrace()), failure.getMessage(), failure.getTrace())); - - t.setLastStep(TestManager.instance().getLastReportedStep()); - t.setLastRun(new Date()); - t.commit(); - } - - private long getUnitTestInnerTime(Description description, UnitTest t) throws IllegalAccessException, - IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { - long delta = System.currentTimeMillis() - t.getLastRun().getTime(); - - if (AbstractUnitTest.class.isAssignableFrom(description.getTestClass())) - delta = (Long) description.getTestClass().getMethod("getTestRunTime").invoke(null); - return delta; - } - - private String findProperExceptionLine(String trace) { - String[] lines = trace.split("\n"); - if (lines.length > 2) - for (int i = 1; i < lines.length; i++) { - String line = lines[i].trim(); - if (!line.startsWith("at org.junit") && line.contains("(")) - return " at " + line.substring(line.indexOf('(') + 1, line.indexOf(')')).replace(":", " line "); - } - - return ""; - } -} +package unittesting; + +import java.lang.reflect.InvocationTargetException; +import java.util.Date; + +import com.mendix.logging.ILogNode; +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +import com.mendix.systemwideinterfaces.core.IContext; + +import unittesting.proxies.TestSuite; +import unittesting.proxies.UnitTest; +import unittesting.proxies.ENUM_UnitTestResult; + +public class UnitTestRunListener extends RunListener { + private static final ILogNode LOG = ConfigurationManager.LOG; + + private IContext context; + private TestSuite testSuite; + + public UnitTestRunListener(IContext context, TestSuite testSuite) { + this.context = context; + this.testSuite = testSuite; + } + + @Override + public void testRunStarted(Description description) { + LOG.info("Starting test run"); + } + + @Override + public void testRunFinished(Result result) { + LOG.info("Test run finished"); + } + + @Override + public void testStarted(Description description) throws Exception { + String message = "Starting JUnit test " + description.getClassName() + "." + description.getMethodName(); + LOG.info(message); + TestManager.instance().reportStep(message); + + UnitTest t = getUnitTest(description); + t.setResult(ENUM_UnitTestResult._1_Running); + t.setResultMessage(""); + t.setLastRun(new Date()); + t.commit(); + } + + private UnitTest getUnitTest(Description description) { + return TestManager.instance().getJUnitTest(context, testSuite, description); + } + + @Override + public void testFinished(Description description) throws Exception { + LOG.info("Finished test " + description.getClassName() + "." + description.getMethodName()); + + UnitTest t = getUnitTest(description); + + if (t.getResult() == ENUM_UnitTestResult._1_Running) { + t.setResult(ENUM_UnitTestResult._3_Success); + t.setResultMessage("JUnit test completed successfully"); + t.setReadableTime(getReadableTime(description, t)); + + testSuite.setTestPassedCount(testSuite.getTestPassedCount() + 1); + testSuite.commit(); + } + + t.setLastStep(TestManager.instance().getLastReportedStep()); + t.commit(); + } + + @Override + public void testFailure(Failure failure) throws Exception { + UnitTest t = getUnitTest(failure.getDescription()); + + /** + * Test itself failed + */ + LOG.error("Failed test (at step '" + TestManager.instance().getLastReportedStep() + "') " + + failure.getDescription().getClassName() + "." + failure.getDescription().getMethodName() + " : " + + failure.getMessage(), failure.getException()); + + testSuite.setTestFailedCount(testSuite.getTestFailedCount() + 1); + testSuite.commit(); + + t.setResult(ENUM_UnitTestResult._2_Failed); + t.setResultMessage(getFailureMessage(failure)); + t.setStackTrace(failure.getTrace()); + t.setReadableTime(getReadableTime(failure.getDescription(), t)); + t.setLastStep(TestManager.instance().getLastReportedStep()); + t.setLastRun(new Date()); + t.commit(); + } + + private String getFailureMessage(Failure failure) { + String message = String.format("JUnit test failed at %s", findProperExceptionLine(failure.getTrace())); + return failure.getMessage() != null ? message + ": " + failure.getMessage() : message; + } + + private String getReadableTime(Description description, UnitTest t) throws Exception { + long delta = getUnitTestInnerTime(description, t); + return TestManager.formatAsReadableTime(delta); + } + + private long getUnitTestInnerTime(Description description, UnitTest t) throws IllegalAccessException, + IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { + long delta = System.currentTimeMillis() - t.getLastRun().getTime(); + + if (AbstractUnitTest.class.isAssignableFrom(description.getTestClass())) + delta = (Long) description.getTestClass().getMethod("getTestRunTime").invoke(null); + return delta; + } + + private String findProperExceptionLine(String trace) { + String[] lines = trace.split("\n"); + + if (lines.length > 2) { + for (int i = 1; i < lines.length; i++) { + String line = lines[i].trim(); + if (!line.startsWith("at org.junit") && line.contains("(")) + return line.substring(line.indexOf('(') + 1, line.indexOf(')')).replace(":", " line "); + } + } + + return ""; + } +} diff --git a/Source/javasource/unittesting/actions/AssertUsingExpression.java b/Source/javasource/unittesting/actions/AssertUsingExpression.java new file mode 100644 index 00000000..ed5fd7c3 --- /dev/null +++ b/Source/javasource/unittesting/actions/AssertUsingExpression.java @@ -0,0 +1,68 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package unittesting.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.IMendixObject; +import unittesting.TestExecutionContext; +import unittesting.TestManager; +import unittesting.proxies.Assertion; +import unittesting.proxies.ENUM_UnitTestResult; +import com.mendix.systemwideinterfaces.core.UserAction; + +public class AssertUsingExpression extends UserAction +{ + private final java.lang.String name; + private final java.lang.Boolean expression; + private final java.lang.String failureMessage; + private final java.lang.Boolean stopOnFailure; + + public AssertUsingExpression( + IContext context, + java.lang.String _name, + java.lang.Boolean _expression, + java.lang.String _failureMessage, + java.lang.Boolean _stopOnFailure + ) + { + super(context); + this.name = _name; + this.expression = _expression; + this.failureMessage = _failureMessage; + this.stopOnFailure = _stopOnFailure; + } + + @java.lang.Override + public IMendixObject executeAction() throws Exception + { + // BEGIN USER CODE + TestExecutionContext executionContext = TestManager.instance().executionContext(); + Assertion result = executionContext.collectAssertion(getContext(), name, expression, failureMessage); + + if (ENUM_UnitTestResult._2_Failed.equals(result.getResult()) && stopOnFailure) + throw new TestManager.AssertionException(failureMessage); + + return result.getMendixObject(); + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "AssertUsingExpression"; + } + + // BEGIN EXTRA CODE + // END EXTRA CODE +} diff --git a/Source/javasource/unittesting/actions/FindAllUnitTests.java b/Source/javasource/unittesting/actions/FindAllUnitTests.java index e36c95bd..eaf1d520 100644 --- a/Source/javasource/unittesting/actions/FindAllUnitTests.java +++ b/Source/javasource/unittesting/actions/FindAllUnitTests.java @@ -11,9 +11,9 @@ import unittesting.TestManager; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class FindAllUnitTests extends CustomJavaAction +public class FindAllUnitTests extends UserAction { public FindAllUnitTests(IContext context) { diff --git a/Source/javasource/unittesting/actions/Initialize.java b/Source/javasource/unittesting/actions/Initialize.java new file mode 100644 index 00000000..398a242f --- /dev/null +++ b/Source/javasource/unittesting/actions/Initialize.java @@ -0,0 +1,44 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package unittesting.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import unittesting.ConfigurationManager; +import com.mendix.systemwideinterfaces.core.UserAction; + +public class Initialize extends UserAction +{ + public Initialize(IContext context) + { + super(context); + } + + @java.lang.Override + public java.lang.Void executeAction() throws Exception + { + // BEGIN USER CODE + ConfigurationManager.initialize(); + return null; + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "Initialize"; + } + + // BEGIN EXTRA CODE + // END EXTRA CODE +} diff --git a/Source/javasource/unittesting/actions/IsEnabled.java b/Source/javasource/unittesting/actions/IsEnabled.java new file mode 100644 index 00000000..5a773525 --- /dev/null +++ b/Source/javasource/unittesting/actions/IsEnabled.java @@ -0,0 +1,43 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package unittesting.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import unittesting.ConfigurationManager; +import com.mendix.systemwideinterfaces.core.UserAction; + +public class IsEnabled extends UserAction +{ + public IsEnabled(IContext context) + { + super(context); + } + + @java.lang.Override + public java.lang.Boolean executeAction() throws Exception + { + // BEGIN USER CODE + return ConfigurationManager.isEnabled(); + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "IsEnabled"; + } + + // BEGIN EXTRA CODE + // END EXTRA CODE +} diff --git a/Source/javasource/unittesting/actions/IsInitialized.java b/Source/javasource/unittesting/actions/IsInitialized.java new file mode 100644 index 00000000..43e9f636 --- /dev/null +++ b/Source/javasource/unittesting/actions/IsInitialized.java @@ -0,0 +1,43 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package unittesting.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import unittesting.ConfigurationManager; +import com.mendix.systemwideinterfaces.core.UserAction; + +public class IsInitialized extends UserAction +{ + public IsInitialized(IContext context) + { + super(context); + } + + @java.lang.Override + public java.lang.Boolean executeAction() throws Exception + { + // BEGIN USER CODE + return ConfigurationManager.isInitialized(); + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "IsInitialized"; + } + + // BEGIN EXTRA CODE + // END EXTRA CODE +} diff --git a/Source/javasource/unittesting/actions/RegisterModelUpdateSubscriber.java b/Source/javasource/unittesting/actions/RegisterModelUpdateSubscriber.java new file mode 100644 index 00000000..060c1de7 --- /dev/null +++ b/Source/javasource/unittesting/actions/RegisterModelUpdateSubscriber.java @@ -0,0 +1,57 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package unittesting.actions; + +import com.mendix.core.Core; +import com.mendix.logging.ILogNode; +import com.mendix.systemwideinterfaces.core.IContext; +import unittesting.ConfigurationManager; +import unittesting.ModelUpdateSubscriber; +import com.mendix.systemwideinterfaces.core.UserAction; + +public class RegisterModelUpdateSubscriber extends UserAction +{ + public RegisterModelUpdateSubscriber(IContext context) + { + super(context); + } + + @java.lang.Override + public java.lang.Boolean executeAction() throws Exception + { + // BEGIN USER CODE + if (ConfigurationManager.isLocalDevelopment()) { + ModelUpdateSubscriber logSubscriber = ModelUpdateSubscriber.getInstance(); + + Core.registerLogSubscriber(logSubscriber); + logSubscriber.start(); + + return true; + } else { + LOG.debug("Did not subscribe to model updates, not in local development"); + return false; + } + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "RegisterModelUpdateSubscriber"; + } + + // BEGIN EXTRA CODE + private static final ILogNode LOG = ConfigurationManager.LOG; + // END EXTRA CODE +} diff --git a/Source/javasource/unittesting/actions/ReportStepJava.java b/Source/javasource/unittesting/actions/ReportStepJava.java index 8cf16bbc..b2d1b95c 100644 --- a/Source/javasource/unittesting/actions/ReportStepJava.java +++ b/Source/javasource/unittesting/actions/ReportStepJava.java @@ -11,9 +11,9 @@ import unittesting.TestManager; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class ReportStepJava extends CustomJavaAction +public class ReportStepJava extends UserAction { private final java.lang.String message; @@ -30,7 +30,7 @@ public ReportStepJava( public java.lang.Boolean executeAction() throws Exception { // BEGIN USER CODE - TestManager.instance().reportStep(message); + TestManager.instance().executionContext().collectStep(message); return true; // END USER CODE } diff --git a/Source/javasource/unittesting/actions/RunAllUnitTestsWrapper.java b/Source/javasource/unittesting/actions/RunAllUnitTestsWrapper.java index 4ec30d96..85dc463b 100644 --- a/Source/javasource/unittesting/actions/RunAllUnitTestsWrapper.java +++ b/Source/javasource/unittesting/actions/RunAllUnitTestsWrapper.java @@ -9,14 +9,16 @@ package unittesting.actions; +import com.mendix.logging.ILogNode; import org.apache.commons.lang3.exception.ExceptionUtils; +import unittesting.ConfigurationManager; import unittesting.TestManager; import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class RunAllUnitTestsWrapper extends CustomJavaAction +public class RunAllUnitTestsWrapper extends UserAction { /** @deprecated use testRun.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) @@ -41,7 +43,7 @@ public java.lang.Boolean executeAction() throws Exception // Run tests in a new context without transaction! TestManager.instance().runTestSuite(Core.createSystemContext(), testRun); } catch (Exception e) { - TestManager.LOG.error( + LOG.error( "An error occurred while trying to run the unit tests: " + ExceptionUtils.getRootCauseMessage(e), e); return false; @@ -61,5 +63,6 @@ public java.lang.String toString() } // BEGIN EXTRA CODE + private static final ILogNode LOG = ConfigurationManager.LOG; // END EXTRA CODE } diff --git a/Source/javasource/unittesting/actions/RunUnitTest.java b/Source/javasource/unittesting/actions/RunUnitTest.java index 747f5ae0..89b30d7a 100644 --- a/Source/javasource/unittesting/actions/RunUnitTest.java +++ b/Source/javasource/unittesting/actions/RunUnitTest.java @@ -12,9 +12,9 @@ import unittesting.TestManager; import com.mendix.systemwideinterfaces.core.IContext; import com.mendix.systemwideinterfaces.core.IMendixObject; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class RunUnitTest extends CustomJavaAction +public class RunUnitTest extends UserAction { /** @deprecated use unitTest.getMendixObject() instead. */ @java.lang.Deprecated(forRemoval = true) diff --git a/Source/javasource/unittesting/actions/StartRemoteApiServlet.java b/Source/javasource/unittesting/actions/StartRemoteApiServlet.java index 131a44f7..3c67f877 100644 --- a/Source/javasource/unittesting/actions/StartRemoteApiServlet.java +++ b/Source/javasource/unittesting/actions/StartRemoteApiServlet.java @@ -9,12 +9,13 @@ package unittesting.actions; +import unittesting.ConfigurationManager; import unittesting.RemoteApiServlet; import com.mendix.core.Core; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class StartRemoteApiServlet extends CustomJavaAction +public class StartRemoteApiServlet extends UserAction { private final java.lang.String password; @@ -31,6 +32,8 @@ public StartRemoteApiServlet( public java.lang.Boolean executeAction() throws Exception { // BEGIN USER CODE + if (!ConfigurationManager.verifyModuleIsEnabled()) return false; + Core.addRequestHandler("unittests/", new RemoteApiServlet(password)); return true; // END USER CODE diff --git a/Source/javasource/unittesting/actions/StartRunAllSuites.java b/Source/javasource/unittesting/actions/StartRunAllSuites.java index 7f7bfcd3..684e884a 100644 --- a/Source/javasource/unittesting/actions/StartRunAllSuites.java +++ b/Source/javasource/unittesting/actions/StartRunAllSuites.java @@ -11,9 +11,9 @@ import unittesting.TestManager; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class StartRunAllSuites extends CustomJavaAction +public class StartRunAllSuites extends UserAction { public StartRunAllSuites(IContext context) { diff --git a/Source/javasource/unittesting/actions/TestRefreshRequired.java b/Source/javasource/unittesting/actions/TestRefreshRequired.java new file mode 100644 index 00000000..45d87aea --- /dev/null +++ b/Source/javasource/unittesting/actions/TestRefreshRequired.java @@ -0,0 +1,43 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package unittesting.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import unittesting.ModelUpdateSubscriber; +import com.mendix.systemwideinterfaces.core.UserAction; + +public class TestRefreshRequired extends UserAction +{ + public TestRefreshRequired(IContext context) + { + super(context); + } + + @java.lang.Override + public java.lang.Boolean executeAction() throws Exception + { + // BEGIN USER CODE + return ModelUpdateSubscriber.getInstance().getRefreshRequired(); + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "TestRefreshRequired"; + } + + // BEGIN EXTRA CODE + // END EXTRA CODE +} diff --git a/Source/javasource/unittesting/actions/ThrowAssertionFailed.java b/Source/javasource/unittesting/actions/ThrowAssertionFailed.java index 4234fe9d..dd4509a1 100644 --- a/Source/javasource/unittesting/actions/ThrowAssertionFailed.java +++ b/Source/javasource/unittesting/actions/ThrowAssertionFailed.java @@ -11,9 +11,9 @@ import unittesting.TestManager; import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; +import com.mendix.systemwideinterfaces.core.UserAction; -public class ThrowAssertionFailed extends CustomJavaAction +public class ThrowAssertionFailed extends UserAction { private final java.lang.String message; diff --git a/Source/javasource/unittesting/actions/UpdateTestSuiteCountersAndResult.java b/Source/javasource/unittesting/actions/UpdateTestSuiteCountersAndResult.java new file mode 100644 index 00000000..f97db113 --- /dev/null +++ b/Source/javasource/unittesting/actions/UpdateTestSuiteCountersAndResult.java @@ -0,0 +1,55 @@ +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package unittesting.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import unittesting.TestManager; +import com.mendix.systemwideinterfaces.core.IMendixObject; +import com.mendix.systemwideinterfaces.core.UserAction; + +public class UpdateTestSuiteCountersAndResult extends UserAction +{ + /** @deprecated use testSuite.getMendixObject() instead. */ + @java.lang.Deprecated(forRemoval = true) + private final IMendixObject __testSuite; + private final unittesting.proxies.TestSuite testSuite; + + public UpdateTestSuiteCountersAndResult( + IContext context, + IMendixObject _testSuite + ) + { + super(context); + this.__testSuite = _testSuite; + this.testSuite = _testSuite == null ? null : unittesting.proxies.TestSuite.initialize(getContext(), _testSuite); + } + + @java.lang.Override + public java.lang.Void executeAction() throws Exception + { + // BEGIN USER CODE + TestManager.instance().updateTestSuiteCountersAndResult(getContext(), testSuite, true); + return null; + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "UpdateTestSuiteCountersAndResult"; + } + + // BEGIN EXTRA CODE + // END EXTRA CODE +} diff --git a/Source/javasource/unittesting/activities/ExceptionExecutionActivity.java b/Source/javasource/unittesting/activities/ExceptionExecutionActivity.java new file mode 100644 index 00000000..8e4a6dfb --- /dev/null +++ b/Source/javasource/unittesting/activities/ExceptionExecutionActivity.java @@ -0,0 +1,14 @@ +package unittesting.activities; + +public class ExceptionExecutionActivity extends ExecutionActivity { + private final Exception exception; + + public ExceptionExecutionActivity(int sequence, Exception exception) { + super(sequence); + this.exception = exception; + } + + public Exception getException() { + return this.exception; + } +} diff --git a/Source/javasource/unittesting/activities/ExecutionActivity.java b/Source/javasource/unittesting/activities/ExecutionActivity.java new file mode 100644 index 00000000..c3812ee7 --- /dev/null +++ b/Source/javasource/unittesting/activities/ExecutionActivity.java @@ -0,0 +1,13 @@ +package unittesting.activities; + +public class ExecutionActivity { + private final int sequence; + + public ExecutionActivity(int sequence) { + this.sequence = sequence; + } + + public int getSequence() { + return this.sequence; + } +} diff --git a/Source/javasource/unittesting/activities/StartEndExecutionActivity.java b/Source/javasource/unittesting/activities/StartEndExecutionActivity.java new file mode 100644 index 00000000..30e5d94e --- /dev/null +++ b/Source/javasource/unittesting/activities/StartEndExecutionActivity.java @@ -0,0 +1,26 @@ +package unittesting.activities; + +import unittesting.proxies.ENUM_UnitTestResult; + +public class StartEndExecutionActivity extends ExecutionActivity { + private final boolean result; + private final String message; + + public StartEndExecutionActivity(int sequence, boolean result, String message) { + super(sequence); + this.result = result; + this.message = message; + } + + public boolean getResult() { + return this.result; + } + + public ENUM_UnitTestResult getResultEnum() { + return this.result ? ENUM_UnitTestResult._3_Success : ENUM_UnitTestResult._2_Failed; + } + + public String getMessage() { + return this.message; + } +} diff --git a/Source/javasource/unittesting/activities/StepExecutionActivity.java b/Source/javasource/unittesting/activities/StepExecutionActivity.java new file mode 100644 index 00000000..6d123408 --- /dev/null +++ b/Source/javasource/unittesting/activities/StepExecutionActivity.java @@ -0,0 +1,15 @@ +package unittesting.activities; + +public class StepExecutionActivity extends ExecutionActivity { + private final String message; + + public StepExecutionActivity(int sequence, String message) { + super(sequence); + this.message = message; + } + + public String getMessage() { + return this.message; + } +} + diff --git a/Source/javasource/workflowcommons/actions/JA_Workflow_GetKey.java b/Source/javasource/workflowcommons/actions/JA_UserTaskView_GenerateKey.java similarity index 57% rename from Source/javasource/workflowcommons/actions/JA_Workflow_GetKey.java rename to Source/javasource/workflowcommons/actions/JA_UserTaskView_GenerateKey.java index 522f0827..2a2f3ae7 100644 --- a/Source/javasource/workflowcommons/actions/JA_Workflow_GetKey.java +++ b/Source/javasource/workflowcommons/actions/JA_UserTaskView_GenerateKey.java @@ -1,57 +1,56 @@ -// This file was generated by Mendix Studio Pro. -// -// WARNING: Only the following code will be retained when actions are regenerated: -// - the import list -// - the code between BEGIN USER CODE and END USER CODE -// - the code between BEGIN EXTRA CODE and END EXTRA CODE -// Other code you write will be lost the next time you deploy the project. -// Special characters, e.g., é, ö, à, etc. are supported in comments. - -package workflowcommons.actions; - -import com.mendix.core.Core; -import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; -import com.mendix.systemwideinterfaces.core.IMendixObject; - -public class JA_Workflow_GetKey extends CustomJavaAction -{ - /** @deprecated use workflow.getMendixObject() instead. */ - @java.lang.Deprecated(forRemoval = true) - private final IMendixObject __workflow; - private final system.proxies.Workflow workflow; - - public JA_Workflow_GetKey( - IContext context, - IMendixObject _workflow - ) - { - super(context); - this.__workflow = _workflow; - this.workflow = _workflow == null ? null : system.proxies.Workflow.initialize(getContext(), _workflow); - } - - @java.lang.Override - public java.lang.String executeAction() throws Exception - { - // BEGIN USER CODE - if (workflow == null) - throw new RuntimeException("No Workflow object provided"); - - return Core.workflows().getWorkflow(getContext(), workflow.getMendixObject()).getKey(); - // END USER CODE - } - - /** - * Returns a string representation of this action - * @return a string representation of this action - */ - @java.lang.Override - public java.lang.String toString() - { - return "JA_Workflow_GetKey"; - } - - // BEGIN EXTRA CODE - // END EXTRA CODE -} +// This file was generated by Mendix Studio Pro. +// +// WARNING: Only the following code will be retained when actions are regenerated: +// - the import list +// - the code between BEGIN USER CODE and END USER CODE +// - the code between BEGIN EXTRA CODE and END EXTRA CODE +// Other code you write will be lost the next time you deploy the project. +// Special characters, e.g., é, ö, à, etc. are supported in comments. + +package workflowcommons.actions; + +import com.mendix.systemwideinterfaces.core.IContext; +import com.mendix.systemwideinterfaces.core.UserAction; +import com.mendix.systemwideinterfaces.core.IMendixObject; + +public class JA_UserTaskView_GenerateKey extends UserAction +{ + /** @deprecated use userTaskView.getMendixObject() instead. */ + @java.lang.Deprecated(forRemoval = true) + private final IMendixObject __userTaskView; + private final workflowcommons.proxies.UserTaskView userTaskView; + + public JA_UserTaskView_GenerateKey( + IContext context, + IMendixObject _userTaskView + ) + { + super(context); + this.__userTaskView = _userTaskView; + this.userTaskView = _userTaskView == null ? null : workflowcommons.proxies.UserTaskView.initialize(getContext(), _userTaskView); + } + + @java.lang.Override + public java.lang.String executeAction() throws Exception + { + // BEGIN USER CODE + if (userTaskView == null) + throw new RuntimeException("No UserTaskView object provided"); + + return Long.toHexString(userTaskView.getMendixObject().getId().toLong()); + // END USER CODE + } + + /** + * Returns a string representation of this action + * @return a string representation of this action + */ + @java.lang.Override + public java.lang.String toString() + { + return "JA_UserTaskView_GenerateKey"; + } + + // BEGIN EXTRA CODE + // END EXTRA CODE +} diff --git a/Source/javasource/workflowcommons/actions/JA_WorkflowUserTask_GetKey.java b/Source/javasource/workflowcommons/actions/JA_WorkflowUserTask_GetKey.java deleted file mode 100644 index 558bc4c6..00000000 --- a/Source/javasource/workflowcommons/actions/JA_WorkflowUserTask_GetKey.java +++ /dev/null @@ -1,57 +0,0 @@ -// This file was generated by Mendix Studio Pro. -// -// WARNING: Only the following code will be retained when actions are regenerated: -// - the import list -// - the code between BEGIN USER CODE and END USER CODE -// - the code between BEGIN EXTRA CODE and END EXTRA CODE -// Other code you write will be lost the next time you deploy the project. -// Special characters, e.g., é, ö, à, etc. are supported in comments. - -package workflowcommons.actions; - -import com.mendix.core.Core; -import com.mendix.systemwideinterfaces.core.IContext; -import com.mendix.webui.CustomJavaAction; -import com.mendix.systemwideinterfaces.core.IMendixObject; - -public class JA_WorkflowUserTask_GetKey extends CustomJavaAction -{ - /** @deprecated use workflowUserTask.getMendixObject() instead. */ - @java.lang.Deprecated(forRemoval = true) - private final IMendixObject __workflowUserTask; - private final system.proxies.WorkflowUserTask workflowUserTask; - - public JA_WorkflowUserTask_GetKey( - IContext context, - IMendixObject _workflowUserTask - ) - { - super(context); - this.__workflowUserTask = _workflowUserTask; - this.workflowUserTask = _workflowUserTask == null ? null : system.proxies.WorkflowUserTask.initialize(getContext(), _workflowUserTask); - } - - @java.lang.Override - public java.lang.String executeAction() throws Exception - { - // BEGIN USER CODE - if (workflowUserTask == null) - throw new RuntimeException("No WorkflowUserTask object provided"); - - return Core.workflows().getUserTask(getContext(), workflowUserTask.getMendixObject()).getKey(); - // END USER CODE - } - - /** - * Returns a string representation of this action - * @return a string representation of this action - */ - @java.lang.Override - public java.lang.String toString() - { - return "JA_WorkflowUserTask_GetKey"; - } - - // BEGIN EXTRA CODE - // END EXTRA CODE -} diff --git a/Source/themesource/atlas_core/.version b/Source/themesource/atlas_core/.version index 95ed564f..3f67e25c 100644 --- a/Source/themesource/atlas_core/.version +++ b/Source/themesource/atlas_core/.version @@ -1 +1 @@ -3.14.2 +3.17.0 diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.badge.badge.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.badge.badge.json new file mode 100644 index 00000000..0a39384d --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.badge.badge.json @@ -0,0 +1,10 @@ +{ + "Type": "Type", + "Render it as either a badge or a color label": "Render it as either a badge or a color label", + "Value": "Value", + "General": "General", + "On click": "On click", + "Events": "Events", + "Visibility": "Visibility", + "Common": "Common" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.badgebutton.badgebutton.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.badgebutton.badgebutton.json new file mode 100644 index 00000000..d49d33fd --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.badgebutton.badgebutton.json @@ -0,0 +1,10 @@ +{ + "Caption": "Caption", + "General": "General", + "Value": "Value", + "Badge": "Badge", + "Visibility": "Visibility", + "On click": "On click", + "Events": "Events", + "Common": "Common" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.carousel.carousel.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.carousel.carousel.json new file mode 100644 index 00000000..c43a9a07 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.carousel.carousel.json @@ -0,0 +1,17 @@ +{ + "Carousel displaying images": "Carousel displaying images", + "Data source": "Data source", + "Content": "Content", + "Data Source": "Data Source", + "Pagination": "Pagination", + "Navigation controls": "Navigation controls", + "Auto play": "Auto play", + "Delay": "Delay", + "The amount of time to delay between automatically cycling an item (ms)": "The amount of time to delay between automatically cycling an item (ms)", + "Infinite loop": "Infinite loop", + "Animation": "Animation", + "Display": "Display", + "On click action": "On click action", + "Events": "Events", + "General": "General" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.colorpicker.colorpicker.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.colorpicker.colorpicker.json new file mode 100644 index 00000000..0134c921 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.colorpicker.colorpicker.json @@ -0,0 +1,24 @@ +{ + "Pick a color from color input": "Pick a color from color input", + "Color attribute": "Color attribute", + "The attribute containing a valid color, supported color formats are hexadecimal, rgb and rgba. Non-color formats such as ‘red’ are not supported.": "The attribute containing a valid color, supported color formats are hexadecimal, rgb and rgba. Non-color formats such as ‘red’ are not supported.", + "Data source": "Data source", + "Enable advanced options": "Enable advanced options", + "Display mode": "Display mode", + "The presentation of the color picker": "The presentation of the color picker", + "Picker type": "Picker type", + "The various different styles, for how the color picker should look when clicked.": "The various different styles, for how the color picker should look when clicked.", + "Color format": "Color format", + "The format that which the selected color will be saved as.": "The format that which the selected color will be saved as.", + "Default colors": "Default colors", + "This is a list of pre-defined colors used within the color picker.": "This is a list of pre-defined colors used within the color picker.", + "Color": "Color", + "Valid color value: #d0d0d0, rgb(115,159,159) or rgba(195,226,226,1)": "Valid color value: #d0d0d0, rgb(115,159,159) or rgba(195,226,226,1)", + "Invalid format message": "Invalid format message", + "Message shown when the user provides a wrong input, :colors: will be replaced by a sample format.": "Message shown when the user provides a wrong input, :colors: will be replaced by a sample format.", + "General": "General", + "Editability": "Editability", + "On change": "On change", + "Events": "Events", + "Visibility": "Visibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.maps.maps.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.maps.maps.json new file mode 100644 index 00000000..d36a922f --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.maps.maps.json @@ -0,0 +1,60 @@ +{ + "Custom description please": "Custom description please", + "Enable advanced options": "Enable advanced options", + "General": "General", + "Marker": "Marker", + "A list of static locations on the map.": "A list of static locations on the map.", + "Location": "Location", + "Address": "Address", + "Address containing (a subset of) street, number, zipcode, city and country.": "Address containing (a subset of) street, number, zipcode, city and country.", + "Latitude": "Latitude", + "Decimal number from -90.0 to 90.0.": "Decimal number from -90.0 to 90.0.", + "Longitude": "Longitude", + "Decimal number from -180.0 to 180.0.": "Decimal number from -180.0 to 180.0.", + "Title": "Title", + "Title displayed when clicking the marker.": "Title displayed when clicking the marker.", + "On click": "On click", + "Events": "Events", + "Marker style": "Marker style", + "Image": "Image", + "Image that replaces the default icon.": "Image that replaces the default icon.", + "Visualization": "Visualization", + "Locations": "Locations", + "Marker list": "Marker list", + "A list of markers showing dynamic locations on the map.": "A list of markers showing dynamic locations on the map.", + "Data source": "Data source", + "Markers": "Markers", + "API Key": "API Key", + "API Key for usage of the map through the selected provider.Google Maps - https://developers.google.com/maps/documentation/javascript/get-api-key Map Box - https://docs.mapbox.com/help/getting-started/access-tokens/ Here Maps - https://developer.here.com/tutorials/getting-here-credentials/": "API Key for usage of the map through the selected provider.Google Maps - https://developers.google.com/maps/documentation/javascript/get-api-key Map Box - https://docs.mapbox.com/help/getting-started/access-tokens/ Here Maps - https://developer.here.com/tutorials/getting-here-credentials/", + "Geo location API key": "Geo location API key", + "Used to translate addresses to latitude and longitude. This API Key should be a Google Geocoding API Key found in https://developers.google.com/maps/documentation/geocoding/overview": "Used to translate addresses to latitude and longitude. This API Key should be a Google Geocoding API Key found in https://developers.google.com/maps/documentation/geocoding/overview", + "Show current location marker": "Show current location marker", + "Shows the user current location marker.": "Shows the user current location marker.", + "Configurations": "Configurations", + "Drag": "Drag", + "The center will move when end-users drag the map.": "The center will move when end-users drag the map.", + "Scroll to zoom": "Scroll to zoom", + "The map is zoomed with a mouse scroll.": "The map is zoomed with a mouse scroll.", + "Zoom": "Zoom", + "Show zoom controls [ + ] [ - ].": "Show zoom controls [ + ] [ - ].", + "Attribution control": "Attribution control", + "Add attributions to the map (credits).": "Add attributions to the map (credits).", + "Street view": "Street view", + "Enables the Street View control.": "Enables the Street View control.", + "Map type": "Map type", + "Enables switching between different map types.": "Enables switching between different map types.", + "Full screen": "Full screen", + "Rotate": "Rotate", + "Controls": "Controls", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Zoom level": "Zoom level", + "Dimensions": "Dimensions", + "Map provider": "Map provider", + "Google MapId key": "Google MapId key", + "Used to render and style the Google map. This MapId key from Google can be found in https://developers.google.com/maps/documentation/get-map-id": "Used to render and style the Google map. This MapId key from Google can be found in https://developers.google.com/maps/documentation/get-map-id", + "Advanced": "Advanced" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.progressbar.progressbar.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.progressbar.progressbar.json new file mode 100644 index 00000000..82e6b00b --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.progressbar.progressbar.json @@ -0,0 +1,16 @@ +{ + "The widget lets you display a percentage as a bar": "The widget lets you display a percentage as a bar", + "Type": "Type", + "Current value": "Current value", + "Minimum value": "Minimum value", + "Maximum value": "Maximum value", + "General": "General", + "On click": "On click", + "Events": "Events", + "Show label": "Show label", + "Label type": "Label type", + "Note: If the Size of the progress bar is set to \"Small\" in the Appearance tab, then text and percentage labels will be shown in a tooltip and custom labels will be ignored.": "Note: If the Size of the progress bar is set to \"Small\" in the Appearance tab, then text and percentage labels will be shown in a tooltip and custom labels will be ignored.", + "Label text": "Label text", + "Custom label": "Custom label", + "Progress Label": "Progress Label" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.progresscircle.progresscircle.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.progresscircle.progresscircle.json new file mode 100644 index 00000000..e1c66ae4 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.progresscircle.progresscircle.json @@ -0,0 +1,15 @@ +{ + "Displays a progress in a circle": "Displays a progress in a circle", + "Type": "Type", + "Current value": "Current value", + "Minimum value": "Minimum value", + "Maximum value": "Maximum value", + "General": "General", + "On click": "On click", + "Events": "Events", + "Show label": "Show label", + "Label type": "Label type", + "Label text": "Label text", + "Custom label": "Custom label", + "Progress Label": "Progress Label" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.rangeslider.rangeslider.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.rangeslider.rangeslider.json new file mode 100644 index 00000000..f5391171 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.rangeslider.rangeslider.json @@ -0,0 +1,36 @@ +{ + "Change range of values using a slider": "Change range of values using a slider", + "Lower bound attribute": "Lower bound attribute", + "The lower bound value on the slider": "The lower bound value on the slider", + "Upper bound attribute": "Upper bound attribute", + "The upper bound value on the slider": "The upper bound value on the slider", + "Data source": "Data source", + "Enable advanced options": "Enable advanced options", + "Minimum value type": "Minimum value type", + "Minimum value": "Minimum value", + "Maximum value type": "Maximum value type", + "Maximum value": "Maximum value", + "Step size type": "Step size type", + "Step size": "Step size", + "Show tooltip": "Show tooltip", + "Lower bound tooltip type": "Lower bound tooltip type", + "By default tooltip shows current value. Choose 'Custom' to create your own template.": "By default tooltip shows current value. Choose 'Custom' to create your own template.", + "Tooltip": "Tooltip", + "Upper bound tooltip type": "Upper bound tooltip type", + "Tooltip always visible": "Tooltip always visible", + "When enabled tooltip is always visible to the user": "When enabled tooltip is always visible to the user", + "General": "General", + "Editability": "Editability", + "Visibility": "Visibility", + "Number of markers": "Number of markers", + "Marker ticks on the slider (visible when larger than 0)": "Marker ticks on the slider (visible when larger than 0)", + "Decimal places": "Decimal places", + "Number of decimal places for marker values": "Number of decimal places for marker values", + "Orientation": "Orientation", + "If orientation is 'Vertical', make sure that parent or slider itself has fixed height": "If orientation is 'Vertical', make sure that parent or slider itself has fixed height", + "Height unit": "Height unit", + "Height": "Height", + "Track": "Track", + "On change": "On change", + "Events": "Events" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.richtext.richtext.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.richtext.richtext.json new file mode 100644 index 00000000..37ad9324 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.richtext.richtext.json @@ -0,0 +1,78 @@ +{ + "Rich inline or toolbar text editing": "Rich inline or toolbar text editing", + "Value attribute": "Value attribute", + "The attribute used for the content of the text editor, recommendation is to use an unlimited string data type.": "The attribute used for the content of the text editor, recommendation is to use an unlimited string data type.", + "Data source": "Data source", + "Menu bar": "Menu bar", + "Enable status bar": "Enable status bar", + "General": "General", + "Toolbar": "Toolbar", + "Mode": "Mode", + "Location": "Location", + "Enable quick toolbar": "Enable quick toolbar", + "Context menu": "Context menu", + "Read-only style": "Read-only style", + "How the rich text editor will appear in read-only mode.": "How the rich text editor will appear in read-only mode.", + "Editability": "Editability", + "Visibility": "Visibility", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Minimum height": "Minimum height", + "Editor's minimum height. The number value is in pixels.": "Editor's minimum height. The number value is in pixels.", + "Editor resize": "Editor resize", + "Dimensions": "Dimensions", + "On change": "On change", + "On enter": "On enter", + "On leave": "On leave", + "On key press": "On key press", + "Events": "Events", + "On change behavior": "On change behavior", + "Additional valid elements": "Additional valid elements", + "Additional sanitization rules to allow certain tag, sample: script[src|async]": "Additional sanitization rules to allow certain tag, sample: script[src|async]", + "Enable spell checking": "Enable spell checking", + "Highlight on focus": "Highlight on focus", + "Additional stylesheet": "Additional stylesheet", + "Additional stylesheet to be included in the rich text content": "Additional stylesheet to be included in the rich text content", + "Sandbox iframes": "Sandbox iframes", + "When enabled, all embedded media using iframes elements will be given the sandbox=\"\" attribute, applying all restrictions.": "When enabled, all embedded media using iframes elements will be given the sandbox=\"\" attribute, applying all restrictions.", + "Use relative URL Link": "Use relative URL Link", + "When enabled, same domain URL links will be converted into relative URL.": "When enabled, same domain URL links will be converted into relative URL.", + "Advanced": "Advanced", + "Toolbar group": "Toolbar group", + "Basic style": "Basic style", + "Extended style": "Extended style", + "Text alignment": "Text alignment", + "Clipboard": "Clipboard", + "Font style": "Font style", + "Paragraph": "Paragraph", + "Document": "Document", + "History": "History", + "Accordion": "Accordion", + "Code": "Code", + "Anchor": "Anchor", + "Text direction": "Text direction", + "Link": "Link", + "List": "List", + "Preview": "Preview", + "Table": "Table", + "Visual aid": "Visual aid", + "Media": "Media", + "Utility": "Utility", + "Emoticon": "Emoticon", + "Removal": "Removal", + "Advanced groups": "Advanced groups", + "Button": "Button", + "Button Type": "Button Type", + "Custom toolbar": "Custom toolbar", + "File": "File", + "Edit": "Edit", + "Insert": "Insert", + "View": "View", + "Format": "Format", + "Tools": "Tools", + "Help": "Help", + "Custom menubar": "Custom menubar" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.slider.slider.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.slider.slider.json new file mode 100644 index 00000000..937d270e --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.slider.slider.json @@ -0,0 +1,35 @@ +{ + "Change a number value using a slider": "Change a number value using a slider", + "Value attribute": "Value attribute", + "Data source": "Data source", + "Enable advanced options": "Enable advanced options", + "Minimum value type": "Minimum value type", + "Minimum value": "Minimum value", + "The minimum value of the slider.": "The minimum value of the slider.", + "Maximum value type": "Maximum value type", + "Maximum value": "Maximum value", + "The maximum value of the slider.": "The maximum value of the slider.", + "Step size type": "Step size type", + "Step size": "Step size", + "Value to be added or subtracted on each step the slider makes. Must be greater than zero, and max - min should be evenly divisible by the step value.": "Value to be added or subtracted on each step the slider makes. Must be greater than zero, and max - min should be evenly divisible by the step value.", + "Show tooltip": "Show tooltip", + "Tooltip type": "Tooltip type", + "By default tooltip shows current value. Choose 'Custom' to create your own template.": "By default tooltip shows current value. Choose 'Custom' to create your own template.", + "Tooltip": "Tooltip", + "Tooltip always visible": "Tooltip always visible", + "When enabled tooltip is always visible to the user": "When enabled tooltip is always visible to the user", + "General": "General", + "Editability": "Editability", + "Visibility": "Visibility", + "Number of markers": "Number of markers", + "The number of marker ticks that appear along the slider’s track. (Visible when larger than 0)": "The number of marker ticks that appear along the slider’s track. (Visible when larger than 0)", + "Decimal places": "Decimal places", + "Number of decimal places for marker values": "Number of decimal places for marker values", + "Orientation": "Orientation", + "The orientation of the slider. If ‘Vertical’, make sure to set the either the height of the parent or slider to a fixed height.": "The orientation of the slider. If ‘Vertical’, make sure to set the either the height of the parent or slider to a fixed height.", + "Height unit": "Height unit", + "Height": "Height", + "Track": "Track", + "On change": "On change", + "Events": "Events" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.starrating.starrating.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.starrating.starrating.json new file mode 100644 index 00000000..768daade --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.starrating.starrating.json @@ -0,0 +1,12 @@ +{ + "Attribute": "Attribute", + "Empty icon": "Empty icon", + "Selected icon": "Selected icon", + "Amount": "Amount", + "The number of rating icons": "The number of rating icons", + "Animation": "Animation", + "General": "General", + "On change": "On change", + "Events": "Events", + "Common": "Common" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.switch.switch.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.switch.switch.json new file mode 100644 index 00000000..e5cc524c --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.custom.switch.switch.json @@ -0,0 +1,11 @@ +{ + "Toggle a boolean attribute": "Toggle a boolean attribute", + "Boolean attribute": "Boolean attribute", + "Attribute to toggle": "Attribute to toggle", + "Data source": "Data source", + "On change": "On change", + "Action to be performed when the switch is toggled": "Action to be performed when the switch is toggled", + "Actions": "Actions", + "General": "General", + "Common": "Common" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.accessibilityhelper.accessibilityhelper.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.accessibilityhelper.accessibilityhelper.json new file mode 100644 index 00000000..201d7d75 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.accessibilityhelper.accessibilityhelper.json @@ -0,0 +1,14 @@ +{ + "Target selector": "Target selector", + "Selector to find the first HTML element you want to target which must be a valid CSS selector like '.mx-name-texbox1 input'": "Selector to find the first HTML element you want to target which must be a valid CSS selector like '.mx-name-texbox1 input'", + "Content": "Content", + "HTML Attributes": "HTML Attributes", + "HTML attribute": "HTML attribute", + "The HTML attribute to be set based on the condition. The following attributes are not allowed: 'class', 'style', 'widgetid', 'data-mendix-id'.": "The HTML attribute to be set based on the condition. The following attributes are not allowed: 'class', 'style', 'widgetid', 'data-mendix-id'.", + "Source type": "Source type", + "Expression value": "Expression value", + "Text value": "Text value", + "Condition": "Condition", + "Condition to determine if the HTML attribute must be set or not": "Condition to determine if the HTML attribute must be set or not", + "General": "General" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.accordion.accordion.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.accordion.accordion.json new file mode 100644 index 00000000..55ccf812 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.accordion.accordion.json @@ -0,0 +1,33 @@ +{ + "Toggle the display of sections of content.": "Toggle the display of sections of content.", + "Enable advanced options": "Enable advanced options", + "Groups": "Groups", + "Header": "Header", + "Text": "Text", + "Render mode": "Render mode", + "Content": "Content", + "Visible": "Visible", + "Dynamic class": "Dynamic class", + "Load content": "Load content", + "This property determines when the widgets should be rendered and data is fetched. The “Always” option will always load the widgets regardless whether the group is expanded. The “When expanded” option can reduce the initial (page) load time, but will increase the load time when expanding the group.": "This property determines when the widgets should be rendered and data is fetched. The “Always” option will always load the widgets regardless whether the group is expanded. The “When expanded” option can reduce the initial (page) load time, but will increase the load time when expanding the group.", + "General": "General", + "Start as": "Start as", + "Start as collapsed": "Start as collapsed", + "Collapsed": "Collapsed", + "Determines whether the group is collapsed or expanded. The 'Start as' properties override the attribute value for the initial state.": "Determines whether the group is collapsed or expanded. The 'Start as' properties override the attribute value for the initial state.", + "On change": "On change", + "Executes an action when the 'Collapsed' attribute value changes. Note: the 'Start as' properties can prevent execution of this action when the initial state changes.": "Executes an action when the 'Collapsed' attribute value changes. Note: the 'Start as' properties can prevent execution of this action when the initial state changes.", + "State": "State", + "Collapsible": "Collapsible", + "Expanded groups": "Expanded groups", + "Allow a single group or multiple groups to be expanded at the same time.": "Allow a single group or multiple groups to be expanded at the same time.", + "Animate": "Animate", + "Behavior": "Behavior", + "Show icon": "Show icon", + "Icon": "Icon", + "Expand icon": "Expand icon", + "Collapse icon": "Collapse icon", + "Animate icon": "Animate icon", + "Animate the icon when the group is collapsing or expanding.": "Animate the icon when the group is collapsing or expanding.", + "Visualization": "Visualization" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.areachart.areachart.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.areachart.areachart.json new file mode 100644 index 00000000..d3c2b8aa --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.areachart.areachart.json @@ -0,0 +1,47 @@ +{ + "Create an area chart": "Create an area chart", + "Series": "Series", + "Add series and configure their properties": "Add series and configure their properties", + "Data set": "Data set", + "Data source": "Data source", + "Data points for a single series.": "Data points for a single series.", + "Data points for all series which will be divided into single series based on the Group by attribute value.": "Data points for all series which will be divided into single series based on the Group by attribute value.", + "Group by": "Group by", + "Data points within the same group form one series.": "Data points within the same group form one series.", + "Series name": "Series name", + "The series name displayed in the legend.": "The series name displayed in the legend.", + "X axis attribute": "X axis attribute", + "Y axis attribute": "Y axis attribute", + "Aggregation function": "Aggregation function", + "Defines how data is aggregated when multiple Y values are available for a single X value": "Defines how data is aggregated when multiple Y values are available for a single X value", + "Tooltip hover text": "Tooltip hover text", + "General": "General", + "Interpolation": "Interpolation", + "Line style": "Line style", + "Line color": "Line color", + "Marker color": "Marker color", + "Area fill color": "Area fill color", + "Appearance": "Appearance", + "On click action": "On click action", + "Events": "Events", + "Custom series options": "Custom series options", + "Advanced": "Advanced", + "Enable advanced options": "Enable advanced options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "X axis label": "X axis label", + "Y axis label": "Y axis label", + "Show legend": "Show legend", + "Grid lines": "Grid lines", + "Visibility": "Visibility", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.barchart.barchart.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.barchart.barchart.json new file mode 100644 index 00000000..5e3a575c --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.barchart.barchart.json @@ -0,0 +1,44 @@ +{ + "Create a bar chart": "Create a bar chart", + "Series": "Series", + "Add one or more lines. The order influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.": "Add one or more lines. The order influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.", + "Data set": "Data set", + "Data source": "Data source", + "Data points for a single line.": "Data points for a single line.", + "Data points for all lines which will be divided into single lines based on the Group by attribute value.": "Data points for all lines which will be divided into single lines based on the Group by attribute value.", + "Group by": "Group by", + "Data points within the same group form one line.": "Data points within the same group form one line.", + "Series name": "Series name", + "The line name displayed in the legend.": "The line name displayed in the legend.", + "X axis attribute": "X axis attribute", + "Y axis attribute": "Y axis attribute", + "Aggregation function": "Aggregation function", + "Defines how data is aggregated when multiple Y values are available for a single X value": "Defines how data is aggregated when multiple Y values are available for a single X value", + "Tooltip hover text": "Tooltip hover text", + "General": "General", + "Bar color": "Bar color", + "Appearance": "Appearance", + "On click action": "On click action", + "Events": "Events", + "Custom series options": "Custom series options", + "Advanced": "Advanced", + "Enable advanced options": "Enable advanced options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "X axis label": "X axis label", + "Y axis label": "Y axis label", + "Bar format": "Bar format", + "Show legend": "Show legend", + "Grid lines": "Grid lines", + "Visibility": "Visibility", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.barcodescanner.barcodescanner.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.barcodescanner.barcodescanner.json new file mode 100644 index 00000000..6fd037ac --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.barcodescanner.barcodescanner.json @@ -0,0 +1,24 @@ +{ + "The widget lets you scan a barcode": "The widget lets you scan a barcode", + "Scanned result": "Scanned result", + "The String attribute used to store the result of the scanned barcode.": "The String attribute used to store the result of the scanned barcode.", + "Show barcode mask": "Show barcode mask", + "Apply a mask to camera view, as a specific target area for the barcode.": "Apply a mask to camera view, as a specific target area for the barcode.", + "Use all barcode formats": "Use all barcode formats", + "Scan for all available barcode formats": "Scan for all available barcode formats", + "Enabled barcode formats": "Enabled barcode formats", + "Barcode format": "Barcode format", + "Barcode format which should be recognized by the scanner": "Barcode format which should be recognized by the scanner", + "Object list group": "Object list group", + "General": "General", + "On detect action": "On detect action", + "Action to trigger when the barcode has been successfully detected.": "Action to trigger when the barcode has been successfully detected.", + "Events": "Events", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.bubblechart.bubblechart.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.bubblechart.bubblechart.json new file mode 100644 index 00000000..18a71217 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.bubblechart.bubblechart.json @@ -0,0 +1,47 @@ +{ + "Create a bubble chart": "Create a bubble chart", + "Data source": "Data source", + "Add one or more lines. The order influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.": "Add one or more lines. The order influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.", + "Data set": "Data set", + "Data points for a single line.": "Data points for a single line.", + "Data points for all lines which will be divided into single lines based on the Group by attribute value.": "Data points for all lines which will be divided into single lines based on the Group by attribute value.", + "Group by": "Group by", + "Data points within the same group form one line.": "Data points within the same group form one line.", + "Series name": "Series name", + "The line name displayed in the legend.": "The line name displayed in the legend.", + "X axis attribute": "X axis attribute", + "Y axis attribute": "Y axis attribute", + "Aggregation function": "Aggregation function", + "Defines how data is aggregated when multiple Y values are available for a single X value": "Defines how data is aggregated when multiple Y values are available for a single X value", + "Bubble size attribute": "Bubble size attribute", + "The value determines the bubble size": "The value determines the bubble size", + "Auto scale": "Auto scale", + "Scale factor": "Scale factor", + "When “Auto scale” is set to false, use the scale factor to determine the rendered size of the bubble, it will multiply the value of “bubble size” by this factor.": "When “Auto scale” is set to false, use the scale factor to determine the rendered size of the bubble, it will multiply the value of “bubble size” by this factor.", + "Tooltip hover text": "Tooltip hover text", + "General": "General", + "Marker color": "Marker color", + "Appearance": "Appearance", + "On click action": "On click action", + "Events": "Events", + "Custom series options": "Custom series options", + "Advanced": "Advanced", + "Enable advanced options": "Enable advanced options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "X axis label": "X axis label", + "Y axis label": "Y axis label", + "Show legend": "Show legend", + "Grid lines": "Grid lines", + "Visibility": "Visibility", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.chartplayground.chartplayground.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.chartplayground.chartplayground.json new file mode 100644 index 00000000..a964983a --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.chartplayground.chartplayground.json @@ -0,0 +1,3 @@ +{ + "A helper for easy and quick chart customization": "A helper for easy and quick chart customization" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.columnchart.columnchart.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.columnchart.columnchart.json new file mode 100644 index 00000000..9bcda6c8 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.columnchart.columnchart.json @@ -0,0 +1,45 @@ +{ + "Create a column chart": "Create a column chart", + "Series": "Series", + "Add one or more columns. The order influences how columns overlay one another: the first column (from the top) is drawn lowest and other columns are drawn on top of it.": "Add one or more columns. The order influences how columns overlay one another: the first column (from the top) is drawn lowest and other columns are drawn on top of it.", + "Data set": "Data set", + "Data source": "Data source", + "Data points for a single column.": "Data points for a single column.", + "Data points for all columns which will be divided into single columns based on the Group by attribute value.": "Data points for all columns which will be divided into single columns based on the Group by attribute value.", + "Group by": "Group by", + "Data points within the same group form one column.": "Data points within the same group form one column.", + "Series name": "Series name", + "The column name displayed in the legend.": "The column name displayed in the legend.", + "X axis attribute": "X axis attribute", + "Y axis attribute": "Y axis attribute", + "Aggregation function": "Aggregation function", + "Defines how data is aggregated when multiple Y values are available for a single X value": "Defines how data is aggregated when multiple Y values are available for a single X value", + "Tooltip hover text": "Tooltip hover text", + "General": "General", + "Column color": "Column color", + "Appearance": "Appearance", + "On click action": "On click action", + "Events": "Events", + "Custom series options": "Custom series options", + "Advanced": "Advanced", + "Data Source": "Data Source", + "Enable advanced options": "Enable advanced options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "X axis label": "X axis label", + "Y axis label": "Y axis label", + "Show legend": "Show legend", + "Grid lines": "Grid lines", + "Column format": "Column format", + "Visibility": "Visibility", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.combobox.combobox.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.combobox.combobox.json new file mode 100644 index 00000000..ae9d77c6 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.combobox.combobox.json @@ -0,0 +1,58 @@ +{ + "Source": "Source", + "Type": "Type", + "Attribute": "Attribute", + "Selectable objects": "Selectable objects", + "Selection type": "Selection type", + "Data source": "Data source", + "Value": "Value", + "Default value": "Default value", + "Entity": "Entity", + "Caption type": "Caption type", + "Caption": "Caption", + "Values": "Values", + "Value to be set": "Value to be set", + "Custom content": "Custom content", + "Caption to be shown": "Caption to be shown", + "Static values": "Static values", + "Placeholder text": "Placeholder text", + "Filter type": "Filter type", + "No options text": "No options text", + "Clearable": "Clearable", + "Show footer": "Show footer", + "Footer content": "Footer content", + "General": "General", + "Selection method": "Selection method", + "Show selected items as": "Show selected items as", + "Show select all": "Show select all", + "Add a button to select/deselect all options.": "Add a button to select/deselect all options.", + "Caption for select all": "Caption for select all", + "Multiple-selection (reference set)": "Multiple-selection (reference set)", + "Label": "Label", + "Conditional visibility": "Conditional visibility", + "Read-only style": "Read-only style", + "How the combo box will appear in read-only mode.": "How the combo box will appear in read-only mode.", + "Editability": "Editability", + "On change action": "On change action", + "On enter action": "On enter action", + "On leave action": "On leave action", + "Events": "Events", + "Aria required": "Aria required", + "Accessibility": "Accessibility", + "Clear selection button": "Clear selection button", + "Used to clear all selected values.": "Used to clear all selected values.", + "Remove value button": "Remove value button", + "Used to remove individual selected values when using labels with multi-selection.": "Used to remove individual selected values when using labels with multi-selection.", + "Aria labels": "Aria labels", + "Selected value": "Selected value", + "Output example: \"Selected value: Avocado, Apple, Banana.\"": "Output example: \"Selected value: Avocado, Apple, Banana.\"", + "Options available": "Options available", + "Output example: \"Number of options available: 1\"": "Output example: \"Number of options available: 1\"", + "Instructions": "Instructions", + "Instructions to be read after announcing the status.": "Instructions to be read after announcing the status.", + "Accessibility status message": "Accessibility status message", + "Lazy loading": "Lazy loading", + "Loading type": "Loading type", + "Performance": "Performance", + "Advanced": "Advanced" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagrid.datagrid.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagrid.datagrid.json new file mode 100644 index 00000000..04aa95e8 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagrid.datagrid.json @@ -0,0 +1,87 @@ +{ + "Enable advanced options": "Enable advanced options", + "Data source": "Data source", + "Refresh time (in seconds)": "Refresh time (in seconds)", + "Selection": "Selection", + "Selection method": "Selection method", + "Toggle on click": "Toggle on click", + "Defines item selection behavior.": "Defines item selection behavior.", + "Show (un)check all toggle": "Show (un)check all toggle", + "Show a checkbox in the grid header to check or uncheck multiple items.": "Show a checkbox in the grid header to check or uncheck multiple items.", + "General": "General", + "Columns": "Columns", + "Show": "Show", + "Attribute": "Attribute", + "Attribute is required if the column can be sorted or filtered": "Attribute is required if the column can be sorted or filtered", + "Custom content": "Custom content", + "Dynamic text": "Dynamic text", + "Export value": "Export value", + "Caption": "Caption", + "Tooltip": "Tooltip", + "Filter": "Filter", + "Reference": "Reference", + "Set the reference to enable filtering over association with the Drop-down filter widget.": "Set the reference to enable filtering over association with the Drop-down filter widget.", + "The options to show in the Drop-down filter widget.": "The options to show in the Drop-down filter widget.", + "Use lazy load": "Use lazy load", + "Lazy loading enables faster data grid loading, but with personalization enabled, value restoration will be limited.": "Lazy loading enables faster data grid loading, but with personalization enabled, value restoration will be limited.", + "Option caption": "Option caption", + "Visible": "Visible", + "Can sort": "Can sort", + "Can resize": "Can resize", + "Can reorder": "Can reorder", + "Can hide": "Can hide", + "Allow row events": "Allow row events", + "If set to yes, then all default events on the row, such as \"on click\" or selection, will be triggered when the user interacts with custom content.": "If set to yes, then all default events on the row, such as \"on click\" or selection, will be triggered when the user interacts with custom content.", + "Column capabilities": "Column capabilities", + "Column width": "Column width", + "Min width": "Min width", + "Min width value (px)": "Min width value (px)", + "Column size": "Column size", + "Alignment": "Alignment", + "Dynamic cell class": "Dynamic cell class", + "Wrap text": "Wrap text", + "Appearance": "Appearance", + "Show column filters": "Show column filters", + "Page size": "Page size", + "Pagination": "Pagination", + "Position of paging buttons": "Position of paging buttons", + "Show paging buttons": "Show paging buttons", + "Load more caption": "Load more caption", + "Empty list message": "Empty list message", + "Empty placeholder": "Empty placeholder", + "Dynamic row class": "Dynamic row class", + "Rows": "Rows", + "On click trigger": "On click trigger", + "On click action": "On click action", + "On selection change": "On selection change", + "Events": "Events", + "Sorting": "Sorting", + "Enable sorting for all columns unless specified otherwise in the column setting": "Enable sorting for all columns unless specified otherwise in the column setting", + "Resizing": "Resizing", + "Enable resizing for all columns unless specified otherwise in the column setting": "Enable resizing for all columns unless specified otherwise in the column setting", + "Reordering": "Reordering", + "Enable reordering for all columns unless specified otherwise in the column setting": "Enable reordering for all columns unless specified otherwise in the column setting", + "Hiding": "Hiding", + "Enable hiding for all columns unless specified otherwise in the column setting": "Enable hiding for all columns unless specified otherwise in the column setting", + "Store configuration in": "Store configuration in", + "When Browser local storage is selected, the configuration is scoped to a browser profile. This configuration is not tied to a Mendix user.": "When Browser local storage is selected, the configuration is scoped to a browser profile. This configuration is not tied to a Mendix user.", + "Attribute containing the personalized configuration of the capabilities. This configuration is automatically stored and loaded. The attribute requires Unlimited String.": "Attribute containing the personalized configuration of the capabilities. This configuration is automatically stored and loaded. The attribute requires Unlimited String.", + "On change": "On change", + "Configuration": "Configuration", + "Personalization": "Personalization", + "Filters": "Filters", + "The list of attributes is used by the filter widgets that are placed in the placeholder above the data grid. This enables filtering across multiple attributes or columns instead of limiting to a single column.": "The list of attributes is used by the filter widgets that are placed in the placeholder above the data grid. This enables filtering across multiple attributes or columns instead of limiting to a single column.", + "Filter attribute": "Filter attribute", + "Filters placeholder": "Filters placeholder", + "Grid wide filtering": "Grid wide filtering", + "Filter section": "Filter section", + "Assistive technology will read this upon reaching a filtering or sorting section.": "Assistive technology will read this upon reaching a filtering or sorting section.", + "Export progress": "Export progress", + "Assistive technology will read this upon reaching a export dialog.": "Assistive technology will read this upon reaching a export dialog.", + "Cancel data export": "Cancel data export", + "Assistive technology will read this upon reaching a cancel button.": "Assistive technology will read this upon reaching a cancel button.", + "Select row": "Select row", + "If selection is enabled, assistive technology will read this upon reaching a checkbox.": "If selection is enabled, assistive technology will read this upon reaching a checkbox.", + "Aria labels": "Aria labels", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagriddatefilter.datagriddatefilter.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagriddatefilter.datagriddatefilter.json new file mode 100644 index 00000000..c441751a --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagriddatefilter.datagriddatefilter.json @@ -0,0 +1,28 @@ +{ + "Enable advanced options": "Enable advanced options", + "Default value": "Default value", + "Default start date": "Default start date", + "Default end date": "Default end date", + "Default filter": "Default filter", + "Placeholder": "Placeholder", + "Adjustable by user": "Adjustable by user", + "General": "General", + "Saved attribute": "Saved attribute", + "Attribute used to store the last value of the filter.": "Attribute used to store the last value of the filter.", + "Saved start date attribute": "Saved start date attribute", + "Attribute used to store the last value of the start date filter.": "Attribute used to store the last value of the start date filter.", + "Saved end date attribute": "Saved end date attribute", + "Attribute used to store the last value of the end date filter.": "Attribute used to store the last value of the end date filter.", + "Configurations": "Configurations", + "On change": "On change", + "Action to be triggered when the value or filter changes.": "Action to be triggered when the value or filter changes.", + "Events": "Events", + "Comparison button caption": "Comparison button caption", + "Assistive technology will read this upon reaching the comparison button that triggers the filter type drop-down menu.": "Assistive technology will read this upon reaching the comparison button that triggers the filter type drop-down menu.", + "Calendar button caption": "Calendar button caption", + "Assistive technology will read this upon reaching the button that triggers the calendar.": "Assistive technology will read this upon reaching the button that triggers the calendar.", + "Input caption": "Input caption", + "Assistive technology will read this upon reaching the input element.": "Assistive technology will read this upon reaching the input element.", + "Screen reader": "Screen reader", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagriddropdownfilter.datagriddropdownfilter.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagriddropdownfilter.datagriddropdownfilter.json new file mode 100644 index 00000000..4e799ca4 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagriddropdownfilter.datagriddropdownfilter.json @@ -0,0 +1,22 @@ +{ + "Automatic options": "Automatic options", + "Show options based on the references or the enumeration values and captions.": "Show options based on the references or the enumeration values and captions.", + "Enable advanced options": "Enable advanced options", + "Default value": "Default value", + "Empty option caption will be shown by default or if configured default value matches none of the options": "Empty option caption will be shown by default or if configured default value matches none of the options", + "Options": "Options", + "Caption": "Caption", + "Value": "Value", + "Empty option caption": "Empty option caption", + "Multiselect": "Multiselect", + "General": "General", + "Saved attribute": "Saved attribute", + "Attribute used to store the last value of the filter. Associations are not supported.": "Attribute used to store the last value of the filter. Associations are not supported.", + "Configurations": "Configurations", + "On change": "On change", + "Action to be triggered when the value or filter changes.": "Action to be triggered when the value or filter changes.", + "Events": "Events", + "Input caption": "Input caption", + "Assistive technology will read this upon reaching the input element.": "Assistive technology will read this upon reaching the input element.", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagridnumberfilter.datagridnumberfilter.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagridnumberfilter.datagridnumberfilter.json new file mode 100644 index 00000000..c8e6f272 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagridnumberfilter.datagridnumberfilter.json @@ -0,0 +1,23 @@ +{ + "Enable advanced options": "Enable advanced options", + "Default value": "Default value", + "Default filter": "Default filter", + "Placeholder": "Placeholder", + "Adjustable by user": "Adjustable by user", + "General": "General", + "Apply after (ms)": "Apply after (ms)", + "Wait this period before applying then change(s) to the filter": "Wait this period before applying then change(s) to the filter", + "On change behavior": "On change behavior", + "Saved attribute": "Saved attribute", + "Attribute used to store the last value of the filter.": "Attribute used to store the last value of the filter.", + "Configurations": "Configurations", + "On change": "On change", + "Action to be triggered when the value or filter changes.": "Action to be triggered when the value or filter changes.", + "Events": "Events", + "Comparison button caption": "Comparison button caption", + "Assistive technology will read this upon reaching the comparison button that triggers the filter type drop-down menu.": "Assistive technology will read this upon reaching the comparison button that triggers the filter type drop-down menu.", + "Input caption": "Input caption", + "Assistive technology will read this upon reaching the input element.": "Assistive technology will read this upon reaching the input element.", + "Screen reader": "Screen reader", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagridtextfilter.datagridtextfilter.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagridtextfilter.datagridtextfilter.json new file mode 100644 index 00000000..c8e6f272 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.datagridtextfilter.datagridtextfilter.json @@ -0,0 +1,23 @@ +{ + "Enable advanced options": "Enable advanced options", + "Default value": "Default value", + "Default filter": "Default filter", + "Placeholder": "Placeholder", + "Adjustable by user": "Adjustable by user", + "General": "General", + "Apply after (ms)": "Apply after (ms)", + "Wait this period before applying then change(s) to the filter": "Wait this period before applying then change(s) to the filter", + "On change behavior": "On change behavior", + "Saved attribute": "Saved attribute", + "Attribute used to store the last value of the filter.": "Attribute used to store the last value of the filter.", + "Configurations": "Configurations", + "On change": "On change", + "Action to be triggered when the value or filter changes.": "Action to be triggered when the value or filter changes.", + "Events": "Events", + "Comparison button caption": "Comparison button caption", + "Assistive technology will read this upon reaching the comparison button that triggers the filter type drop-down menu.": "Assistive technology will read this upon reaching the comparison button that triggers the filter type drop-down menu.", + "Input caption": "Input caption", + "Assistive technology will read this upon reaching the input element.": "Assistive technology will read this upon reaching the input element.", + "Screen reader": "Screen reader", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.dropdownsort.dropdownsort.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.dropdownsort.dropdownsort.json new file mode 100644 index 00000000..e2f29e58 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.dropdownsort.dropdownsort.json @@ -0,0 +1,9 @@ +{ + "Empty option caption": "Empty option caption", + "General": "General", + "Sort order button caption": "Sort order button caption", + "Assistive technology will read this upon reaching the sort order button.": "Assistive technology will read this upon reaching the sort order button.", + "Input caption": "Input caption", + "Assistive technology will read this upon reaching the input element.": "Assistive technology will read this upon reaching the input element.", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.events.events.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.events.events.json new file mode 100644 index 00000000..73bcafca --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.events.events.json @@ -0,0 +1,11 @@ +{ + "Events": "Events", + "Action": "Action", + "Delay": "Delay", + "Timer delay to first action execution. Value is in milliseconds. If set to 0, action will be triggered immediately.": "Timer delay to first action execution. Value is in milliseconds. If set to 0, action will be triggered immediately.", + "Repeat": "Repeat", + "Interval between repeat action execution. Value is in milliseconds.": "Interval between repeat action execution. Value is in milliseconds.", + "Component load": "Component load", + "Attribute": "Attribute", + "On change": "On change" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.fieldset.fieldset.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.fieldset.fieldset.json new file mode 100644 index 00000000..d6b46c08 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.fieldset.fieldset.json @@ -0,0 +1,7 @@ +{ + "Legend": "Legend", + "Content": "Content", + "General": "General", + "Visibility": "Visibility", + "Common": "Common" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.fileuploader.fileuploader.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.fileuploader.fileuploader.json new file mode 100644 index 00000000..073e9ba3 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.fileuploader.fileuploader.json @@ -0,0 +1,20 @@ +{ + "My widget description": "My widget description", + "Associated files": "Associated files", + "Action to create new files": "Action to create new files", + "Allowed file formats": "Allowed file formats", + "List of comma separated file formats. No restrictions if left empty.": "List of comma separated file formats. No restrictions if left empty.", + "Configuration mode": "Configuration mode", + "Predefined type": "Predefined type", + "Mime Type": "Mime Type", + "For example 'image/jpeg' or 'application/pdf'": "For example 'image/jpeg' or 'application/pdf'", + "Extensions list": "Extensions list", + "Comma separated list of extensions. For example: '.jpg,.jpeg'.": "Comma separated list of extensions. For example: '.jpg,.jpeg'.", + "Type description": "Type description", + "Shown to the end users to describe supported file types.": "Shown to the end users to describe supported file types.", + "General": "General", + "Maximum number of files": "Maximum number of files", + "Limit the number of file per one upload.": "Limit the number of file per one upload.", + "Maximum file size (MB)": "Maximum file size (MB)", + "Reject files that are bigger than specified size.": "Reject files that are bigger than specified size." +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.gallery.gallery.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.gallery.gallery.json new file mode 100644 index 00000000..b74acb90 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.gallery.gallery.json @@ -0,0 +1,39 @@ +{ + "Enable advanced options": "Enable advanced options", + "Data source": "Data source", + "Selection": "Selection", + "Item click toggles selection": "Item click toggles selection", + "Defines item selection behavior.": "Defines item selection behavior.", + "Content placeholder": "Content placeholder", + "General": "General", + "Desktop columns": "Desktop columns", + "Tablet columns": "Tablet columns", + "Phone columns": "Phone columns", + "Columns": "Columns", + "Page size": "Page size", + "Pagination": "Pagination", + "Position of paging buttons": "Position of paging buttons", + "Empty message": "Empty message", + "Empty placeholder": "Empty placeholder", + "Dynamic item class": "Dynamic item class", + "Items": "Items", + "On click trigger": "On click trigger", + "On click action": "On click action", + "On selection change": "On selection change", + "Events": "Events", + "Filters": "Filters", + "Filter attribute": "Filter attribute", + "Filters placeholder": "Filters placeholder", + "Filtering": "Filtering", + "Sort attributes": "Sort attributes", + "Attribute": "Attribute", + "Caption": "Caption", + "Sorting": "Sorting", + "Filter section": "Filter section", + "Assistive technology will read this upon reaching a filtering or sorting section.": "Assistive technology will read this upon reaching a filtering or sorting section.", + "Assistive technology will read this upon reaching an empty message section.": "Assistive technology will read this upon reaching an empty message section.", + "Content description": "Content description", + "Assistive technology will read this upon reaching gallery.": "Assistive technology will read this upon reaching gallery.", + "Aria labels": "Aria labels", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.googletag.googletag.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.googletag.googletag.json new file mode 100644 index 00000000..10832422 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.googletag.googletag.json @@ -0,0 +1,20 @@ +{ + "Google tag integration widget": "Google tag integration widget", + "Widget mode": "Widget mode", + "The basic option automatically sends page view events. Place this widget in the layouts to automatically send events when pages are changed. The advanced option can be used for more control.": "The basic option automatically sends page view events. Place this widget in the layouts to automatically send events when pages are changed. The advanced option can be used for more control.", + "Tag ID": "Tag ID", + "Examples of tag IDs include GT-XXXXXXXXX, G-XXXXXXXXX, and AW-XXXXXXXXX": "Examples of tag IDs include GT-XXXXXXXXX, G-XXXXXXXXX, and AW-XXXXXXXXX", + "Parameters": "Parameters", + "Name": "Name", + "Value": "Value", + "Standard value": "Standard value", + "Custom value": "Custom value", + "General": "General", + "Share user ID": "Share user ID", + "Expose the authenticated User ID to uniquely identify individual users in Google Analytics.": "Expose the authenticated User ID to uniquely identify individual users in Google Analytics.", + "Command": "Command", + "Event can be used to send an event. Config can be used to configure advanced configuration parameters.": "Event can be used to send an event. Config can be used to configure advanced configuration parameters.", + "Event name": "Event name", + "Track page changes": "Track page changes", + "Send the event when the page is changed.": "Send the event when the page is changed." +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.heatmap.heatmap.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.heatmap.heatmap.json new file mode 100644 index 00000000..6ee2dc47 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.heatmap.heatmap.json @@ -0,0 +1,50 @@ +{ + "Renders a heatmap chart": "Renders a heatmap chart", + "Series": "Series", + "Value attribute": "Value attribute", + "The attribute used to display “heat” at an “x y” location.": "The attribute used to display “heat” at an “x y” location.", + "Data source": "Data source", + "X Axis Attribute": "X Axis Attribute", + "X Axis Sort Attribute": "X Axis Sort Attribute", + "Attribute to use for sorting the data. Sorting can only be used when data source is ‘Database’. For data source ‘Microflow’, the sorting should be done within the microflow.": "Attribute to use for sorting the data. Sorting can only be used when data source is ‘Database’. For data source ‘Microflow’, the sorting should be done within the microflow.", + "X Axis Sort Order": "X Axis Sort Order", + "Y Axis Attribute": "Y Axis Attribute", + "Y Axis Sort Attribute": "Y Axis Sort Attribute", + "Y Axis Sort Order": "Y Axis Sort Order", + "Axis": "Axis", + "Enable Advanced Options": "Enable Advanced Options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "X axis label": "X axis label", + "Y axis label": "Y axis label", + "Show Scale": "Show Scale", + "Grid lines": "Grid lines", + "General": "General", + "Colors": "Colors", + "The percentages with the colors that should be applied. At least two values needs to be specified, for 0% and 100%, else the default colors are used.": "The percentages with the colors that should be applied. At least two values needs to be specified, for 0% and 100%, else the default colors are used.", + "Percentage": "Percentage", + "The percentage at which the color should be applied. This value must be between 0 and 100.": "The percentage at which the color should be applied. This value must be between 0 and 100.", + "Color": "Color", + "The CSS value e.g. blue, #48B0F7 or rgb(0,0,0)": "The CSS value e.g. blue, #48B0F7 or rgb(0,0,0)", + "Scale": "Scale", + "Smooth color": "Smooth color", + "Gradual color gradient between data points": "Gradual color gradient between data points", + "Show values": "Show values", + "Font value color": "Font value color", + "Visibility": "Visibility", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "On click action": "On click action", + "Tooltip hover text": "Tooltip hover text", + "Events": "Events", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations", + "Custom series options": "Custom series options", + "Advanced": "Advanced", + "Common": "Common" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.htmlelement.htmlelement.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.htmlelement.htmlelement.json new file mode 100644 index 00000000..11fdf8c2 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.htmlelement.htmlelement.json @@ -0,0 +1,27 @@ +{ + "Displays custom HTML": "Displays custom HTML", + "Tag name": "Tag name", + "Custom tag": "Custom tag", + "Repeat element": "Repeat element", + "Repeat element for each item in data source.": "Repeat element for each item in data source.", + "Data source": "Data source", + "Content": "Content", + "HTML": "HTML", + "HTML element": "HTML element", + "Attributes": "Attributes", + "The HTML attributes that are added to the HTML element. For example: ‘title‘, ‘href‘. If ‘class’ or ‘style’ is added as attribute this is merged with the widget class/style property. For events (e.g. onClick) use the Events section.": "The HTML attributes that are added to the HTML element. For example: ‘title‘, ‘href‘. If ‘class’ or ‘style’ is added as attribute this is merged with the widget class/style property. For events (e.g. onClick) use the Events section.", + "Name": "Name", + "Value based on": "Value based on", + "Value": "Value", + "HTML attributes": "HTML attributes", + "General": "General", + "Events": "Events", + "Action": "Action", + "Event": "Event", + "Stop propagation": "Stop propagation", + "Prevent default": "Prevent default", + "Advanced": "Advanced", + "Sanitization configuration": "Sanitization configuration", + "Configuration for HTML sanitization in JSON format. Leave blank for default.": "Configuration for HTML sanitization in JSON format. Leave blank for default.", + "HTML Sanitization": "HTML Sanitization" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.image.image.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.image.image.json new file mode 100644 index 00000000..f72c6c19 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.image.image.json @@ -0,0 +1,34 @@ +{ + "Display an image and enlarge it on click.": "Display an image and enlarge it on click.", + "Image type": "Image type", + "Image source": "Image source", + "Default image": "Default image", + "This is the image that is displayed if no image is uploaded.": "This is the image that is displayed if no image is uploaded.", + "Image URL": "Image URL", + "The link of the external image.": "The link of the external image.", + "Icon": "Icon", + "The icon image.": "The icon image.", + "Background image": "Background image", + "Whether the image is rendered as a background. More content can be put inside, while design properties will have no effect.": "Whether the image is rendered as a background. More content can be put inside, while design properties will have no effect.", + "Place content here": "Place content here", + "Data source": "Data source", + "On click type": "On click type", + "On click": "On click", + "Events": "Events", + "Alternative text": "Alternative text", + "Alternative text of the image for accessibility purposes.": "Alternative text of the image for accessibility purposes.", + "Accessibility": "Accessibility", + "Conditional Visibility": "Conditional Visibility", + "General": "General", + "Width unit": "Width unit", + "Width": "Width", + "Height unit": "Height unit", + "Auto will keep the aspect ratio of the image.": "Auto will keep the aspect ratio of the image.", + "Height": "Height", + "Icon size": "Icon size", + "The size of the icon in pixels.": "The size of the icon in pixels.", + "Show": "Show", + "Responsive": "Responsive", + "Image will never get larger than its original size. It can become smaller.": "Image will never get larger than its original size. It can become smaller.", + "Dimensions": "Dimensions" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.languageselector.languageselector.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.languageselector.languageselector.json new file mode 100644 index 00000000..2c258144 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.languageselector.languageselector.json @@ -0,0 +1,15 @@ +{ + "Data source": "Data source", + "Recommended: Database data source with System.Language as entity.": "Recommended: Database data source with System.Language as entity.", + "Language caption": "Language caption", + "Recommended: $currentObject/Description.": "Recommended: $currentObject/Description.", + "Languages": "Languages", + "Menu position": "Menu position", + "The location of the menu relative to the current selected language (click area).": "The location of the menu relative to the current selected language (click area).", + "Open menu on": "Open menu on", + "Hide for single language": "Hide for single language", + "General": "General", + "Label caption": "Label caption", + "Assistive technology will read this upon reaching the input element.": "Assistive technology will read this upon reaching the input element.", + "Accessibility": "Accessibility" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.linechart.linechart.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.linechart.linechart.json new file mode 100644 index 00000000..15fd8c47 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.linechart.linechart.json @@ -0,0 +1,46 @@ +{ + "Create a line chart": "Create a line chart", + "Series": "Series", + "Add one or more lines. The order influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.": "Add one or more lines. The order influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.", + "Data set": "Data set", + "Data source": "Data source", + "Data points for a single line.": "Data points for a single line.", + "Data points for all lines which will be divided into single lines based on the Group by attribute value.": "Data points for all lines which will be divided into single lines based on the Group by attribute value.", + "Group by": "Group by", + "Data points within the same group form one line.": "Data points within the same group form one line.", + "Series name": "Series name", + "The line name displayed in the legend.": "The line name displayed in the legend.", + "X axis attribute": "X axis attribute", + "Y axis attribute": "Y axis attribute", + "Aggregation function": "Aggregation function", + "Defines how data is aggregated when multiple Y values are available for a single X value": "Defines how data is aggregated when multiple Y values are available for a single X value", + "Tooltip hover text": "Tooltip hover text", + "General": "General", + "Interpolation": "Interpolation", + "Line style": "Line style", + "Line color": "Line color", + "Marker color": "Marker color", + "Appearance": "Appearance", + "On click action": "On click action", + "Events": "Events", + "Custom series options": "Custom series options", + "Advanced": "Advanced", + "Enable advanced options": "Enable advanced options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "X axis label": "X axis label", + "Y axis label": "Y axis label", + "Show legend": "Show legend", + "Grid lines": "Grid lines", + "Visibility": "Visibility", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.markdown.markdown.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.markdown.markdown.json new file mode 100644 index 00000000..32452283 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.markdown.markdown.json @@ -0,0 +1,8 @@ +{ + "Value attribute": "Value attribute", + "The attribute used for the content of the text editor, recommendation is to use an unlimited string data type.": "The attribute used for the content of the text editor, recommendation is to use an unlimited string data type.", + "Data source": "Data source", + "Label": "Label", + "Conditional visibility": "Conditional visibility", + "General": "General" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.piechart.piechart.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.piechart.piechart.json new file mode 100644 index 00000000..c46e2238 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.piechart.piechart.json @@ -0,0 +1,33 @@ +{ + "Renders a pie or doughnut chart": "Renders a pie or doughnut chart", + "Series": "Series", + "Series name": "Series name", + "Value attribute": "Value attribute", + "Sort attribute": "Sort attribute", + "Sort order": "Sort order", + "Slice color": "Slice color", + "Data source": "Data source", + "Enable advanced options": "Enable advanced options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "Show legend": "Show legend", + "Hole radius": "Hole radius", + "A percentage between 0 and 100 indicating the radius of the hole in the pie chart relative to the chart itself. Defaults to 0.": "A percentage between 0 and 100 indicating the radius of the hole in the pie chart relative to the chart itself. Defaults to 0.", + "Tooltip hover text": "Tooltip hover text", + "General": "General", + "Visibility": "Visibility", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "On click action": "On click action", + "Events": "Events", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations", + "Custom series options": "Custom series options", + "Advanced": "Advanced" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.popupmenu.popupmenu.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.popupmenu.popupmenu.json new file mode 100644 index 00000000..ca6e75a9 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.popupmenu.popupmenu.json @@ -0,0 +1,24 @@ +{ + "Displays a set of pre-defined items within the Pop-up menu": "Displays a set of pre-defined items within the Pop-up menu", + "Enable advanced options": "Enable advanced options", + "The area to open or close the menu.": "The area to open or close the menu.", + "Responsible for toggling the Pop-up menu.": "Responsible for toggling the Pop-up menu.", + "Menu items": "Menu items", + "The popup menu items.": "The popup menu items.", + "Item type": "Item type", + "Caption": "Caption", + "Visible": "Visible", + "On click action": "On click action", + "Style": "Style", + "An extra class will be added: \"popupmenu-basic-item-[style]\"": "An extra class will be added: \"popupmenu-basic-item-[style]\"", + "The popup menu custom items. To make sure the popup closes correctly after a click, do not configure clickable widgets inside the placeholders. Use the action property of this widget.": "The popup menu custom items. To make sure the popup closes correctly after a click, do not configure clickable widgets inside the placeholders. Use the action property of this widget.", + "Content": "Content", + "Open on": "Open on", + "Close on": "Close on", + "Menu position": "Menu position", + "The location of the menu relative to the click area.": "The location of the menu relative to the click area.", + "General": "General", + "Show preview": "Show preview", + "Use this to see a preview of the menu items while developing.": "Use this to see a preview of the menu items while developing.", + "Development": "Development" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.selectionhelper.selectionhelper.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.selectionhelper.selectionhelper.json new file mode 100644 index 00000000..c1e52c5f --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.selectionhelper.selectionhelper.json @@ -0,0 +1,9 @@ +{ + "Style": "Style", + "Custom enables placeholders for using widgets for the different states.": "Custom enables placeholders for using widgets for the different states.", + "Check box caption": "Check box caption", + "All selected": "All selected", + "Some selected": "Some selected", + "None selected": "None selected", + "General": "General" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.timeline.timeline.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.timeline.timeline.json new file mode 100644 index 00000000..6f78a8e2 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.timeline.timeline.json @@ -0,0 +1,34 @@ +{ + "Shows vertical timeline with events": "Shows vertical timeline with events", + "Data source": "Data source", + "Title": "Title", + "Description": "Description", + "Time Indication": "Time Indication", + "Data Source": "Data Source", + "Custom Visualization": "Custom Visualization", + "Enables free to model timeline.": "Enables free to model timeline.", + "Icon": "Icon", + "If no icon is configured, a circle will be rendered.": "If no icon is configured, a circle will be rendered.", + "Group Events": "Group Events", + "Shows a header between grouped events based on event date.": "Shows a header between grouped events based on event date.", + "Group Attribute": "Group Attribute", + "Will be used for grouping events, as a group header value. If events have no date time value, use \"Unscheduled events placement\" to control rendering.": "Will be used for grouping events, as a group header value. If events have no date time value, use \"Unscheduled events placement\" to control rendering.", + "Group by": "Group by", + "Group events based on day, month or year.": "Group events based on day, month or year.", + "Format": "Format", + "Format group header with current language's format": "Format group header with current language's format", + "Ungrouped events position": "Ungrouped events position", + "Position in the list of events without a date and time": "Position in the list of events without a date and time", + "General": "General", + "Content of the icon": "Content of the icon", + "Group header": "Group header", + "Content of the group header": "Content of the group header", + "Content of the title": "Content of the title", + "Event time": "Event time", + "Content of the event time": "Content of the event time", + "Content": "Content", + "Content of the description": "Content of the description", + "Custom": "Custom", + "On click": "On click", + "Events": "Events" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.timeseries.timeseries.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.timeseries.timeseries.json new file mode 100644 index 00000000..b374f38b --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.timeseries.timeseries.json @@ -0,0 +1,52 @@ +{ + "Create a time series chart": "Create a time series chart", + "Series": "Series", + "Add one or more series. The order of series influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.": "Add one or more series. The order of series influences how lines overlay one another: the first line (from the top) is drawn lowest and other lines are drawn on top of it.", + "Data set": "Data set", + "Data source": "Data source", + "Data points for a single line.": "Data points for a single line.", + "Data points for all lines which will be divided into single lines based on the Group by attribute value.": "Data points for all lines which will be divided into single lines based on the Group by attribute value.", + "Series name": "Series name", + "The line name displayed in the legend.": "The line name displayed in the legend.", + "Group by": "Group by", + "Data points within the same group form one line.": "Data points within the same group form one line.", + "X axis attribute": "X axis attribute", + "Y axis attribute": "Y axis attribute", + "Aggregation function": "Aggregation function", + "Defines how data is aggregated when multiple Y values are available for a single X value": "Defines how data is aggregated when multiple Y values are available for a single X value", + "Tooltip hover text": "Tooltip hover text", + "General": "General", + "Interpolation": "Interpolation", + "Line style": "Line style", + "Line color": "Line color", + "Marker color": "Marker color", + "Fill area": "Fill area", + "Fill area between data point and x-axis": "Fill area between data point and x-axis", + "Area color": "Area color", + "By default, the border color with transparency is used": "By default, the border color with transparency is used", + "Appearance": "Appearance", + "On click action": "On click action", + "Events": "Events", + "Custom series options": "Custom series options", + "Advanced": "Advanced", + "Enable advanced options": "Enable advanced options", + "Show playground slot": "Show playground slot", + "Playground slot": "Playground slot", + "X axis label": "X axis label", + "Y axis label": "Y axis label", + "Show legend": "Show legend", + "Show range slider": "Show range slider", + "Grid lines": "Grid lines", + "Common": "Common", + "Width unit": "Width unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Height": "Height", + "Dimensions": "Dimensions", + "Enable theme folder config loading": "Enable theme folder config loading", + "Custom layout": "Custom layout", + "Custom configurations": "Custom configurations", + "Y-axis range mode": "Y-axis range mode", + "Controls the y-axis range. \"From zero\" starts the y-axis from zero. \"Auto\" sets the range based on the plotted values. \"Non-negative\" only shows a range of positive values. If the series \"Fill area\" property is set to \"yes\", the range mode is set to \"From zero\" by default.": "Controls the y-axis range. \"From zero\" starts the y-axis from zero. \"Auto\" sets the range based on the plotted values. \"Non-negative\" only shows a range of positive values. If the series \"Fill area\" property is set to \"yes\", the range mode is set to \"From zero\" by default." +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.tooltip.tooltip.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.tooltip.tooltip.json new file mode 100644 index 00000000..c14d02c3 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.tooltip.tooltip.json @@ -0,0 +1,13 @@ +{ + "Trigger: place widgets here": "Trigger: place widgets here", + "Render method": "Render method", + "Tooltip content: place widgets here": "Tooltip content: place widgets here", + "Tooltip": "Tooltip", + "Tooltip position": "Tooltip position", + "How to position the tooltip in relation to the trigger element - at the top, to the left, at the bottom or to the right.": "How to position the tooltip in relation to the trigger element - at the top, to the left, at the bottom or to the right.", + "Arrow position": "Arrow position", + "How to position the tooltip arrow in relation to the tooltip - at the start, in the center or at the end.": "How to position the tooltip arrow in relation to the tooltip - at the start, in the center or at the end.", + "Open on": "Open on", + "How the tooltip is triggered - click, hover, hover and focus. On mobile device “hover” will be triggered on touch.": "How the tooltip is triggered - click, hover, hover and focus. On mobile device “hover” will be triggered on touch.", + "General": "General" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.treenode.treenode.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.treenode.treenode.json new file mode 100644 index 00000000..7f72846a --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.treenode.treenode.json @@ -0,0 +1,23 @@ +{ + "Display a tree view structure": "Display a tree view structure", + "Enable advanced options": "Enable advanced options", + "Data source": "Data source", + "Header type": "Header type", + "Open node when": "Open node when", + "Define which part of the node, when clicked, should open or close this node. \"Header is clicked\" means the whole header is clickable, while \"Icon is clicked\" means only the icon is used to switch node state.": "Define which part of the node, when clicked, should open or close this node. \"Header is clicked\" means the whole header is clickable, while \"Icon is clicked\" means only the icon is used to switch node state.", + "Header": "Header", + "Header caption": "Header caption", + "Has children": "Has children", + "Indicate whether the node has children or is an end node. When set to yes, a composable region becomes available to define the child nodes.": "Indicate whether the node has children or is an end node. When set to yes, a composable region becomes available to define the child nodes.", + "Start expanded": "Start expanded", + "Place other Tree nodes here": "Place other Tree nodes here", + "Animate": "Animate", + "General": "General", + "Show icon": "Show icon", + "Expanded icon": "Expanded icon", + "Collapsed icon": "Collapsed icon", + "Animate icon": "Animate icon", + "Animate the icon when the group is collapsing or expanding.": "Animate the icon when the group is collapsing or expanding.", + "Icon": "Icon", + "Visualization": "Visualization" +} diff --git a/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.videoplayer.videoplayer.json b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.videoplayer.videoplayer.json new file mode 100644 index 00000000..e8cbc641 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/com.mendix.widget.web.videoplayer.videoplayer.json @@ -0,0 +1,29 @@ +{ + "Shows a video from YouTube, Vimeo, Dailymotion and Mp4": "Shows a video from YouTube, Vimeo, Dailymotion and Mp4", + "Type": "Type", + "Video URL": "Video URL", + "The web address of the video: YouTube, Vimeo, Dailymotion or MP4.": "The web address of the video: YouTube, Vimeo, Dailymotion or MP4.", + "Poster URL": "Poster URL", + "The web address of the poster image. A poster image is a custom preview image that will be shown in the player until the user starts the video.": "The web address of the poster image. A poster image is a custom preview image that will be shown in the player until the user starts the video.", + "Data source": "Data source", + "Common": "Common", + "General": "General", + "Auto start": "Auto start", + "Automatically start playing the video when the page loads.": "Automatically start playing the video when the page loads.", + "Show Controls": "Show Controls", + "Display video controls (control bar, display icons, dock buttons). Available for YouTube, Dailymotion and external videos.": "Display video controls (control bar, display icons, dock buttons). Available for YouTube, Dailymotion and external videos.", + "Muted": "Muted", + "Start the video on mute.": "Start the video on mute.", + "Loop": "Loop", + "Loop the video after it finishes. Available for YouTube, Vimeo, and external videos.": "Loop the video after it finishes. Available for YouTube, Vimeo, and external videos.", + "Controls": "Controls", + "Width Unit": "Width Unit", + "Percentage: portion of parent size. Pixels: absolute amount of pixels.": "Percentage: portion of parent size. Pixels: absolute amount of pixels.", + "Width": "Width", + "Height unit": "Height unit", + "Aspect ratio: ratio of width to height. Percentage of parent: portion of parent height. Percentage of width: portion of the width. Pixels: absolute amount of pixels.": "Aspect ratio: ratio of width to height. Percentage of parent: portion of parent height. Percentage of width: portion of the width. Pixels: absolute amount of pixels.", + "Aspect ratio": "Aspect ratio", + "16:9 (Widescreen, HD Video), 4:3 (Classic TV, Standard monitor), 3:2 (Classic film), 21:9 (Cinemascope), 1:1 (Square, Social media)": "16:9 (Widescreen, HD Video), 4:3 (Classic TV, Standard monitor), 3:2 (Classic film), 21:9 (Cinemascope), 1:1 (Square, Social media)", + "Height": "Height", + "Dimensions": "Dimensions" +} diff --git a/Source/themesource/atlas_core/locales/en-US/translation.json b/Source/themesource/atlas_core/locales/en-US/translation.json new file mode 100644 index 00000000..74c88100 --- /dev/null +++ b/Source/themesource/atlas_core/locales/en-US/translation.json @@ -0,0 +1,153 @@ +{ + "Add a shadow to this element": "Add a shadow to this element", + "Add alternating background colors to groups in the accordion.": "Add alternating background colors to groups in the accordion.", + "Align content": "Align content", + "Align content of this element left, right or center it. Align elements inside the container as a row or as a column.": "Align content of this element left, right or center it. Align elements inside the container as a row or as a column.", + "Align icon": "Align icon", + "Align self": "Align self", + "Align the image in the center of an element.": "Align the image in the center of an element.", + "Align the text.": "Align the text.", + "Alignment": "Alignment", + "All": "All", + "Android": "Android", + "Apply a shade to your background color": "Apply a shade to your background color", + "Auto": "Auto", + "Background Primary": "Background Primary", + "Background Secondary": "Background Secondary", + "Background color": "Background color", + "Bar color": "Bar color", + "Bold": "Bold", + "Border": "Border", + "Bordered": "Bordered", + "Borders": "Borders", + "Brand Danger": "Brand Danger", + "Brand Gradient": "Brand Gradient", + "Brand Primary": "Brand Primary", + "Brand Secondary": "Brand Secondary", + "Brand Success": "Brand Success", + "Brand Warning": "Brand Warning", + "Break long words and sentences into multiple lines.": "Break long words and sentences into multiple lines.", + "Callout style": "Callout style", + "Capitalize": "Capitalize", + "Center": "Center", + "Center align as a column": "Center align as a column", + "Center align as a row": "Center align as a row", + "Center image": "Center image", + "Change size of the rating icon/image. Default is medium.": "Change size of the rating icon/image. Default is medium.", + "Change the appearance of a label.": "Change the appearance of a label.", + "Change the appearance of cells in the table.": "Change the appearance of cells in the table.", + "Change the appearance of rows in the list view.": "Change the appearance of rows in the list view.", + "Change the appearance of the tab container": "Change the appearance of the tab container", + "Change the background color of the container.": "Change the background color of the container.", + "Change the border appearance. By default, only horizontal borders between groups are applied.": "Change the border appearance. By default, only horizontal borders between groups are applied.", + "Change the color of text.": "Change the color of text.", + "Change the fit of the image.": "Change the fit of the image.", + "Change the image style.": "Change the image style.", + "Change the letter case of the text.": "Change the letter case of the text.", + "Change the opacity of the image.": "Change the opacity of the image.", + "Change the position of the tabs": "Change the position of the tabs", + "Change the row spacing of the list view.": "Change the row spacing of the list view.", + "Change the spacing between cells to be compact.": "Change the spacing between cells to be compact.", + "Choose one of the following styles to change the appearance of the data grid.": "Choose one of the following styles to change the appearance of the data grid.", + "Choose one of the following styles to change the appearance of the groupbox.": "Choose one of the following styles to change the appearance of the groupbox.", + "Choose one of the following styles to change the appearance of the template grid.": "Choose one of the following styles to change the appearance of the template grid.", + "Choose the image fit.": "Choose the image fit.", + "Choose the style of your image.": "Choose the style of your image.", + "Circle": "Circle", + "Color": "Color", + "Color of the progress bar": "Color of the progress bar", + "Compact": "Compact", + "Contain": "Contain", + "Cover": "Cover", + "Danger": "Danger", + "Dark": "Dark", + "Desktop": "Desktop", + "Detail color": "Detail color", + "Device style": "Device style", + "Emphasize the text with a heavier or lighter font weight": "Emphasize the text with a heavier or lighter font weight", + "Enable data grid hover to make rows hoverable.": "Enable data grid hover to make rows hoverable.", + "Enable groupbox callout functionality to highlight importance of groupbox.": "Enable groupbox callout functionality to highlight importance of groupbox.", + "Enable template grid hover to make rows hoverable.": "Enable template grid hover to make rows hoverable.", + "Extend button to full width of container it is placed in.": "Extend button to full width of container it is placed in.", + "Fill": "Fill", + "Fit": "Fit", + "Float element left or right.": "Float element left or right.", + "Full width": "Full width", + "Header color": "Header color", + "Hide icons": "Hide icons", + "Hide navigation items icon": "Hide navigation items icon", + "Hide on device type": "Hide on device type", + "High": "High", + "Highlight row when hovering over it. Only useful when row is clickable.": "Highlight row when hovering over it. Only useful when row is clickable.", + "Horizontal": "Horizontal", + "Hover style": "Hover style", + "Image fit": "Image fit", + "Image style": "Image style", + "Increase or decrease row spacing in data grid row.": "Increase or decrease row spacing in data grid row.", + "Justify": "Justify", + "Justify tabs to 100% width": "Justify tabs to 100% width", + "L": "L", + "Large": "Large", + "Left": "Left", + "Left align as a column": "Left align as a column", + "Left align as a row": "Left align as a row", + "Letter case": "Letter case", + "Light": "Light", + "Lined": "Lined", + "Low": "Low", + "M": "M", + "Make groups in accordion more compact.": "Make groups in accordion more compact.", + "Make text smaller or larger.": "Make text smaller or larger.", + "Medium": "Medium", + "No styling": "No styling", + "No wrap": "No wrap", + "None": "None", + "Normal": "Normal", + "Opacity": "Opacity", + "Phone": "Phone", + "Pills": "Pills", + "Place icon right or on top button.": "Place icon right or on top button.", + "Primary": "Primary", + "Right": "Right", + "Right align as a column": "Right align as a column", + "Right align as a row": "Right align as a row", + "Rounded": "Rounded", + "Row size": "Row size", + "S": "S", + "Scale-down": "Scale-down", + "Semibold": "Semibold", + "Shade": "Shade", + "Shadow": "Shadow", + "Show widget as inline element.": "Show widget as inline element.", + "Size": "Size", + "Size buttons accordingly: Small, Medium, Large, Full width, etc.. ": "Size buttons accordingly: Small, Medium, Large, Full width, etc.. ", + "Size of the buttons": "Size of the buttons", + "Size of the progress bar": "Size of the progress bar", + "Small": "Small", + "Spacing": "Spacing", + "Square": "Square", + "Striped": "Striped", + "Striped bar": "Striped bar", + "Striped progress bar": "Striped progress bar", + "Style": "Style", + "Style button with transparent background, colored border, and colored text.": "Style button with transparent background, colored border, and colored text.", + "Success": "Success", + "Tab position": "Tab position", + "Tablet": "Tablet", + "The brand style affecting this element's appearance.": "The brand style affecting this element's appearance.", + "The general appearance of the switch. When no option selected iOS styles are applied": "The general appearance of the switch. When no option selected iOS styles are applied", + "The spacing around a widget": "The spacing around a widget", + "Thickness of the progress circle": "Thickness of the progress circle", + "Thumbnail": "Thumbnail", + "Top": "Top", + "Transparent": "Transparent", + "UPPER": "UPPER", + "Warning": "Warning", + "Weight": "Weight", + "White": "White", + "Wizard": "Wizard", + "Wrap": "Wrap", + "Wrap options": "Wrap options", + "iOS": "iOS", + "lower": "lower" +} diff --git a/Source/themesource/atlas_core/locales/metadata.json b/Source/themesource/atlas_core/locales/metadata.json new file mode 100644 index 00000000..db436bbd --- /dev/null +++ b/Source/themesource/atlas_core/locales/metadata.json @@ -0,0 +1,50 @@ +{ + "WidgetsToBeTranslated": [ + "com.mendix.widget.custom.badge.badge", + "com.mendix.widget.custom.badgebutton.badgebutton", + "com.mendix.widget.custom.carousel.carousel", + "com.mendix.widget.custom.colorpicker.colorpicker", + "com.mendix.widget.custom.maps.maps", + "com.mendix.widget.custom.progressbar.progressbar", + "com.mendix.widget.custom.progresscircle.progresscircle", + "com.mendix.widget.custom.rangeslider.rangeslider", + "com.mendix.widget.custom.richtext.richtext", + "com.mendix.widget.custom.slider.slider", + "com.mendix.widget.custom.starrating.starrating", + "com.mendix.widget.custom.switch.switch", + "com.mendix.widget.web.accessibilityhelper.accessibilityhelper", + "com.mendix.widget.web.accordion.accordion", + "com.mendix.widget.web.areachart.areachart", + "com.mendix.widget.web.barchart.barchart", + "com.mendix.widget.web.barcodescanner.barcodescanner", + "com.mendix.widget.web.bubblechart.bubblechart", + "com.mendix.widget.web.chartplayground.chartplayground", + "com.mendix.widget.web.columnchart.columnchart", + "com.mendix.widget.web.combobox.combobox", + "com.mendix.widget.web.datagrid.datagrid", + "com.mendix.widget.web.datagriddatefilter.datagriddatefilter", + "com.mendix.widget.web.datagriddropdownfilter.datagriddropdownfilter", + "com.mendix.widget.web.datagridnumberfilter.datagridnumberfilter", + "com.mendix.widget.web.datagridtextfilter.datagridtextfilter", + "com.mendix.widget.web.dropdownsort.dropdownsort", + "com.mendix.widget.web.events.events", + "com.mendix.widget.web.fieldset.fieldset", + "com.mendix.widget.web.fileuploader.fileuploader", + "com.mendix.widget.web.gallery.gallery", + "com.mendix.widget.web.googletag.googletag", + "com.mendix.widget.web.heatmap.heatmap", + "com.mendix.widget.web.htmlelement.htmlelement", + "com.mendix.widget.web.image.image", + "com.mendix.widget.web.languageselector.languageselector", + "com.mendix.widget.web.linechart.linechart", + "com.mendix.widget.web.markdown.markdown", + "com.mendix.widget.web.piechart.piechart", + "com.mendix.widget.web.popupmenu.popupmenu", + "com.mendix.widget.web.selectionhelper.selectionhelper", + "com.mendix.widget.web.timeline.timeline", + "com.mendix.widget.web.timeseries.timeseries", + "com.mendix.widget.web.tooltip.tooltip", + "com.mendix.widget.web.treenode.treenode", + "com.mendix.widget.web.videoplayer.videoplayer" + ] +} diff --git a/Source/themesource/atlas_core/native/core/widgets/tabcontainer.js b/Source/themesource/atlas_core/native/core/widgets/tabcontainer.js index 1f683721..68415e56 100644 --- a/Source/themesource/atlas_core/native/core/widgets/tabcontainer.js +++ b/Source/themesource/atlas_core/native/core/widgets/tabcontainer.js @@ -23,7 +23,7 @@ export const TabContainer = { pressOpacity: 0.8, pressColor: tabContainer.tabBar.pressColor, backgroundColor: tabContainer.tabBar.backgroundColor, - height: 48, + minHeight: 48, justifyContent: "center" }, indicator: { diff --git a/Source/themesource/atlas_core/web/core/helpers/_helper-classes.scss b/Source/themesource/atlas_core/web/core/helpers/_helper-classes.scss index e3b7d6f9..8d250342 100644 --- a/Source/themesource/atlas_core/web/core/helpers/_helper-classes.scss +++ b/Source/themesource/atlas_core/web/core/helpers/_helper-classes.scss @@ -195,12 +195,18 @@ display: none #{$important-helpers-value}; } } + .profile-phone .hide-phone { + display: none #{$important-helpers-value}; + } @media (min-width: $screen-md) and (max-width: $screen-md-max) { .hide-tablet { display: none #{$important-helpers-value}; } } + .profile-tablet .hide-tablet { + display: none #{$important-helpers-value}; + } @media (min-width: $screen-lg) { .hide-desktop { diff --git a/Source/themesource/atlas_core/web/core/helpers/_navigation-bar.scss b/Source/themesource/atlas_core/web/core/helpers/_navigation-bar.scss index ccdda1a1..533bc872 100644 --- a/Source/themesource/atlas_core/web/core/helpers/_navigation-bar.scss +++ b/Source/themesource/atlas_core/web/core/helpers/_navigation-bar.scss @@ -82,11 +82,12 @@ border: 0; box-shadow: 0px 2px 2px rgba(194, 196, 201, 0.30354); & > li.mx-navbar-subitem a { - padding: $spacing-small; - color: $navtopbar-color; border-radius: $border-radius-default; - margin-bottom: $spacing-small; + color: $navtopbar-color; + font-size: $navtopbar-sub-font-size; line-height: 1.2; + margin: 0 0 $spacing-small; + padding: $spacing-small; &:hover, &:focus { color: $navtopbar-color-hover; diff --git a/Source/themesource/atlas_core/web/core/widgets/_data-view.scss b/Source/themesource/atlas_core/web/core/widgets/_data-view.scss index 7cde6310..413ad5ba 100644 --- a/Source/themesource/atlas_core/web/core/widgets/_data-view.scss +++ b/Source/themesource/atlas_core/web/core/widgets/_data-view.scss @@ -13,11 +13,16 @@ ========================================================================== */ .mx-dataview { - /* Dataview-content gives problems for nexted layout grid containers */ - > .mx-dataview-content > .mx-container-nested { - > .row { - margin-right: 0; - margin-left: 0; + display: flex; + flex-direction: column; + /* Dataview-content gives problems for nested layout grid containers */ + > .mx-dataview-content { + flex-grow: 1; + > .mx-container-nested { + > .row { + margin-right: 0; + margin-left: 0; + } } } @@ -29,7 +34,6 @@ } .mx-dataview-controls { - margin-top: $spacing-medium; padding: $spacing-medium 0 0; border-top: 1px solid $dataview-controls-border-color; border-radius: 0; diff --git a/Source/themesource/atlas_core/web/core/widgets/_modal.scss b/Source/themesource/atlas_core/web/core/widgets/_modal.scss index 29ffd5a9..c7fa9865 100644 --- a/Source/themesource/atlas_core/web/core/widgets/_modal.scss +++ b/Source/themesource/atlas_core/web/core/widgets/_modal.scss @@ -36,7 +36,7 @@ /* For IE8 and earlier */ color: $modal-header-color; text-shadow: none; - &:focus { + &:focus-visible { border-radius: 4px; outline: 2px solid $brand-primary; } diff --git a/Source/themesource/atlas_core/web/core/widgets/_pop-up-menu.scss b/Source/themesource/atlas_core/web/core/widgets/_pop-up-menu.scss index 1f77ea9b..30f2111c 100644 --- a/Source/themesource/atlas_core/web/core/widgets/_pop-up-menu.scss +++ b/Source/themesource/atlas_core/web/core/widgets/_pop-up-menu.scss @@ -14,9 +14,11 @@ .popupmenu { position: relative; display: inline-flex; + overflow: visible; } .popupmenu-trigger { + position: relative; cursor: pointer; } @@ -65,6 +67,17 @@ } } + ul.popupmenu-menu { + display: flex; + list-style-type: none; + padding-inline-start: 0; + z-index: 1; + } + + .table .td > .popupmenu { + overflow: visible; + } + .popupmenu-basic-divider { width: 100%; height: 1px; diff --git a/Source/themesource/atlas_core/web/core/widgets/_scroll-container-react.scss b/Source/themesource/atlas_core/web/core/widgets/_scroll-container-react.scss index 01e6bbc7..451a43eb 100644 --- a/Source/themesource/atlas_core/web/core/widgets/_scroll-container-react.scss +++ b/Source/themesource/atlas_core/web/core/widgets/_scroll-container-react.scss @@ -132,7 +132,7 @@ .mx-scrollcontainer-push:not(.mx-scrollcontainer-open) > .mx-scrollcontainer-toggleable, .mx-scrollcontainer-slide:not(.mx-scrollcontainer-open) > .mx-scrollcontainer-toggleable { flex-basis: var(--closed-sidebar-width, 0px); - overflow: clip; + overflow: hidden; } // For open sidebar - full width @@ -188,8 +188,16 @@ overflow-x: clip; } - .mx-scrollcontainer-wrapper:not(.mx-scrollcontainer-nested) { - -webkit-overflow-scrolling: touch; + .mx-scrollcontainer-wrapper { + height: 100%; + + &:not(.mx-scrollcontainer-nested) { + -webkit-overflow-scrolling: touch; + } + + & > .mx-placeholder { + height: 100%; + } } // for push aside and slide over the main part should be non-interactive if sidebar is open diff --git a/Source/themesource/atlas_core/web/layouts/_layout-atlas-responsive.scss b/Source/themesource/atlas_core/web/layouts/_layout-atlas-responsive.scss index 5b9a2e01..ad6945e2 100644 --- a/Source/themesource/atlas_core/web/layouts/_layout-atlas-responsive.scss +++ b/Source/themesource/atlas_core/web/layouts/_layout-atlas-responsive.scss @@ -26,7 +26,7 @@ &.mx-navigationtree-has-items:hover > ul { position: absolute; z-index: 100; - top: 0; + top: $topbar-minimalheight; bottom: 0; left: $sidebar-icon-width; display: block; @@ -34,6 +34,7 @@ padding: $spacing-small 0; & > li.mx-navigationtree-has-items:hover > ul { + top: 0; left: 100%; } } @@ -187,6 +188,18 @@ @media (max-width: $screen-sm-max) { padding: 0 $spacing-small; } + + .mx-scrollcontainer-wrapper { + .mx-layoutgrid, + .mx-layoutgrid-fluid { + padding: 0 $gutter-size; + } + } + + .mx-icon-filled, + .mx-icon-lined { + font-size: 20px; + } } } diff --git a/Source/themesource/atlas_core/web/main.scss b/Source/themesource/atlas_core/web/main.scss index 29c24e1a..563c96be 100644 --- a/Source/themesource/atlas_core/web/main.scss +++ b/Source/themesource/atlas_core/web/main.scss @@ -2,9 +2,9 @@ @import "exclusion-variables-defaults"; @import "../../../theme/web/exclusion-variables"; @import "generated-exclusion-variables"; +@import "../../../theme/web/custom-variables"; @import "variables"; @import "variables-css-mappings"; -@import "../../../theme/web/custom-variables"; // Font Family Import @if $font-family-import != false { diff --git a/Source/themesource/atlas_web_content/.version b/Source/themesource/atlas_web_content/.version index 40c341bd..19811903 100644 --- a/Source/themesource/atlas_web_content/.version +++ b/Source/themesource/atlas_web_content/.version @@ -1 +1 @@ -3.6.0 +3.8.0 diff --git a/Source/themesource/datawidgets/.version b/Source/themesource/datawidgets/.version index 54f61a74..8de9f111 100644 --- a/Source/themesource/datawidgets/.version +++ b/Source/themesource/datawidgets/.version @@ -1 +1 @@ -2.28.1 \ No newline at end of file +2.31.0 \ No newline at end of file diff --git a/Source/themesource/datawidgets/web/_datagrid-dropdown-filter.scss b/Source/themesource/datawidgets/web/_datagrid-dropdown-filter.scss new file mode 100644 index 00000000..b77663d6 --- /dev/null +++ b/Source/themesource/datawidgets/web/_datagrid-dropdown-filter.scss @@ -0,0 +1,329 @@ +@mixin scroll-shadow { + background: + /* Shadow Cover TOP */ + linear-gradient(white 30%, rgba(255, 255, 255, 0)) center top, + /* Shadow Cover BOTTOM */ linear-gradient(rgba(255, 255, 255, 0), white 70%) center bottom, + /* Shadow TOP */ linear-gradient(0deg, rgba(255, 255, 255, 0.6), rgba(197, 197, 197, 0.6)) center top, + /* Shadow BOTTOM */ linear-gradient(180deg, rgba(255, 255, 255, 0.6), rgba(197, 197, 197, 0.6)) center bottom; + + background-repeat: no-repeat; + background-size: + 100% 70px, + 100% 70px, + 100% 35px, + 100% 35px; + background-attachment: local, local, scroll, scroll; +} + +@mixin btn-with-cross { + path { + stroke-width: 0; + } + &:hover { + color: var(--brand-primary, #264ae5); + path { + stroke-width: 1px; + } + } +} + +$root: ".widget-dropdown-filter"; + +#{$root} { + --wdf-outer-spacing: var(--dropdown-outer-spacing, 10px); + --wdf-spacing: var(--spacing-smaller, 4px); + --wdf-spacing-tiny: var(--spacing-smallest, 2px); + --wdf-popover-spacing: 0; + --wdf-popover-z-index: 50; + --wdf-popover-shadow: 0px 0px var(--wdf-outer-spacing) 0px var(--shadow-color-border, rgba(0, 0, 0, 0.2)); + --wdf-bd-radius: var(--dropdown-border-radius, 7px); + --wdf-menu-bg-color: var(--label-info-color, #ffffff); + --wdf-menu-max-height: var(--dropdown-menu-max-height, 320px); + --wdf-menu-item-padding: 6px 10px; + --wdf-highlighted-bg-color: var(--color-default-light, #f5f6f6); + --wdf-selected-bg-color: var(--color-primary-lighter, #e6eaff); + --wdf-button-spacing: 8px; + --wdf-color: var(--gray-dark, black); + --wdf-state-icon-size: 16px; + --wdf-toggle-width: calc(4px + var(--wdf-state-icon-size) + var(--wdf-button-spacing)); + --wdf-toggle-inline-end: var(--wdf-toggle-width); + --wdf-clear-margin: var(--wdf-toggle-inline-end); + --wdf-clear-inline-spacing: 6px; + --wdf-clear-border-width: 1px; + --wdf-clear-width: calc(14px + (var(--wdf-clear-inline-spacing) * 2) + var(--wdf-clear-border-width)); + --wdf-toggle-inline-end-clearable: calc(var(--wdf-clear-width) + var(--wdf-toggle-inline-end)); + --wdf-tag-padding: var(--wdf-spacing-tiny) var(--dropdown-outer-spacing, 10px); + + &.form-control { + display: flex; + min-width: 65px; + padding-block: var(--wdf-button-spacing); + padding-inline-end: var(--wdf-button-spacing); + padding-inline-start: var(--wdf-button-spacing); + } + + &-popover { + z-index: var(--wdf-popover-z-index); + box-shadow: var(--wdf-popover-shadow); + margin-top: var(--wdf-spacing); + border-radius: var(--wdf-bd-radius); + } + + &-menu-slot { + border-radius: inherit; + background-color: var(--wdf-menu-bg-color); + } + + &-menu { + @include scroll-shadow; + border-radius: inherit; + margin: 0; + padding: 0; + list-style-type: none; + max-height: var(--wdf-menu-max-height); + overflow-y: auto; + } + + &-menu-item { + display: flex; + flex-flow: row nowrap; + align-content: center; + align-items: center; + cursor: pointer; + user-select: none; + padding: var(--wdf-menu-item-padding); + height: fit-content; + overflow: hidden; + font-weight: normal; + color: var(--wdf-color); + + &:where([data-selected]) { + background-color: var(--wdf-selected-bg-color); + } + + &:where([data-highlighted]) { + background-color: var(--wdf-highlighted-bg-color); + } + } + + &-checkbox-slot { + display: flex; + margin-inline-end: var(--wdf-outer-spacing); + } + + &-input { + border: none; + flex: 1; + margin: 0; + min-width: 50px; + padding: 0; + } + + &-toggle, + &-clear { + background-color: transparent; + border: none; + } + + &-input, + &-toggle { + color: var(--wdf-color); + font-weight: normal; + overflow: hidden; + text-align: start; + text-overflow: ellipsis; + white-space: nowrap; + } + + &-clear { + @include btn-with-cross; + align-items: center; + align-self: center; + display: flex; + flex-shrink: 0; + justify-self: end; + margin-inline-end: var(--wdf-spacing); + padding: 3px 6px; + position: relative; + + &:has(+ #{$root}-state-icon), + &:has(+ #{$root}-toggle) { + border-inline-end: 1px solid var(--gray, #787d87); + } + } + + &-state-icon { + transition: transform 0.2s; + :where(#{$root}[data-expanded="true"]) & { + transform: rotate(180deg); + } + } + + &-input-container { + align-items: center; + display: flex; + flex: 1; + flex-flow: row wrap; + margin: 0; + min-width: 0; + overflow: hidden; + padding: 0; + position: relative; + } + + &-remove-icon { + cursor: pointer; + display: flex; + @include btn-with-cross; + } + + &-separator { + position: absolute; + margin-inline-end: var(--wdf-clear-margin); + background-color: var(--gray, #787d87); + justify-self: end; + inset-block: var(--wdf-button-spacing); + width: 1px; + } + + &-state-icon, + &-toggle { + align-items: center; + display: flex; + flex-shrink: 0; + justify-content: center; + padding-inline-end: 0; + padding-inline-start: 0; + } +} + +:where([data-highlighted]) #{$root}-checkbox:not(:checked)::after { + content: ""; + border-color: var(--form-input-bg-hover, #e7e7e9); +} + +/* Select variant */ +:where(#{$root}.variant-select) { + #{$root}-toggle { + display: block; + flex: 1 1 0; + justify-content: flex-start; + min-width: 0; + } + + #{$root}-state-icon { + align-self: center; + box-sizing: content-box; + justify-self: end; + pointer-events: none; + } + + #{$root}-input-container { + border: none; + background-color: transparent; + white-space: nowrap; + width: 100%; + } + + #{$root}-controls { + display: flex; + flex-shrink: 0; + align-items: center; + } +} + +:where(#{$root}.variant-select[data-empty]) { + --wdf-input-placeholder-color: rgb(117, 117, 117); + #{$root}-toggle { + color: var(--wdf-input-placeholder-color); + } +} + +/* Combobox variant */ +:where(#{$root}.variant-combobox) { + #{$root}-input { + border-radius: inherit; + padding-inline-start: 0; + padding-inline-end: 0; + } +} + +/* Tag Picker variant */ +:where(#{$root}.variant-tag-picker) { + #{$root}-selected-item { + align-items: center; + background-color: var(--color-primary-lighter, #e6eaff); + border-radius: 26px; + color: #000; + display: inline-flex; + flex-flow: row nowrap; + font-size: var(--font-size-small, 12px); + gap: 8px; + justify-content: center; + line-height: 1.334; + padding: var(--wdf-tag-padding); + &:focus-visible { + outline: var(--brand-primary, #264ae5) auto 1px; + } + } + + #{$root}-input { + flex-basis: 0; + min-width: 50px; + width: initial; + } + + #{$root}-clear { + border-color: transparent; + } +} + +/* Tag Picker variant text */ +:where(#{$root}.variant-tag-picker-text) { + #{$root}-selected-item { + background-color: transparent; + border-radius: 2px; + color: var(--wdf-color); + display: block; + overflow: hidden; + position: absolute; + bottom: 0; + left: 0; + right: 0; + top: 0; + text-overflow: ellipsis; + white-space: nowrap; + z-index: 0; + + &-hidden { + display: none; + } + + &:focus-visible { + outline: var(--brand-primary, #264ae5) solid 1px; + outline-offset: 2px; + } + } + + #{$root}-remove-icon { + padding: var(--wdf-spacing-tiny); + border-radius: 50%; + + path { + stroke-width: 1px; + } + } + + #{$root}-input { + background-color: transparent; + min-width: 75px; + opacity: 0; + width: 100%; + z-index: 1; + + &:focus, + &:not(:has(+ #{$root}-selected-item)) { + opacity: 1; + } + } +} diff --git a/Source/themesource/datawidgets/web/_datagrid-filters.scss b/Source/themesource/datawidgets/web/_datagrid-filters.scss index 58be0721..edba2595 100644 --- a/Source/themesource/datawidgets/web/_datagrid-filters.scss +++ b/Source/themesource/datawidgets/web/_datagrid-filters.scss @@ -60,55 +60,23 @@ $dg-item-min-height: 32px; padding-left: 4px; /* The font has spaces in the right side, so to align in the middle we need this */ } } - - .filter-selectors { - position: absolute; - width: max-content; - left: 0; - margin: 0 var(--spacing-small, $dg-spacing-small); - padding: 0; - background: var(--bg-color-secondary, $dg-background-color); - z-index: 102; - border-radius: 8px; - list-style-type: none; - box-shadow: 0 2px 20px 1px rgba(5, 15, 129, 0.05), 0 2px 16px 0 rgba(33, 43, 54, 0.08); - overflow: hidden; - z-index: 102; - - li { - display: flex; - align-items: center; - font-weight: normal; - line-height: 32px; - cursor: pointer; - - .filter-label { - padding-right: 8px; - } - - &.filter-selected { - background-color: var(--gray-lighter, $dg-hover-color); - color: var(--brand-primary, $dg-brand-primary); - } - - &:hover, - &:focus { - background-color: var(--gray-lighter, $dg-hover-color); - } - } - } } } .filter-selectors { + position: absolute; + width: max-content; + left: 0; padding: 0; + margin: 0; background: var(--bg-color-secondary, $dg-background-color); + z-index: 51; border-radius: 8px; list-style-type: none; box-shadow: 0 2px 20px 1px rgba(5, 15, 129, 0.05), 0 2px 16px 0 rgba(33, 43, 54, 0.08); overflow: hidden; - z-index: 102; + .filter-listitem, li { display: flex; align-items: center; @@ -126,7 +94,7 @@ $dg-item-min-height: 32px; } &:hover, - &:focus { + &.filter-highlighted { background-color: var(--gray-lighter, $dg-hover-color); } } diff --git a/Source/themesource/datawidgets/web/_datagrid-scroll.scss b/Source/themesource/datawidgets/web/_datagrid-scroll.scss deleted file mode 100644 index 911c85c7..00000000 --- a/Source/themesource/datawidgets/web/_datagrid-scroll.scss +++ /dev/null @@ -1,25 +0,0 @@ -.sticky-sentinel { - &.container-stuck { - & + .widget-datagrid-grid, - & + .table { - .th { - position: -webkit-sticky; /* Safari */ - position: sticky; - z-index: 50; - } - } - } -} - -.widget-datagrid-content.infinite-loading { - overflow-y: auto; - margin-bottom: 20px; -} - -.table { - .table-content { - &.infinite-loading { - overflow-y: scroll; - } - } -} diff --git a/Source/themesource/datawidgets/web/_datagrid.scss b/Source/themesource/datawidgets/web/_datagrid.scss index 346b6f87..c40d78d6 100644 --- a/Source/themesource/datawidgets/web/_datagrid.scss +++ b/Source/themesource/datawidgets/web/_datagrid.scss @@ -22,35 +22,34 @@ $dg-brand-light: #e6eaff; $dg-grid-selected-row-background: $dg-brand-light; $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2d2d2 100%); +$root: ".widget-datagrid"; + .table { position: relative; border-width: 0; background-color: var(--bg-color-secondary, $dg-background-color); - /* Table Content */ - .table-content { - display: grid; - position: relative; - } - /* Pseudo Row, to target this object please use .tr > .td or .tr > div */ .tr { display: contents; } /* Column Header */ - .th { - display: flex; - align-items: flex-start; - font-weight: 600; - background-color: var(--bg-color-secondary, $dg-background-color); - border-width: 0; - border-color: var(--grid-border-color, $dg-grid-border-color); - padding: var(--spacing-medium, $dg-spacing-medium); - top: 0; - min-width: 0; - position: relative; + @at-root { + :where(.widget-datagrid-grid .th) { + display: flex; + align-items: flex-start; + background-color: var(--bg-color-secondary, $dg-background-color); + border-width: 0; + border-color: var(--grid-border-color, $dg-grid-border-color); + padding: var(--spacing-medium, $dg-spacing-medium); + top: 0; + min-width: 0; + position: relative; + } + } + .th { &.dragging { opacity: 0.5; &.dragging-over-self { @@ -98,6 +97,7 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 padding: 0 4px; align-self: stretch; cursor: col-resize; + margin-right: -12px; &:hover .column-resizer-bar { background-color: var(--brand-primary, $dg-brand-primary); @@ -132,6 +132,7 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 margin: 1px 1px calc((-1 * var(--spacing-smaller, $dg-dragging-effect-size)) + 2px); display: flex; align-items: baseline; + font-weight: 600; span { min-width: 0; @@ -163,18 +164,9 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 .filter { display: flex; margin-top: 4px; - input:not([type="checkbox"]) { - font-weight: normal; - flex-grow: 1; - width: 100%; - } > .form-group { margin-bottom: 0; } - > .form-control { - flex: unset; - min-width: unset; - } } } @@ -231,6 +223,9 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 padding: 0 16px; background: var(--bg-color-secondary, $dg-background-color); z-index: 102; + overflow-y: auto; + width: fit-content; + max-width: 500px; border-radius: 3px; border: 1px solid transparent; list-style-type: none; @@ -246,6 +241,8 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 margin: 8px; font-weight: normal; white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; } } } @@ -323,6 +320,12 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 } } +:where(.table .th .filter input:not([type="checkbox"])) { + font-weight: normal; + flex-grow: 1; + width: 100%; +} + .pagination-bar { display: flex; justify-content: flex-end; @@ -378,6 +381,9 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 padding: 0 16px; background: var(--bg-color-secondary, $dg-background-color); z-index: 102; + overflow-y: auto; + width: fit-content; + max-width: 500px; border-radius: 3px; border: 1px solid transparent; list-style-type: none; @@ -385,11 +391,6 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 -moz-box-shadow: 0 2px 20px 1px rgba(32, 43, 54, 0.08); box-shadow: 0 2px 20px 1px rgba(32, 43, 54, 0.08); - &.overflow { - height: 250px; - overflow-y: scroll; - } - li { display: flex; align-items: center; @@ -399,13 +400,27 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 margin: 8px; font-weight: normal; white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; } } } -.widget-datagrid { +#{$root} { position: relative; + &-grid { + display: grid !important; + } + + &-grid-head { + display: contents; + } + + &-grid-body { + display: contents; + } + &.widget-datagrid-selection-method-click { .tr.tr-selected .td { background-color: $dg-grid-selected-row-background; @@ -434,16 +449,13 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 outline-offset: 0; } - &-content { - overflow-y: auto; - } - &-loader-container { align-items: center; background-color: rgba(255, 255, 255, 1); display: flex; height: 400px; justify-content: center; + grid-column: 1/-1; } &-skeleton, @@ -457,7 +469,9 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 } &-skeleton { - padding: 6px var(--dropdown-outer-padding, 10px); + padding: 2px var(--dropdown-outer-padding, 0); + overflow: hidden; + flex: 1; &-loader { animation: skeleton-loading 1s linear infinite alternate; @@ -465,7 +479,9 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 background-size: 300% 100%; border-radius: 4px; height: 16px; - width: 148px; + width: 100%; + min-width: 32px; + max-width: 148px; &-small { margin-right: 8px; @@ -516,6 +532,15 @@ $dg-skeleton-background: linear-gradient(90deg, rgba(194, 194, 194, 0.2) 0%, #d2 margin: 0 auto; } +:where(.widget-datagrid-grid.infinite-loading) { + overflow-y: auto; +} + +:where(.infinite-loading .widget-datagrid-grid-head .th) { + position: sticky; + z-index: 1; +} + @keyframes skeleton-loading { 0% { background-position: right; diff --git a/Source/themesource/datawidgets/web/main.scss b/Source/themesource/datawidgets/web/main.scss index dfcc61f9..19fbcb88 100644 --- a/Source/themesource/datawidgets/web/main.scss +++ b/Source/themesource/datawidgets/web/main.scss @@ -1,8 +1,8 @@ @import "../../../theme/web/custom-variables"; @import "datagrid"; @import "datagrid-filters"; +@import "datagrid-dropdown-filter"; @import "datagrid-design-properties"; -@import "datagrid-scroll"; @import "drop-down-sort"; @import "gallery"; @import "gallery-design-properties"; diff --git a/Source/themesource/unittesting/web/_filters.scss b/Source/themesource/unittesting/web/_filters.scss new file mode 100644 index 00000000..470f3ea7 --- /dev/null +++ b/Source/themesource/unittesting/web/_filters.scss @@ -0,0 +1,75 @@ +@import '../../../theme/web/custom-variables'; + +$filter-breakpoint: 1650px !default; + +.btn.mx-unit-test-filter-button, +.btn.mx-unit-test-filter-button:hover, +.btn.mx-unit-test-filter-button:active, +.btn.mx-unit-test-filter-button:focus { + background-color: transparent; + color: $font-color-default; + padding: $spacing-smaller $spacing-small; + + &.mx-unit-test-filter-button-default { + border-color: transparent; + } + + &.mx-unit-test-filter-button-default:hover { + border-color: $color-default-dark; + } + + &.mx-unit-test-filter-button-active { + &.btn-danger { + background-color: $color-danger-lighter; + } + + &.btn-success { + background-color: $color-success-lighter; + } + + &.btn-default { + background-color: $brand-default; + border-color: $color-default-dark; + } + } + + &.mx-unit-test-filter-button-active:hover { + &.btn-danger { + background-color: lighten($color-danger-lighter, 5%); + } + + &.btn-success { + background-color: lighten($color-success-lighter, 5%) + } + + &.btn-default { + background-color: lighten($brand-default, 5%); + } + } +} + +@media (max-width: $filter-breakpoint) { + .mx-unit-test-filter-container-minimal { + display: block; + } + + .mx-unit-test-filter-container-full, + .mx-unit-test-filter-text { + display: none; + } +} + +@media (min-width: $filter-breakpoint) { + .mx-unit-test-filter-container-minimal { + display: none; + } + + .mx-unit-test-filter-container-full, + .mx-unit-test-filter-text { + display: block; + } +} + +.mx-unit-test-filter-text.mx-text { + white-space: nowrap; +} diff --git a/Source/themesource/unittesting/web/_layout.scss b/Source/themesource/unittesting/web/_layout.scss new file mode 100644 index 00000000..185acbae --- /dev/null +++ b/Source/themesource/unittesting/web/_layout.scss @@ -0,0 +1,68 @@ +@import '../../../theme/web/custom-variables'; + +.mx-unit-test-master-detail { + > .row > div:first-child, + > .row > div:last-child { + overflow-x: hidden; + overflow-y: auto; + max-height: 100%; + } +} + +@media (max-width: $screen-sm-max) { + .mx-unit-test-master-detail { + > .row > div:first-child { + border-bottom: 1px $border-color-default solid; + padding-bottom: $spacing-small; + } + + > .row > div:last-child { + padding-top: $spacing-large; + } + } +} + +@media (min-width: $screen-md) { + .mx-unit-test-master-detail { + > .row > div:first-child { + border-right: 1px $border-color-default solid; + padding-right: $spacing-large; + } + + > .row > div:last-child { + padding-left: $spacing-large; + } + } + + .mx-unit-test-grid-full-height, + .mx-unit-test-grid-full-height > .row, + .mx-unit-test-grid-full-height > .row > div:first-child, + .mx-unit-test-grid-full-height > .row > div:first-child > .mx-dataview, + .mx-unit-test-grid-full-height > .row > div:first-child > .mx-dataview > .mx-dataview-content { + height: 100%; + } +} + +.mx-unit-test-detail-placeholder { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + color: $font-color-detail; +} + +.mx-unit-test-listview.mx-listview > ul > li { + background: transparent; + + .mx-dataview { + overflow: hidden; + } +} + +.mx-unit-test-default-container-gap { + gap: $spacing-smaller; +} + +.mx-unit-test-button-container-gap { + gap: $spacing-small; +} \ No newline at end of file diff --git a/Source/themesource/unittesting/web/_test-details.scss b/Source/themesource/unittesting/web/_test-details.scss new file mode 100644 index 00000000..8ad1dd60 --- /dev/null +++ b/Source/themesource/unittesting/web/_test-details.scss @@ -0,0 +1,51 @@ +@import '../../../theme/web/custom-variables'; + +.mx-unit-test-listview .mx-unit-test-icon { + @extend .mx-unit-test-icon-medium; +} + +.mx-unit-test-result-failed.widget-accordion { + .widget-accordion-group { + background-color: transparent; + border-color: transparent; + + > .widget-accordion-group-header > .widget-accordion-group-header-button, + > .widget-accordion-group-header > .widget-accordion-group-header-button.widget-accordion-group-header-button-clickable:hover, + > .widget-accordion-group-header > .widget-accordion-group-header-button.widget-accordion-group-header-button-clickable:focus { + background-color: $color-danger-lighter; + } + } +} + +.mx-test-details-layout-grid { + .row { + row-gap: 10px; + } + + .row > div:first-child { + flex-basis: 65%; + flex-grow: 1; + } +} + +.mx-unit-test-details-button-container { + display: flex; +} + +.mx-unit-test-header { + overflow: hidden; + text-overflow: ellipsis; +} + +.mx-unit-test-rollback-container { + display: flex; + align-items: center; + + .mx-text { + white-space: nowrap; + } +} + +.mx-unit-test-suite-result-text .mx-text { + white-space: nowrap; +} \ No newline at end of file diff --git a/Source/themesource/unittesting/web/_timeline.scss b/Source/themesource/unittesting/web/_timeline.scss new file mode 100644 index 00000000..83570644 --- /dev/null +++ b/Source/themesource/unittesting/web/_timeline.scss @@ -0,0 +1,108 @@ +@import '../../../theme/web/custom-variables'; + +$timeline-item-height: 80px !default; +$timeline-item-spacing: 60px !default; + +.mx-unit-test-timeline-item { + padding: $spacing-smaller 0 $spacing-smaller $timeline-item-spacing; + + &::before { + content: ""; + display: block; + position: absolute; + top: 0; + left: calc($timeline-item-spacing / 2); + height: 100%; + width: 0; + border-left: 1px $border-color-default solid; + } +} + +.mx-unit-test-timeline-listview > ul > li:first-child .mx-unit-test-timeline-item-static::before { + top: 50%; +} + +.mx-unit-test-timeline-listview > ul > li:first-child .mx-unit-test-timeline-item-expandable::before { + top: calc($timeline-item-height / 2); +} + +.mx-unit-test-timeline-listview > ul > li:last-child .mx-unit-test-timeline-item-static::before { + height: 50%; +} + +.mx-unit-test-timeline-listview > ul > li:last-child .mx-unit-test-timeline-item-expandable::before { + height: calc($timeline-item-height / 2); +} + +.mx-unit-test-timeline-listview > ul > li:first-child:last-child .mx-unit-test-timeline-item::before { + display: none; +} + +.mx-unit-test-timeline-circle { + width: 8px; + height: 8px; + border-radius: 50%; + background-color: $gray-dark; + position: absolute; + left: calc($timeline-item-spacing / 2 - 3.5px); +} + +.mx-unit-test-timeline-item-static .mx-unit-test-timeline-circle { + top: calc(50% - 4px); +} + +.mx-unit-test-timeline-item-expandable .mx-unit-test-timeline-circle { + top: calc($timeline-item-height / 2 - 4px + $spacing-smaller); +} + +.mx-unit-test-timeline-accordion.widget-accordion { + .widget-accordion-group:first-child, + .widget-accordion-group:last-child, + .widget-accordion-group > .widget-accordion-group-header > .widget-accordion-group-header-button { + background-color: transparent; + border-radius: 0; + min-height: $timeline-item-height; + } +} + +.mx-unit-test-timeline-static-content { + padding: $spacing-medium; + border: 1px $border-color-default solid; + min-height: $timeline-item-height; +} + +.mx-unit-test-stacktrace { + position: relative; + padding: $spacing-small; + padding-right: 30px; + border: 1px $border-color-default solid; + border-radius: 2px; +} + +.mx-unit-test-stacktrace-preview { + max-height: calc(3 * $font-size-default * $line-height-base); + overflow: hidden; + display: block; +} + +.mx-unit-test-stacktrace-full { + overflow-wrap: break-word; + overflow-y: scroll; +} + +.mx-unit-test-stacktrace-layoutgrid, +.mx-unit-test-stacktrace-layoutgrid * { + height: 100%; +} + +.mx-unit-test-stacktrace-copy-btn { + position: absolute; + top: 7px; + right: 7px; +} + +.mx-unit-test-stacktrace-copy-btn-popup { + position: absolute; + top: 7px; + right: 22px; +} \ No newline at end of file diff --git a/Source/themesource/unittesting/web/_tree-node.scss b/Source/themesource/unittesting/web/_tree-node.scss new file mode 100644 index 00000000..77754a99 --- /dev/null +++ b/Source/themesource/unittesting/web/_tree-node.scss @@ -0,0 +1,51 @@ +@import '../../../theme/web/custom-variables'; + +.mx-unit-test-tree-node { + margin-top: -$spacing-small; + margin-bottom: 0; + + &.widget-tree-node .widget-tree-node-branch-header { + padding: $spacing-smallest 0; + + .widget-tree-node-branch-header-value { + font-size: $font-size-default; + overflow: hidden; + } + } + + .mx-unit-test-tree-node-item { + padding: $spacing-small $spacing-smaller; + cursor: pointer; + + &::before { + content: ""; + display: block; + position: absolute; + top: 0; + left: -16px; // Based on icon width in tree node widget + height: 100%; + width: 0; + border-left: 1px $border-color-default solid; + } + + .mx-text { + white-space: nowrap; + } + } + + .mx-unit-test-tree-node-spacer { + min-width: $unit-test-icon-size; + } + + .mx-unit-test-tree-node-item-selected { + background-color: $grid-bg-selected; + } + + .mx-unit-test-tree-node-listview > ul { + margin: 0; + + > li { + padding-bottom: $spacing-smallest; + } + } +} \ No newline at end of file diff --git a/Source/themesource/unittesting/web/_util.scss b/Source/themesource/unittesting/web/_util.scss new file mode 100644 index 00000000..ca0efb72 --- /dev/null +++ b/Source/themesource/unittesting/web/_util.scss @@ -0,0 +1,34 @@ +@import '../../../theme/web/custom-variables'; + +.mx-unit-test-icon { + min-width: $unit-test-icon-size; + width: $unit-test-icon-size; +} + +.mx-unit-test-icon-medium { + min-width: $unit-test-icon-size-medium; + width: $unit-test-icon-size-medium; +} + +.mx-unit-test-icon-large { + min-width: $unit-test-icon-size-large; + width: $unit-test-icon-size-large; +} + +.mx-unit-test-align-right { + margin-left: auto; +} + +.mx-unit-test-single-line { + max-height: calc($font-size-default * $line-height-base); + overflow: hidden; +} + +.mx-unit-test-sticky-header { + position: sticky; + top: 0; + z-index: 1; + + background-color: $bg-color; + padding-bottom: $spacing-medium; +} \ No newline at end of file diff --git a/Source/themesource/unittesting/web/main.scss b/Source/themesource/unittesting/web/main.scss index 122370f7..e55cf6f1 100644 --- a/Source/themesource/unittesting/web/main.scss +++ b/Source/themesource/unittesting/web/main.scss @@ -1,2 +1,12 @@ @import '../../../theme/web/custom-variables'; +$unit-test-icon-size: calc($font-size-default + $spacing-smaller); +$unit-test-icon-size-medium: calc(1.5 * $font-size-default + $spacing-smaller); +$unit-test-icon-size-large: calc(2 * $font-size-default + $spacing-smaller); + +@import '_filters'; +@import '_layout'; +@import '_test-details'; +@import '_timeline'; +@import '_tree-node'; +@import '_util'; diff --git a/Source/themesource/workflowcommons/web/shared/_misc.scss b/Source/themesource/workflowcommons/web/shared/_misc.scss index b229b630..b821902c 100644 --- a/Source/themesource/workflowcommons/web/shared/_misc.scss +++ b/Source/themesource/workflowcommons/web/shared/_misc.scss @@ -90,4 +90,8 @@ text-decoration: none; cursor: default; } +} + +.mxwc-account-inactive.mx-link { + color: $brand-danger; } \ No newline at end of file diff --git a/Source/vendorlib/commons-io-2.11.0.jar b/Source/vendorlib/commons-io-2.11.0.jar deleted file mode 100644 index be507d94..00000000 Binary files a/Source/vendorlib/commons-io-2.11.0.jar and /dev/null differ diff --git a/Source/vendorlib/commons-io-2.17.0.jar b/Source/vendorlib/commons-io-2.17.0.jar new file mode 100644 index 00000000..ad00ddc4 Binary files /dev/null and b/Source/vendorlib/commons-io-2.17.0.jar differ diff --git a/Source/vendorlib/vendorlib-sbom.json b/Source/vendorlib/vendorlib-sbom.json index 10f6ee08..4eeddcac 100644 --- a/Source/vendorlib/vendorlib-sbom.json +++ b/Source/vendorlib/vendorlib-sbom.json @@ -7,56 +7,58 @@ { "vendor" : "CycloneDX", "name" : "cyclonedx-gradle-plugin", - "version" : "1.8.1" + "version" : "1.10.0" } ], "component" : { + "type" : "application", + "bom-ref" : "pkg:maven/com.mendix/temp@1.0.0?type=jar", "group" : "com.mendix", "name" : "temp", "version" : "1.0.0", - "purl" : "pkg:maven/com.mendix/temp@1.0.0?type=jar", - "type" : "application", - "bom-ref" : "pkg:maven/com.mendix/temp@1.0.0?type=jar" + "purl" : "pkg:maven/com.mendix/temp@1.0.0?type=jar" } }, "components" : [ { - "group" : "org.apache.httpcomponents.client5", - "name" : "httpclient5", - "version" : "5.2.1", - "description" : "Apache HttpComponents Client", + "type" : "library", + "bom-ref" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar", + "group" : "org.apache.httpcomponents.core5", + "name" : "httpcore5-h2", + "version" : "5.2", + "description" : "Apache HttpComponents HTTP/2 Core Components", "hashes" : [ { "alg" : "MD5", - "content" : "fbbefc687f2e0c55b34b77edf53d486a" + "content" : "272112133e0dd0559efdd8f5e615a344" }, { "alg" : "SHA-1", - "content" : "0c900514d3446d9ce5d9dbd90c21192048125440" + "content" : "698bd8c759ccc7fd7398f3179ff45d0e5a7ccc16" }, { "alg" : "SHA-256", - "content" : "9355f3876baf82fec13ced22c12b62d57536230836406d359459128e4f73ed51" + "content" : "5a087fb8c619979d492a83546f351ddadf32b28cc6a32923229f3fc777171578" }, { "alg" : "SHA-512", - "content" : "0f8cbc1b287f56af9565532aa6e16abbf8e14ce9e22d682eb155b24f9b36e3801306373b03cb9a3ad88963acff15138f949ec48ebe84491230a490a7c745b18b" + "content" : "3c8ebdbe931d014e390a2b42aeae1ec3ae0def07c54a0c18927d0db1afed978fd9730455602c7692393bba029b07bdd43356a5b779f5d79b285d9e36d0c448d1" }, { "alg" : "SHA-384", - "content" : "b828737744748cf6cf4d78f87f3c84bc90723eef7ad8ae68785504fb20389d08dbd4b13a66dddeb3a7d96adf5dd70d54" + "content" : "a1ab74afe0b503a3cf8eb3b060b6696a174aca2b55d728add196d46aaa5c9dce0d81de4e26e2e44482fbeb0cad197f63" }, { "alg" : "SHA3-384", - "content" : "8946c3ef57726352db0621b9f604c88b5065901285f547173d708b48420f3586c04f84d0dd6a86159e8b494d50561361" + "content" : "13fd21b5aaab5f9fc0d8ecbba20196a02dade84e992c4a686ef5c9a98c3366674d201e42f8555cef7042b1ba6d4ad256" }, { "alg" : "SHA3-256", - "content" : "6ab0c8554953cd7d42a9ca03659c8fb8a79be8979084847aea619044ea8dba35" + "content" : "62e29bad6d6c936fba13033ddc64153accd59dc964ed9f3dd7c1bd14212b834d" }, { "alg" : "SHA3-512", - "content" : "e8db6667d9b300c728b0ea4e693f09a49283e27362d123a17e860188b4f03d2c34f57b62ab714ead1202820748c28bae9af4cbe6c43876877573f173e27bdd10" + "content" : "3c891ebf18f05498d732eef4aacf607e0e526bb5d6a821e795601896d80dbf5244a36674f9688bdceff7f8965b8e893c88cc9deb662b7ac206b2c32b2b796e32" } ], "licenses" : [ @@ -66,48 +68,48 @@ } } ], - "purl" : "pkg:maven/org.apache.httpcomponents.client5/httpclient5@5.2.1?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/org.apache.httpcomponents.client5/httpclient5@5.2.1?type=jar" + "purl" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar", + "modified" : false }, { - "group" : "commons-io", - "name" : "commons-io", - "version" : "2.11.0", - "description" : "The Apache Commons IO library contains utility classes, stream implementations, file filters, file comparators, endian transformation classes, and much more.", + "type" : "library", + "bom-ref" : "pkg:maven/com.google.guava/listenablefuture@9999.0-empty-to-avoid-conflict-with-guava?type=jar", + "group" : "com.google.guava", + "name" : "listenablefuture", + "version" : "9999.0-empty-to-avoid-conflict-with-guava", + "description" : "An empty artifact that Guava depends on to signal that it is providing ListenableFuture -- but is also available in a second \"version\" that contains com.google.common.util.concurrent.ListenableFuture class, without any other Guava classes. The idea is: - If users want only ListenableFuture, they depend on listenablefuture-1.0. - If users want all of Guava, they depend on guava, which, as of Guava 27.0, depends on listenablefuture-9999.0-empty-to-avoid-conflict-with-guava. The 9999.0-... version number is enough for some build systems (notably, Gradle) to select that empty artifact over the \"real\" listenablefuture-1.0 -- avoiding a conflict with the copy of ListenableFuture in guava itself. If users are using an older version of Guava or a build system other than Gradle, they may see class conflicts. If so, they can solve them by manually excluding the listenablefuture artifact or manually forcing their build systems to use 9999.0-....", "hashes" : [ { "alg" : "MD5", - "content" : "3b4b7ccfaeceeac240b804839ee1a1ca" + "content" : "d094c22570d65e132c19cea5d352e381" }, { "alg" : "SHA-1", - "content" : "a2503f302b11ebde7ebc3df41daebe0e4eea3689" + "content" : "b421526c5f297295adef1c886e5246c39d4ac629" }, { "alg" : "SHA-256", - "content" : "961b2f6d87dbacc5d54abf45ab7a6e2495f89b75598962d8c723cea9bc210908" + "content" : "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" }, { "alg" : "SHA-512", - "content" : "5bd78eed456ede30119319c5bed8e3e4c443b6fd7bdb3a7a5686647bd83094d0c3e2832a7575cfb60e4ef25f08106b93476939d3adcfecf5533cc030b3039e10" + "content" : "c5987a979174cbacae2e78b319f080420cc71bcdbcf7893745731eeb93c23ed13bff8d4599441f373f3a246023d33df03e882de3015ee932a74a774afdd0782f" }, { "alg" : "SHA-384", - "content" : "114f1e324d90ad887c177876d410f5787a8e8da6c48d4b2862d365802c0efded3a88cb24046976bf6276cadad3712f0f" + "content" : "caff9b74079f95832ca7f6029346b34b606051cc8c5a4389fac263511d277ada0c55f28b0d43011055b268c6eb7184d5" }, { "alg" : "SHA3-384", - "content" : "80288c03ad4d80d69f91d056ffc5570d49a9c76bf54ad2dff0121ecde26a560df76d05156f281f5c6db2a38ff07a873d" + "content" : "e939f08df0545847ea0d3e4b04a114b08499ad069ba8ec9461d1779f87a56e0c37273630a0f4c14e78c348d3ac7eb97f" }, { "alg" : "SHA3-256", - "content" : "5adfb5ccaf5f21a549422f426118a9542673926fcd18c68390cf813e791dcf6c" + "content" : "1f0a8b1177773b3a8ace839df5eed63cbf56b24a38714898a6e4ed065c42559f" }, { "alg" : "SHA3-512", - "content" : "7573f47f0babb53cefdc7c2309a0b982d800139064537b0797da442853d081010ad7c3c74a500598a0f800639a5d540eca21963ea652c68613907059bd4278c2" + "content" : "6b495ecc2a18b17365cb08d124a0da47f04bcdde81927b5245edf3edd8e498c3c3fb92ce6a4127f660bac851bb1d3e4510e5c20d03be47ce99dc296d360db285" } ], "licenses" : [ @@ -117,57 +119,48 @@ } } ], - "purl" : "pkg:maven/commons-io/commons-io@2.11.0?type=jar", - "modified" : false, - "externalReferences" : [ - { - "type" : "issue-tracker", - "url" : "https://issues.apache.org/jira/browse/IO" - }, - { - "type" : "vcs", - "url" : "https://gitbox.apache.org/repos/asf?p=commons-io.git" - } - ], - "type" : "library", - "bom-ref" : "pkg:maven/commons-io/commons-io@2.11.0?type=jar" + "purl" : "pkg:maven/com.google.guava/listenablefuture@9999.0-empty-to-avoid-conflict-with-guava?type=jar", + "modified" : false }, { - "group" : "com.google.errorprone", - "name" : "error_prone_annotations", - "version" : "2.18.0", + "type" : "library", + "bom-ref" : "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar", + "group" : "com.google.guava", + "name" : "guava", + "version" : "32.0.1-jre", + "description" : "Guava is a suite of core and expanded libraries that include utility classes, Google's collections, I/O classes, and much more.", "hashes" : [ { "alg" : "MD5", - "content" : "64145d0e7fee5a69ed7b84cf402de998" + "content" : "6951895e804b36322214c95917e598d4" }, { "alg" : "SHA-1", - "content" : "89b684257096f548fa39a7df9fdaa409d4d4df91" + "content" : "6e5d51a72d142f2d40a57dfb897188b36a95b489" }, { "alg" : "SHA-256", - "content" : "9e6814cb71816988a4fd1b07a993a8f21bb7058d522c162b1de849e19bea54ae" + "content" : "bd7fa227591fb8509677d0d1122cf95158f3b8a9f45653f58281d879f6dc48c5" }, { "alg" : "SHA-512", - "content" : "3cea86be94bb8ae40d21ad4bf7d7f6b2233e89593b7b741ad84c78840cd3837bb5136f52e62fe9ae0953d7b190c46ad3edc102dfa97b4c7ea472a80206bf5db7" + "content" : "5dbe7a697511cfbe44f3ffb954e32e997677ecc61f03bb7bb374f1b8fa4a931a95cd9d1f5288eb5d42e2aa380e3241b35059786c07edc48e5aa67c30cddad8a5" }, { "alg" : "SHA-384", - "content" : "7622eb33f83f03ab32b710b36c2fe836e24c5318f65fb8c0631a99507ca3ae65c2df8e33b63a5ce853b9cab6d9cb32e5" + "content" : "abad4556e073fb38062c636b6599ceed992302c7d98150e3842d32ce92f6aac7d630633c56efa581523d591361fcf898" }, { "alg" : "SHA3-384", - "content" : "1ea52a5ce2a9ee1a960dc2a1bbe4b009d4d6a4448498e4cd76401605fa877662911e8c93b2b8bfda57bedc56c83f10a0" + "content" : "c7b02d77e04c567e8870674f71a60141e83ca9e5e9180138450ede78ad7f2be8b6636c514096e15ba2921c2889427852" }, { "alg" : "SHA3-256", - "content" : "ed53f4295da75753267f241315352c4a39e60796f04e1c0c12d29c3a38be48ed" + "content" : "17f18d8631c9bff9234c214522ce89eb1feef27a4dfe990760d4943ad3de710d" }, { "alg" : "SHA3-512", - "content" : "8266b313bd4e1170daf60642e838841370d99bc24b2a1f91825ca22037a6a30ff15cc76069f8e8770f1dc12772c277ee1320de67e815041697d93d6d7ba884fb" + "content" : "7cf7847812b47cc232ef3c27719457dd19610b3e3bb25c1be640821a3a2be67781047f41e34491b5c8ed68010bbb1d53c5f7706633f3a3f44f3f3133bb7635ec" } ], "licenses" : [ @@ -177,48 +170,48 @@ } } ], - "purl" : "pkg:maven/com.google.errorprone/error_prone_annotations@2.18.0?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/com.google.errorprone/error_prone_annotations@2.18.0?type=jar" + "purl" : "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar", + "modified" : false }, { - "group" : "org.apache.httpcomponents.core5", - "name" : "httpcore5", - "version" : "5.2", - "description" : "Apache HttpComponents HTTP/1.1 core components", + "type" : "library", + "bom-ref" : "pkg:maven/org.apache.httpcomponents.client5/httpclient5@5.2.1?type=jar", + "group" : "org.apache.httpcomponents.client5", + "name" : "httpclient5", + "version" : "5.2.1", + "description" : "Apache HttpComponents Client", "hashes" : [ { "alg" : "MD5", - "content" : "3a40241f9a99cf063f347dfb73c5c4e8" + "content" : "fbbefc687f2e0c55b34b77edf53d486a" }, { "alg" : "SHA-1", - "content" : "ab7d251b8dfa3f2878f1eefbcca0e1fc0ebeba27" + "content" : "0c900514d3446d9ce5d9dbd90c21192048125440" }, { "alg" : "SHA-256", - "content" : "293321cbf594d79ea8a0cb0214f75f146d17f088be17ad5ce11c2fe864df124c" + "content" : "9355f3876baf82fec13ced22c12b62d57536230836406d359459128e4f73ed51" }, { "alg" : "SHA-512", - "content" : "214dcc370a8ca0c7fdb7c7afdea37a0bf1b9ba838aa3e074d64b0d9b950ebc7ff1dae87892fad0f44cc6d56828101d640584b45358ace20076f19a78aa503300" + "content" : "0f8cbc1b287f56af9565532aa6e16abbf8e14ce9e22d682eb155b24f9b36e3801306373b03cb9a3ad88963acff15138f949ec48ebe84491230a490a7c745b18b" }, { "alg" : "SHA-384", - "content" : "af7cbc6d6ba74d974665529431a57de332c69cf5bd5080368015de28e7a9f652c2daa777e78bec68350c95d168ec2280" + "content" : "b828737744748cf6cf4d78f87f3c84bc90723eef7ad8ae68785504fb20389d08dbd4b13a66dddeb3a7d96adf5dd70d54" }, { "alg" : "SHA3-384", - "content" : "22dfb21741aef07351a10123e1531db56cac4b2a158fdcf27d6ebc937b9e23169926741c27b9dcec2a29acc866549f38" + "content" : "8946c3ef57726352db0621b9f604c88b5065901285f547173d708b48420f3586c04f84d0dd6a86159e8b494d50561361" }, { "alg" : "SHA3-256", - "content" : "3a97502a187ede8286a82c46af76cc8088e6b75de7f971a03ce0845ee5163ca6" + "content" : "6ab0c8554953cd7d42a9ca03659c8fb8a79be8979084847aea619044ea8dba35" }, { "alg" : "SHA3-512", - "content" : "9e814868255af14978947519b640d362f41bfddda6c9e47caf07e31403c2b0a64776e521d77b7df56a8970f173a509ec01e667b0863b11738b45ab6fadddfff1" + "content" : "e8db6667d9b300c728b0ea4e693f09a49283e27362d123a17e860188b4f03d2c34f57b62ab714ead1202820748c28bae9af4cbe6c43876877573f173e27bdd10" } ], "licenses" : [ @@ -228,48 +221,48 @@ } } ], - "purl" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar" + "purl" : "pkg:maven/org.apache.httpcomponents.client5/httpclient5@5.2.1?type=jar", + "modified" : false }, { - "group" : "commons-logging", - "name" : "commons-logging", - "version" : "1.2", - "description" : "Apache Commons Logging is a thin adapter allowing configurable bridging to other, well known logging systems.", + "type" : "library", + "bom-ref" : "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar", + "group" : "org.apache.pdfbox", + "name" : "fontbox", + "version" : "2.0.30", + "description" : "The Apache FontBox library is an open source Java tool to obtain low level information from font files. FontBox is a subproject of Apache PDFBox.", "hashes" : [ { "alg" : "MD5", - "content" : "040b4b4d8eac886f6b4a2a3bd2f31b00" + "content" : "3a7b597c9dbd56e18455e6efca52cbb3" }, { "alg" : "SHA-1", - "content" : "4bfc12adfe4842bf07b657f0369c4cb522955686" + "content" : "555e5d59a4d83c95c4330f018a6c32861880b6df" }, { "alg" : "SHA-256", - "content" : "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636" + "content" : "aae7518f9c17d347531e63b22a46de582cb78f7e45d079a78a79dc9bdb23f8ba" }, { "alg" : "SHA-512", - "content" : "ed00dbfabd9ae00efa26dd400983601d076fe36408b7d6520084b447e5d1fa527ce65bd6afdcb58506c3a808323d28e88f26cb99c6f5db9ff64f6525ecdfa557" + "content" : "61eb46fee25826a8b0750fbe3823504e043f7e809f6ac3d144a1ba773195de29ebcffe30faee1bc9d2db50c94c45ebf65b67eb19e3358dbabf7878d36f133396" }, { "alg" : "SHA-384", - "content" : "ac20720d7156131478205f1b454395abf84cfc8da2f163301af32f63bd3c4764bd26cb54ed53800f33193ae591f3ce9c" + "content" : "ca4ccf8281e1b481f83b8e156a3c2cfab0590f3d0a0a19f9cf80997966170affb01da293bacb880ae70ff8e6f54deb0e" }, { "alg" : "SHA3-384", - "content" : "628eb4407e95dca84da1a06b08a6d9b832a49de8472b1b217e8607f08efeeed18b996232d64dd07f03e78e0e3bb4b078" + "content" : "184a9a72f221f34fb98b9d5e132b74b18bab569b8f6e86a5e1e7b88e5d6f82095607809e2cd98620f43cdbd3efd0b277" }, { "alg" : "SHA3-256", - "content" : "9aab62deccf156ee6e324c925dfc30ecb53e8465802863a551901a461424e807" + "content" : "1c1333b59673e8caf3db1fc6453ce9c799b133faaee9017c2860a03257107325" }, { "alg" : "SHA3-512", - "content" : "3fd76857f6d20c03799537cc961c1c4ddf1c375c6c192fb982363e3b9397ba138b77f24ef38b4202f44e37586789c0320e4de18fdadd2772304fd14a9b26d552" + "content" : "4b018c517e51185debe39adc9237728b6a189cbfc8053bc8401fa2c115f2a40c1e242b5ce1ebf0339480bc332bd4681e9a3dcbb1c4c5bc8d7fca16f202e3ef5b" } ], "licenses" : [ @@ -279,58 +272,99 @@ } } ], - "purl" : "pkg:maven/commons-logging/commons-logging@1.2?type=jar", - "modified" : false, - "externalReferences" : [ + "purl" : "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar", + "modified" : false + }, + { + "type" : "library", + "bom-ref" : "pkg:maven/com.google.guava/failureaccess@1.0.1?type=jar", + "group" : "com.google.guava", + "name" : "failureaccess", + "version" : "1.0.1", + "description" : "Contains com.google.common.util.concurrent.internal.InternalFutureFailureAccess and InternalFutures. Most users will never need to use this artifact. Its classes is conceptually a part of Guava, but they're in this separate artifact so that Android libraries can use them without pulling in all of Guava (just as they can use ListenableFuture by depending on the listenablefuture artifact).", + "hashes" : [ { - "type" : "issue-tracker", - "url" : "http://issues.apache.org/jira/browse/LOGGING" + "alg" : "MD5", + "content" : "091883993ef5bfa91da01dcc8fc52236" }, { - "type" : "vcs", - "url" : "http://svn.apache.org/repos/asf/commons/proper/logging/trunk" + "alg" : "SHA-1", + "content" : "1dcf1de382a0bf95a3d8b0849546c88bac1292c9" + }, + { + "alg" : "SHA-256", + "content" : "a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26" + }, + { + "alg" : "SHA-512", + "content" : "f8d59b808d6ba617252305b66d5590937da9b2b843d492d06b8d0b1b1f397e39f360d5817707797b979a5bf20bf21987b35333e7a15c44ed7401fea2d2119cae" + }, + { + "alg" : "SHA-384", + "content" : "67659dbd9647ec303d7f15128dc9dba19b98fd8d74758ee3b602451e32c855e236ccaafe08edf4bbfa245f981268440f" + }, + { + "alg" : "SHA3-384", + "content" : "1460875f0331c5fa3791772a6a322a7db180261bc2adacf7271df1fbf3b088a587a755a604c039982cb593c5cfc1f101" + }, + { + "alg" : "SHA3-256", + "content" : "ea86406e75fcd93eafe3cde1b3135ba485f1bb9b75fed98894a0bf1f0aee04f0" + }, + { + "alg" : "SHA3-512", + "content" : "52ac0f487ab5dd27c9f2e54fd1d84c7a620cae9d49be4072aa2b11501787bf4391ddaa13d02eccdf19e8eea46aecbea5f6064b26777c1b836108a280652e04ac" } ], - "type" : "library", - "bom-ref" : "pkg:maven/commons-logging/commons-logging@1.2?type=jar" + "licenses" : [ + { + "license" : { + "id" : "Apache-2.0" + } + } + ], + "purl" : "pkg:maven/com.google.guava/failureaccess@1.0.1?type=jar", + "modified" : false }, { - "group" : "com.google.guava", - "name" : "guava", - "version" : "32.0.1-jre", - "description" : "Guava is a suite of core and expanded libraries that include utility classes, Google's collections, I/O classes, and much more.", + "type" : "library", + "bom-ref" : "pkg:maven/org.apache.pdfbox/pdfbox@2.0.30?type=jar", + "group" : "org.apache.pdfbox", + "name" : "pdfbox", + "version" : "2.0.30", + "description" : "The Apache PDFBox library is an open source Java tool for working with PDF documents.", "hashes" : [ { "alg" : "MD5", - "content" : "6951895e804b36322214c95917e598d4" + "content" : "da9a5490ecf28832ee6d003f9bcd95bd" }, { "alg" : "SHA-1", - "content" : "6e5d51a72d142f2d40a57dfb897188b36a95b489" + "content" : "730753a91f7f2c574eb09a8af7288065d1e551bd" }, { "alg" : "SHA-256", - "content" : "bd7fa227591fb8509677d0d1122cf95158f3b8a9f45653f58281d879f6dc48c5" + "content" : "abb468d07abe76e34efb3337d1cfd48e365241623320e277e8341ce3cd670760" }, { "alg" : "SHA-512", - "content" : "5dbe7a697511cfbe44f3ffb954e32e997677ecc61f03bb7bb374f1b8fa4a931a95cd9d1f5288eb5d42e2aa380e3241b35059786c07edc48e5aa67c30cddad8a5" + "content" : "3727ede4a890c7c5c23e048fa037e013e8a3c85fcbe014e239c8c4dc7044a45b1143c4d773973f4f78032fb98d427486dd38f79f22dd6fb62dd713fee82e754f" }, { "alg" : "SHA-384", - "content" : "abad4556e073fb38062c636b6599ceed992302c7d98150e3842d32ce92f6aac7d630633c56efa581523d591361fcf898" + "content" : "d191b697ea322c23fe8a142fae04b8d84eb67d9852af5f7d89caf85db4c6573eafc830093f51edaa1622e6330090e860" }, { "alg" : "SHA3-384", - "content" : "c7b02d77e04c567e8870674f71a60141e83ca9e5e9180138450ede78ad7f2be8b6636c514096e15ba2921c2889427852" + "content" : "ba9f6d207a618edf1f9d496731538f2e774ce1238fb8252665cb1efedd4d17c85e319663cf2b8c9bd415ee17ea926bda" }, { "alg" : "SHA3-256", - "content" : "17f18d8631c9bff9234c214522ce89eb1feef27a4dfe990760d4943ad3de710d" + "content" : "9b62e73a41d0f73b805918bbc2c9da4c60e86d454366bf9ae56917264fc8d085" }, { "alg" : "SHA3-512", - "content" : "7cf7847812b47cc232ef3c27719457dd19610b3e3bb25c1be640821a3a2be67781047f41e34491b5c8ed68010bbb1d53c5f7706633f3a3f44f3f3133bb7635ec" + "content" : "41f714619824293519067fd3ba3e7295595f447778e60b21209bd09a46222af0d8492d7cc6a72e1d16012d727402c9e3a1767959be788c5e3a49ad537f3bf3ad" } ], "licenses" : [ @@ -340,63 +374,74 @@ } } ], - "purl" : "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar" + "purl" : "pkg:maven/org.apache.pdfbox/pdfbox@2.0.30?type=jar", + "modified" : false }, { - "group" : "com.google.guava", - "name" : "listenablefuture", - "version" : "9999.0-empty-to-avoid-conflict-with-guava", - "description" : "An empty artifact that Guava depends on to signal that it is providing ListenableFuture -- but is also available in a second \"version\" that contains com.google.common.util.concurrent.ListenableFuture class, without any other Guava classes. The idea is: - If users want only ListenableFuture, they depend on listenablefuture-1.0. - If users want all of Guava, they depend on guava, which, as of Guava 27.0, depends on listenablefuture-9999.0-empty-to-avoid-conflict-with-guava. The 9999.0-... version number is enough for some build systems (notably, Gradle) to select that empty artifact over the \"real\" listenablefuture-1.0 -- avoiding a conflict with the copy of ListenableFuture in guava itself. If users are using an older version of Guava or a build system other than Gradle, they may see class conflicts. If so, they can solve them by manually excluding the listenablefuture artifact or manually forcing their build systems to use 9999.0-....", + "type" : "library", + "bom-ref" : "pkg:maven/commons-io/commons-io@2.17.0?type=jar", + "group" : "commons-io", + "name" : "commons-io", + "version" : "2.17.0", + "description" : "The Apache Commons IO library contains utility classes, stream implementations, file filters, file comparators, endian transformation classes, and much more.", "hashes" : [ { "alg" : "MD5", - "content" : "d094c22570d65e132c19cea5d352e381" + "content" : "f6232d0e290d58bb93f74f67165bf91f" }, { "alg" : "SHA-1", - "content" : "b421526c5f297295adef1c886e5246c39d4ac629" + "content" : "ddcc8433eb019fb48fe25207c0278143f3e1d7e2" }, { "alg" : "SHA-256", - "content" : "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" + "content" : "4aa4ca48f3dfd30b78220b7881d8cb93eac4093ec94361b6befa9487998a550b" }, { "alg" : "SHA-512", - "content" : "c5987a979174cbacae2e78b319f080420cc71bcdbcf7893745731eeb93c23ed13bff8d4599441f373f3a246023d33df03e882de3015ee932a74a774afdd0782f" + "content" : "98bc665c16268ff1074f415f493ba66d214ac23665b6e964086b60d523b35b1b03fd2e79211e84aa8ebf0921ea028f992827e4642fd086d7104a408b454d38ce" }, { "alg" : "SHA-384", - "content" : "caff9b74079f95832ca7f6029346b34b606051cc8c5a4389fac263511d277ada0c55f28b0d43011055b268c6eb7184d5" + "content" : "4dabc3cd47eec79ae537e48739f9abbc64e9b75f63809f35f062d54b8d737de0ba282d7d35a236940b9152e1c54f5918" }, { "alg" : "SHA3-384", - "content" : "e939f08df0545847ea0d3e4b04a114b08499ad069ba8ec9461d1779f87a56e0c37273630a0f4c14e78c348d3ac7eb97f" + "content" : "fb7a6dec31b6170f729143103c47fead49d50b0d9f58c42ec55a593b23d30c4c43114579790f1e43adfc598f684d4493" }, { "alg" : "SHA3-256", - "content" : "1f0a8b1177773b3a8ace839df5eed63cbf56b24a38714898a6e4ed065c42559f" + "content" : "bafc20a1433479b07bd526655f244eee5fe1c99cbf75a0ac27e82237f9c6589b" }, { "alg" : "SHA3-512", - "content" : "6b495ecc2a18b17365cb08d124a0da47f04bcdde81927b5245edf3edd8e498c3c3fb92ce6a4127f660bac851bb1d3e4510e5c20d03be47ce99dc296d360db285" + "content" : "47d71f864268c8ced739b8a78a906fdc9777ed0eae3b56218a8d4e19d1787564ab39edf6034b08700c12cfca47edf505551e6352163a9bb50a93279890e241e1" } ], "licenses" : [ { "license" : { - "id" : "Apache-2.0" + "id" : "Apache-2.0", + "url" : "https://www.apache.org/licenses/LICENSE-2.0" } } ], - "purl" : "pkg:maven/com.google.guava/listenablefuture@9999.0-empty-to-avoid-conflict-with-guava?type=jar", + "purl" : "pkg:maven/commons-io/commons-io@2.17.0?type=jar", "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/com.google.guava/listenablefuture@9999.0-empty-to-avoid-conflict-with-guava?type=jar" + "externalReferences" : [ + { + "type" : "issue-tracker", + "url" : "https://issues.apache.org/jira/browse/IO" + }, + { + "type" : "vcs", + "url" : "https://gitbox.apache.org/repos/asf?p=commons-io.git" + } + ] }, { + "type" : "library", + "bom-ref" : "pkg:maven/junit/junit@4.13.1?type=jar", "publisher" : "JUnit", "group" : "junit", "name" : "junit", @@ -467,104 +512,99 @@ "type" : "vcs", "url" : "https://github.com/junit-team/junit4" } - ], - "type" : "library", - "bom-ref" : "pkg:maven/junit/junit@4.13.1?type=jar" + ] }, { - "group" : "com.google.code.findbugs", - "name" : "jsr305", - "version" : "3.0.2", - "description" : "JSR305 Annotations for Findbugs", + "type" : "library", + "bom-ref" : "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar", + "group" : "org.slf4j", + "name" : "slf4j-api", + "version" : "2.0.9", + "description" : "The slf4j API", "hashes" : [ { "alg" : "MD5", - "content" : "dd83accb899363c32b07d7a1b2e4ce40" + "content" : "45630e54b0f0ac2b3c80462515ad8fda" }, { "alg" : "SHA-1", - "content" : "25ea2e8b0c338a877313bd4672d3fe056ea78f0d" + "content" : "7cf2726fdcfbc8610f9a71fb3ed639871f315340" }, { "alg" : "SHA-256", - "content" : "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" + "content" : "0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c" }, { "alg" : "SHA-512", - "content" : "bb09db62919a50fa5b55906013be6ca4fc7acb2e87455fac5eaf9ede2e41ce8bbafc0e5a385a561264ea4cd71bbbd3ef5a45e02d63277a201d06a0ae1636f804" + "content" : "069e6ddce79617e37d61758120c7e68348ee62f255781948937f7bec3058e46244026d7f6a11e90fbc15cd4288c4bb1acee4f242af521c721a9e68a05e64d526" }, { "alg" : "SHA-384", - "content" : "ca0b169d3eb2d0922dc031133a021f861a043bb3e405a88728215fd6ff00fa52fdc7347842dcc2031472e3726164bdc4" + "content" : "fd6f7ad85d02ac63cd1a586c8bb158c1fc000495f512f097731ea9f749b5da2637615b821294962805ba312c738f40aa" }, { "alg" : "SHA3-384", - "content" : "9903fd7505218999f8262efedb3d935d64bcef84aae781064ab5e1b24755466b269517cada562fa140cd1d417ede57a1" + "content" : "17cd61f59a162250b52a89c7c56eb60da253b776210500313c7b82744483ff84717946f969251fb4d76f9bb12a2458fe" }, { "alg" : "SHA3-256", - "content" : "223fda9a89a461afaae73b177a2dc20ed4a90f2f8757f5c65f3241b0510f00ff" + "content" : "9dcb04582c64c79e788f9191195834ec75bb3457133d22a176a0ccb069b97103" }, { "alg" : "SHA3-512", - "content" : "3996b5af57a5d5c6a0cd62b11773360fb051dd86a2ba968476806a2a5d32049b82d69a24a3c694e8fe4d735be6a28e41000cc500cc2a9fb577e058045855d2d6" + "content" : "990faffa454598a3fa82affe30f1323db769d2e1fff20d9c7163ef6fd95ac7a0874c06a634207a2eaed9e5afbdee68b225138fc75018717ba97efe3ffe92c88a" } ], "licenses" : [ { "license" : { - "id" : "Apache-2.0" + "id" : "MIT", + "url" : "https://opensource.org/license/mit/" } } ], - "purl" : "pkg:maven/com.google.code.findbugs/jsr305@3.0.2?type=jar", - "modified" : false, - "externalReferences" : [ - { - "type" : "vcs", - "url" : "https://code.google.com/p/jsr-305/" - } - ], - "type" : "library", - "bom-ref" : "pkg:maven/com.google.code.findbugs/jsr305@3.0.2?type=jar" + "purl" : "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar", + "modified" : false }, { - "group" : "org.apache.httpcomponents.core5", - "name" : "httpcore5-h2", - "version" : "5.2", - "description" : "Apache HttpComponents HTTP/2 Core Components", + "type" : "library", + "bom-ref" : "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar", + "group" : "org.apache.commons", + "name" : "commons-lang3", + "version" : "3.12.0", + "description" : "Apache Commons Lang, a package of Java utility classes for the classes that are in java.lang's hierarchy, or are considered to be so standard as to justify existence in java.lang.", "hashes" : [ { "alg" : "MD5", - "content" : "272112133e0dd0559efdd8f5e615a344" + "content" : "19fe50567358922bdad277959ea69545" }, { "alg" : "SHA-1", - "content" : "698bd8c759ccc7fd7398f3179ff45d0e5a7ccc16" + "content" : "c6842c86792ff03b9f1d1fe2aab8dc23aa6c6f0e" }, { "alg" : "SHA-256", - "content" : "5a087fb8c619979d492a83546f351ddadf32b28cc6a32923229f3fc777171578" + "content" : "d919d904486c037f8d193412da0c92e22a9fa24230b9d67a57855c5c31c7e94e" }, { "alg" : "SHA-512", - "content" : "3c8ebdbe931d014e390a2b42aeae1ec3ae0def07c54a0c18927d0db1afed978fd9730455602c7692393bba029b07bdd43356a5b779f5d79b285d9e36d0c448d1" + "content" : "fbdbc0943cb3498b0148e86a39b773f97c8e6013740f72dbc727faeabea402073e2cc8c4d68198e5fc6b08a13b7700236292e99d4785f2c9989f2e5fac11fd81" }, { "alg" : "SHA-384", - "content" : "a1ab74afe0b503a3cf8eb3b060b6696a174aca2b55d728add196d46aaa5c9dce0d81de4e26e2e44482fbeb0cad197f63" + "content" : "c34b8a0e0eba2168ad56fedeb7a1d710b6f1d3f1ce6aae99a4e0247bd120efbbadc8dcb2f731045b8a16e3efd30604dc" }, { "alg" : "SHA3-384", - "content" : "13fd21b5aaab5f9fc0d8ecbba20196a02dade84e992c4a686ef5c9a98c3366674d201e42f8555cef7042b1ba6d4ad256" + "content" : "8ad6ebe7754bf0caa8cda7e59c0e95360d76e06a7ad6aeec5637985519dbd1dd06e7eed04711039f36ec4c49de280def" }, { "alg" : "SHA3-256", - "content" : "62e29bad6d6c936fba13033ddc64153accd59dc964ed9f3dd7c1bd14212b834d" + "content" : "18ef639b2aeeb5aedffb18dbf20c79f33e300d99fb31b131689639cc470e6e4c" }, { "alg" : "SHA3-512", - "content" : "3c891ebf18f05498d732eef4aacf607e0e526bb5d6a821e795601896d80dbf5244a36674f9688bdceff7f8965b8e893c88cc9deb662b7ac206b2c32b2b796e32" + "content" : "fbea96114dcf4f31cfaaa99987be756ddda3a6c74f8c835461997df794d54b92da1f60fe5c3f1f2a43cb8c5f5db7f4048bef77c70993673c7a93f3660fffc8da" } ], "licenses" : [ @@ -574,48 +614,58 @@ } } ], - "purl" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar", + "purl" : "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar", "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar" + "externalReferences" : [ + { + "type" : "issue-tracker", + "url" : "https://issues.apache.org/jira/browse/LANG" + }, + { + "type" : "vcs", + "url" : "https://gitbox.apache.org/repos/asf?p=commons-lang.git" + } + ] }, { - "group" : "com.googlecode.owasp-java-html-sanitizer", - "name" : "owasp-java-html-sanitizer", - "version" : "20211018.2", - "description" : "Takes third-party HTML and produces HTML that is safe to embed in your web application. Fast and easy to configure.", + "type" : "library", + "bom-ref" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar", + "group" : "org.apache.httpcomponents.core5", + "name" : "httpcore5", + "version" : "5.2", + "description" : "Apache HttpComponents HTTP/1.1 core components", "hashes" : [ { "alg" : "MD5", - "content" : "5b0008f2b94e1d3100de8d3cdcb670cb" + "content" : "3a40241f9a99cf063f347dfb73c5c4e8" }, { "alg" : "SHA-1", - "content" : "a3226c13cf72633122e94810a53e60529dae2b80" + "content" : "ab7d251b8dfa3f2878f1eefbcca0e1fc0ebeba27" }, { "alg" : "SHA-256", - "content" : "48234cd74e35d91a31a683820a35b5b6d11b55527f32a5b162c6757408b95d7a" + "content" : "293321cbf594d79ea8a0cb0214f75f146d17f088be17ad5ce11c2fe864df124c" }, { "alg" : "SHA-512", - "content" : "2aa772e369e93ae10fff441e063f0439ab36d87803dfcd76b492dbe61848c2b976649a921b9518c6dff9e8751dc9bff0802e1ef793d8cdb232f8e0da77e34732" + "content" : "214dcc370a8ca0c7fdb7c7afdea37a0bf1b9ba838aa3e074d64b0d9b950ebc7ff1dae87892fad0f44cc6d56828101d640584b45358ace20076f19a78aa503300" }, { "alg" : "SHA-384", - "content" : "0caedafcf42e8a2e6a7a10665f48c9ae5cdbb586bbd5337bd63600a91362ec329c12558ce4d967f42ea7d7c83769e69f" + "content" : "af7cbc6d6ba74d974665529431a57de332c69cf5bd5080368015de28e7a9f652c2daa777e78bec68350c95d168ec2280" }, { "alg" : "SHA3-384", - "content" : "aae645eb112a6d5bce213a766a6cf76df828545df07438340b007e9eb8db546e62b2a01d94385daea86bfb7b1952c34a" + "content" : "22dfb21741aef07351a10123e1531db56cac4b2a158fdcf27d6ebc937b9e23169926741c27b9dcec2a29acc866549f38" }, { "alg" : "SHA3-256", - "content" : "c805dca696ff5b10f8c21fca1e99c0771d3778507888ab7da4aa939a6c770e61" + "content" : "3a97502a187ede8286a82c46af76cc8088e6b75de7f971a03ce0845ee5163ca6" }, { "alg" : "SHA3-512", - "content" : "851caf550ca3f5cf9ff38c0961d18c60e752df41b6a8a28a8c856ea8e421cc9de7090155f688cffc889b576aa4ff0558b1138b1810ed25b135c1f68509c8be7f" + "content" : "9e814868255af14978947519b640d362f41bfddda6c9e47caf07e31403c2b0a64776e521d77b7df56a8970f173a509ec01e667b0863b11738b45ab6fadddfff1" } ], "licenses" : [ @@ -625,48 +675,47 @@ } } ], - "purl" : "pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20211018.2?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20211018.2?type=jar" + "purl" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar", + "modified" : false }, { - "group" : "org.apache.commons", - "name" : "commons-lang3", - "version" : "3.12.0", - "description" : "Apache Commons Lang, a package of Java utility classes for the classes that are in java.lang's hierarchy, or are considered to be so standard as to justify existence in java.lang.", + "type" : "library", + "bom-ref" : "pkg:maven/com.google.errorprone/error_prone_annotations@2.18.0?type=jar", + "group" : "com.google.errorprone", + "name" : "error_prone_annotations", + "version" : "2.18.0", "hashes" : [ { "alg" : "MD5", - "content" : "19fe50567358922bdad277959ea69545" + "content" : "64145d0e7fee5a69ed7b84cf402de998" }, { "alg" : "SHA-1", - "content" : "c6842c86792ff03b9f1d1fe2aab8dc23aa6c6f0e" + "content" : "89b684257096f548fa39a7df9fdaa409d4d4df91" }, { "alg" : "SHA-256", - "content" : "d919d904486c037f8d193412da0c92e22a9fa24230b9d67a57855c5c31c7e94e" + "content" : "9e6814cb71816988a4fd1b07a993a8f21bb7058d522c162b1de849e19bea54ae" }, { "alg" : "SHA-512", - "content" : "fbdbc0943cb3498b0148e86a39b773f97c8e6013740f72dbc727faeabea402073e2cc8c4d68198e5fc6b08a13b7700236292e99d4785f2c9989f2e5fac11fd81" + "content" : "3cea86be94bb8ae40d21ad4bf7d7f6b2233e89593b7b741ad84c78840cd3837bb5136f52e62fe9ae0953d7b190c46ad3edc102dfa97b4c7ea472a80206bf5db7" }, { "alg" : "SHA-384", - "content" : "c34b8a0e0eba2168ad56fedeb7a1d710b6f1d3f1ce6aae99a4e0247bd120efbbadc8dcb2f731045b8a16e3efd30604dc" + "content" : "7622eb33f83f03ab32b710b36c2fe836e24c5318f65fb8c0631a99507ca3ae65c2df8e33b63a5ce853b9cab6d9cb32e5" }, { "alg" : "SHA3-384", - "content" : "8ad6ebe7754bf0caa8cda7e59c0e95360d76e06a7ad6aeec5637985519dbd1dd06e7eed04711039f36ec4c49de280def" + "content" : "1ea52a5ce2a9ee1a960dc2a1bbe4b009d4d6a4448498e4cd76401605fa877662911e8c93b2b8bfda57bedc56c83f10a0" }, { "alg" : "SHA3-256", - "content" : "18ef639b2aeeb5aedffb18dbf20c79f33e300d99fb31b131689639cc470e6e4c" + "content" : "ed53f4295da75753267f241315352c4a39e60796f04e1c0c12d29c3a38be48ed" }, { "alg" : "SHA3-512", - "content" : "fbea96114dcf4f31cfaaa99987be756ddda3a6c74f8c835461997df794d54b92da1f60fe5c3f1f2a43cb8c5f5db7f4048bef77c70993673c7a93f3660fffc8da" + "content" : "8266b313bd4e1170daf60642e838841370d99bc24b2a1f91825ca22037a6a30ff15cc76069f8e8770f1dc12772c277ee1320de67e815041697d93d6d7ba884fb" } ], "licenses" : [ @@ -676,130 +725,120 @@ } } ], - "purl" : "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar", - "modified" : false, - "externalReferences" : [ - { - "type" : "issue-tracker", - "url" : "https://issues.apache.org/jira/browse/LANG" - }, - { - "type" : "vcs", - "url" : "https://gitbox.apache.org/repos/asf?p=commons-lang.git" - } - ], - "type" : "library", - "bom-ref" : "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar" + "purl" : "pkg:maven/com.google.errorprone/error_prone_annotations@2.18.0?type=jar", + "modified" : false }, { - "group" : "org.checkerframework", - "name" : "checker-qual", - "version" : "3.33.0", - "description" : "checker-qual contains annotations (type qualifiers) that a programmer writes to specify Java code for type-checking by the Checker Framework.", + "type" : "library", + "bom-ref" : "pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20211018.2?type=jar", + "group" : "com.googlecode.owasp-java-html-sanitizer", + "name" : "owasp-java-html-sanitizer", + "version" : "20211018.2", + "description" : "Takes third-party HTML and produces HTML that is safe to embed in your web application. Fast and easy to configure.", "hashes" : [ { "alg" : "MD5", - "content" : "fc9418b779d9d57dcd52197006cbdb9b" + "content" : "5b0008f2b94e1d3100de8d3cdcb670cb" }, { "alg" : "SHA-1", - "content" : "de2b60b62da487644fc11f734e73c8b0b431238f" + "content" : "a3226c13cf72633122e94810a53e60529dae2b80" }, { "alg" : "SHA-256", - "content" : "e316255bbfcd9fe50d165314b85abb2b33cb2a66a93c491db648e498a82c2de1" + "content" : "48234cd74e35d91a31a683820a35b5b6d11b55527f32a5b162c6757408b95d7a" }, { "alg" : "SHA-512", - "content" : "049c446677b7b386f3fb501bf65e032bdf2b1b29a3f545848035fff2b683cd275380cf302e30eea641af7f0801f779bcda3d82a71d928e4176f564f796640a64" + "content" : "2aa772e369e93ae10fff441e063f0439ab36d87803dfcd76b492dbe61848c2b976649a921b9518c6dff9e8751dc9bff0802e1ef793d8cdb232f8e0da77e34732" }, { "alg" : "SHA-384", - "content" : "ddf7a0f70421d1ed75e93c0a30434a4862c3905e433223e19861323cf0994e843392b746003040f10a7db6fc960b8aa6" + "content" : "0caedafcf42e8a2e6a7a10665f48c9ae5cdbb586bbd5337bd63600a91362ec329c12558ce4d967f42ea7d7c83769e69f" }, { "alg" : "SHA3-384", - "content" : "edf079834fdd23317851318504b2fcc10b055cdb5cc4ada9c773d1b6c815ed6dd193c433d2b83103f070fd521021ff33" + "content" : "aae645eb112a6d5bce213a766a6cf76df828545df07438340b007e9eb8db546e62b2a01d94385daea86bfb7b1952c34a" }, { "alg" : "SHA3-256", - "content" : "56244f45b03fc2a472b35489324e392e6001fac088d19f33629a87adb74a0575" + "content" : "c805dca696ff5b10f8c21fca1e99c0771d3778507888ab7da4aa939a6c770e61" }, { "alg" : "SHA3-512", - "content" : "e0516c11fe613f258bf9ad39358a8d9fb7c8df57ff9aaca5d6d16055c196fac4ed3b4185f2501a3bdf7aeb1fe142693b1d788bdaa73366be1af15762bb3591a4" + "content" : "851caf550ca3f5cf9ff38c0961d18c60e752df41b6a8a28a8c856ea8e421cc9de7090155f688cffc889b576aa4ff0558b1138b1810ed25b135c1f68509c8be7f" } ], "licenses" : [ { "license" : { - "id" : "MIT" + "id" : "Apache-2.0" } } ], - "purl" : "pkg:maven/org.checkerframework/checker-qual@3.33.0?type=jar", - "modified" : false, - "externalReferences" : [ - { - "type" : "vcs", - "url" : "https://github.com/typetools/checker-framework.git" - } - ], - "type" : "library", - "bom-ref" : "pkg:maven/org.checkerframework/checker-qual@3.33.0?type=jar" + "purl" : "pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20211018.2?type=jar", + "modified" : false }, { - "group" : "org.apache.pdfbox", - "name" : "pdfbox", - "version" : "2.0.30", - "description" : "The Apache PDFBox library is an open source Java tool for working with PDF documents.", + "type" : "library", + "bom-ref" : "pkg:maven/org.checkerframework/checker-qual@3.33.0?type=jar", + "group" : "org.checkerframework", + "name" : "checker-qual", + "version" : "3.33.0", + "description" : "checker-qual contains annotations (type qualifiers) that a programmer writes to specify Java code for type-checking by the Checker Framework.", "hashes" : [ { "alg" : "MD5", - "content" : "da9a5490ecf28832ee6d003f9bcd95bd" + "content" : "fc9418b779d9d57dcd52197006cbdb9b" }, { "alg" : "SHA-1", - "content" : "730753a91f7f2c574eb09a8af7288065d1e551bd" + "content" : "de2b60b62da487644fc11f734e73c8b0b431238f" }, { "alg" : "SHA-256", - "content" : "abb468d07abe76e34efb3337d1cfd48e365241623320e277e8341ce3cd670760" + "content" : "e316255bbfcd9fe50d165314b85abb2b33cb2a66a93c491db648e498a82c2de1" }, { "alg" : "SHA-512", - "content" : "3727ede4a890c7c5c23e048fa037e013e8a3c85fcbe014e239c8c4dc7044a45b1143c4d773973f4f78032fb98d427486dd38f79f22dd6fb62dd713fee82e754f" + "content" : "049c446677b7b386f3fb501bf65e032bdf2b1b29a3f545848035fff2b683cd275380cf302e30eea641af7f0801f779bcda3d82a71d928e4176f564f796640a64" }, { "alg" : "SHA-384", - "content" : "d191b697ea322c23fe8a142fae04b8d84eb67d9852af5f7d89caf85db4c6573eafc830093f51edaa1622e6330090e860" + "content" : "ddf7a0f70421d1ed75e93c0a30434a4862c3905e433223e19861323cf0994e843392b746003040f10a7db6fc960b8aa6" }, { "alg" : "SHA3-384", - "content" : "ba9f6d207a618edf1f9d496731538f2e774ce1238fb8252665cb1efedd4d17c85e319663cf2b8c9bd415ee17ea926bda" + "content" : "edf079834fdd23317851318504b2fcc10b055cdb5cc4ada9c773d1b6c815ed6dd193c433d2b83103f070fd521021ff33" }, { "alg" : "SHA3-256", - "content" : "9b62e73a41d0f73b805918bbc2c9da4c60e86d454366bf9ae56917264fc8d085" + "content" : "56244f45b03fc2a472b35489324e392e6001fac088d19f33629a87adb74a0575" }, { "alg" : "SHA3-512", - "content" : "41f714619824293519067fd3ba3e7295595f447778e60b21209bd09a46222af0d8492d7cc6a72e1d16012d727402c9e3a1767959be788c5e3a49ad537f3bf3ad" + "content" : "e0516c11fe613f258bf9ad39358a8d9fb7c8df57ff9aaca5d6d16055c196fac4ed3b4185f2501a3bdf7aeb1fe142693b1d788bdaa73366be1af15762bb3591a4" } ], "licenses" : [ { "license" : { - "id" : "Apache-2.0" + "id" : "MIT" } } ], - "purl" : "pkg:maven/org.apache.pdfbox/pdfbox@2.0.30?type=jar", + "purl" : "pkg:maven/org.checkerframework/checker-qual@3.33.0?type=jar", "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/org.apache.pdfbox/pdfbox@2.0.30?type=jar" + "externalReferences" : [ + { + "type" : "vcs", + "url" : "https://github.com/typetools/checker-framework.git" + } + ] }, { + "type" : "library", + "bom-ref" : "pkg:maven/org.apache.commons/commons-text@1.10.0?type=jar", "group" : "org.apache.commons", "name" : "commons-text", "version" : "1.10.0", @@ -856,99 +895,98 @@ "type" : "vcs", "url" : "https://gitbox.apache.org/repos/asf?p=commons-text.git" } - ], - "type" : "library", - "bom-ref" : "pkg:maven/org.apache.commons/commons-text@1.10.0?type=jar" + ] }, { - "group" : "org.slf4j", - "name" : "slf4j-api", - "version" : "2.0.9", - "description" : "The slf4j API", + "type" : "library", + "bom-ref" : "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar", + "group" : "org.hamcrest", + "name" : "hamcrest-core", + "version" : "1.3", + "description" : "This is the core API of hamcrest matcher framework to be used by third-party framework providers. This includes the a foundation set of matcher implementations for common operations.", "hashes" : [ { "alg" : "MD5", - "content" : "45630e54b0f0ac2b3c80462515ad8fda" + "content" : "6393363b47ddcbba82321110c3e07519" }, { "alg" : "SHA-1", - "content" : "7cf2726fdcfbc8610f9a71fb3ed639871f315340" + "content" : "42a25dc3219429f0e5d060061f71acb49bf010a0" }, { "alg" : "SHA-256", - "content" : "0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c" + "content" : "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9" }, { "alg" : "SHA-512", - "content" : "069e6ddce79617e37d61758120c7e68348ee62f255781948937f7bec3058e46244026d7f6a11e90fbc15cd4288c4bb1acee4f242af521c721a9e68a05e64d526" + "content" : "e237ae735aac4fa5a7253ec693191f42ef7ddce384c11d29fbf605981c0be077d086757409acad53cb5b9e53d86a07cc428d459ff0f5b00d32a8cbbca390be49" }, { "alg" : "SHA-384", - "content" : "fd6f7ad85d02ac63cd1a586c8bb158c1fc000495f512f097731ea9f749b5da2637615b821294962805ba312c738f40aa" + "content" : "4b5297d2a12cc32b824153afc83f1ba9f1869ca288330f0a2f759659d09e4c420eb6ba4a1efbfa0657b625edd41293d5" }, { "alg" : "SHA3-384", - "content" : "17cd61f59a162250b52a89c7c56eb60da253b776210500313c7b82744483ff84717946f969251fb4d76f9bb12a2458fe" + "content" : "b14d34985c0a78cf0ba19b5a18bffd403e08adcb2afde228ddef6e16121c7046dbebf58c04d3419311c4496c48aa93be" }, { "alg" : "SHA3-256", - "content" : "9dcb04582c64c79e788f9191195834ec75bb3457133d22a176a0ccb069b97103" + "content" : "f679af77deedf69b3c3066f7916583848c6fd32a950f9c0b0e2ef1da121717ba" }, { "alg" : "SHA3-512", - "content" : "990faffa454598a3fa82affe30f1323db769d2e1fff20d9c7163ef6fd95ac7a0874c06a634207a2eaed9e5afbdee68b225138fc75018717ba97efe3ffe92c88a" + "content" : "bca821931e438a1977b7b4356b5f8cebf485634f82159d505c48267c34e6a0f4fde9c2917331365f66dc0e52e2ca3a2db5256863584110c27ecebefc28741f63" } ], "licenses" : [ { "license" : { - "id" : "MIT", - "url" : "https://opensource.org/licenses/MIT" + "id" : "BSD-3-Clause" } } ], - "purl" : "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar" + "purl" : "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar", + "modified" : false }, { - "group" : "com.google.j2objc", - "name" : "j2objc-annotations", - "version" : "2.8", - "description" : "A set of annotations that provide additional information to the J2ObjC translator to modify the result of translation.", + "type" : "library", + "bom-ref" : "pkg:maven/commons-logging/commons-logging@1.2?type=jar", + "group" : "commons-logging", + "name" : "commons-logging", + "version" : "1.2", + "description" : "Apache Commons Logging is a thin adapter allowing configurable bridging to other, well known logging systems.", "hashes" : [ { "alg" : "MD5", - "content" : "c50af69b704dc91050efb98e0dff66d1" + "content" : "040b4b4d8eac886f6b4a2a3bd2f31b00" }, { "alg" : "SHA-1", - "content" : "c85270e307e7b822f1086b93689124b89768e273" + "content" : "4bfc12adfe4842bf07b657f0369c4cb522955686" }, { "alg" : "SHA-256", - "content" : "f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed" + "content" : "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636" }, { "alg" : "SHA-512", - "content" : "f8263868a792b41707c9e7fe6fa5650a14cd93fbeafad20efe3772a3058fc933eb59782ec59e6eb9b9c569aa96da80134ae9fdf7547b69c44a97087efddceeff" + "content" : "ed00dbfabd9ae00efa26dd400983601d076fe36408b7d6520084b447e5d1fa527ce65bd6afdcb58506c3a808323d28e88f26cb99c6f5db9ff64f6525ecdfa557" }, { "alg" : "SHA-384", - "content" : "e6087ec31fec8289158496ad2ed6ce8472d5d513808a312e0782cedac3b86c37a62a63c0b5ea3839491d109fe9e148a1" + "content" : "ac20720d7156131478205f1b454395abf84cfc8da2f163301af32f63bd3c4764bd26cb54ed53800f33193ae591f3ce9c" }, { "alg" : "SHA3-384", - "content" : "10add34bfeb8612283eef89ac96747a3c9b755acd80ad526e1addaeb7efd6323c52b9bfa1a3d34adb40e1ccb963ee65d" + "content" : "628eb4407e95dca84da1a06b08a6d9b832a49de8472b1b217e8607f08efeeed18b996232d64dd07f03e78e0e3bb4b078" }, { "alg" : "SHA3-256", - "content" : "b3336f8abd6b1f73b9f06d306974557000a000073bfbae6b54fda26d17dbb072" + "content" : "9aab62deccf156ee6e324c925dfc30ecb53e8465802863a551901a461424e807" }, { "alg" : "SHA3-512", - "content" : "d376c184a6df071c4e93b913d175b5c2e63deac37105dc20342c19bdda62e4e9598ca1e8bfb4f4fd5cdee6dd5ac3b8af49e2c5193e324d59a59ce1f7adeab627" + "content" : "3fd76857f6d20c03799537cc961c1c4ddf1c375c6c192fb982363e3b9397ba138b77f24ef38b4202f44e37586789c0320e4de18fdadd2772304fd14a9b26d552" } ], "licenses" : [ @@ -958,99 +996,58 @@ } } ], - "purl" : "pkg:maven/com.google.j2objc/j2objc-annotations@2.8?type=jar", + "purl" : "pkg:maven/commons-logging/commons-logging@1.2?type=jar", "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/com.google.j2objc/j2objc-annotations@2.8?type=jar" - }, - { - "group" : "org.apache.pdfbox", - "name" : "fontbox", - "version" : "2.0.30", - "description" : "The Apache FontBox library is an open source Java tool to obtain low level information from font files. FontBox is a subproject of Apache PDFBox.", - "hashes" : [ - { - "alg" : "MD5", - "content" : "3a7b597c9dbd56e18455e6efca52cbb3" - }, - { - "alg" : "SHA-1", - "content" : "555e5d59a4d83c95c4330f018a6c32861880b6df" - }, - { - "alg" : "SHA-256", - "content" : "aae7518f9c17d347531e63b22a46de582cb78f7e45d079a78a79dc9bdb23f8ba" - }, - { - "alg" : "SHA-512", - "content" : "61eb46fee25826a8b0750fbe3823504e043f7e809f6ac3d144a1ba773195de29ebcffe30faee1bc9d2db50c94c45ebf65b67eb19e3358dbabf7878d36f133396" - }, - { - "alg" : "SHA-384", - "content" : "ca4ccf8281e1b481f83b8e156a3c2cfab0590f3d0a0a19f9cf80997966170affb01da293bacb880ae70ff8e6f54deb0e" - }, - { - "alg" : "SHA3-384", - "content" : "184a9a72f221f34fb98b9d5e132b74b18bab569b8f6e86a5e1e7b88e5d6f82095607809e2cd98620f43cdbd3efd0b277" - }, + "externalReferences" : [ { - "alg" : "SHA3-256", - "content" : "1c1333b59673e8caf3db1fc6453ce9c799b133faaee9017c2860a03257107325" + "type" : "issue-tracker", + "url" : "http://issues.apache.org/jira/browse/LOGGING" }, { - "alg" : "SHA3-512", - "content" : "4b018c517e51185debe39adc9237728b6a189cbfc8053bc8401fa2c115f2a40c1e242b5ce1ebf0339480bc332bd4681e9a3dcbb1c4c5bc8d7fca16f202e3ef5b" - } - ], - "licenses" : [ - { - "license" : { - "id" : "Apache-2.0" - } + "type" : "vcs", + "url" : "http://svn.apache.org/repos/asf/commons/proper/logging/trunk" } - ], - "purl" : "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar" + ] }, { - "group" : "com.google.guava", - "name" : "failureaccess", - "version" : "1.0.1", - "description" : "Contains com.google.common.util.concurrent.internal.InternalFutureFailureAccess and InternalFutures. Most users will never need to use this artifact. Its classes is conceptually a part of Guava, but they're in this separate artifact so that Android libraries can use them without pulling in all of Guava (just as they can use ListenableFuture by depending on the listenablefuture artifact).", + "type" : "library", + "bom-ref" : "pkg:maven/com.google.code.findbugs/jsr305@3.0.2?type=jar", + "group" : "com.google.code.findbugs", + "name" : "jsr305", + "version" : "3.0.2", + "description" : "JSR305 Annotations for Findbugs", "hashes" : [ { "alg" : "MD5", - "content" : "091883993ef5bfa91da01dcc8fc52236" + "content" : "dd83accb899363c32b07d7a1b2e4ce40" }, { "alg" : "SHA-1", - "content" : "1dcf1de382a0bf95a3d8b0849546c88bac1292c9" + "content" : "25ea2e8b0c338a877313bd4672d3fe056ea78f0d" }, { "alg" : "SHA-256", - "content" : "a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26" + "content" : "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" }, { "alg" : "SHA-512", - "content" : "f8d59b808d6ba617252305b66d5590937da9b2b843d492d06b8d0b1b1f397e39f360d5817707797b979a5bf20bf21987b35333e7a15c44ed7401fea2d2119cae" + "content" : "bb09db62919a50fa5b55906013be6ca4fc7acb2e87455fac5eaf9ede2e41ce8bbafc0e5a385a561264ea4cd71bbbd3ef5a45e02d63277a201d06a0ae1636f804" }, { "alg" : "SHA-384", - "content" : "67659dbd9647ec303d7f15128dc9dba19b98fd8d74758ee3b602451e32c855e236ccaafe08edf4bbfa245f981268440f" + "content" : "ca0b169d3eb2d0922dc031133a021f861a043bb3e405a88728215fd6ff00fa52fdc7347842dcc2031472e3726164bdc4" }, { "alg" : "SHA3-384", - "content" : "1460875f0331c5fa3791772a6a322a7db180261bc2adacf7271df1fbf3b088a587a755a604c039982cb593c5cfc1f101" + "content" : "9903fd7505218999f8262efedb3d935d64bcef84aae781064ab5e1b24755466b269517cada562fa140cd1d417ede57a1" }, { "alg" : "SHA3-256", - "content" : "ea86406e75fcd93eafe3cde1b3135ba485f1bb9b75fed98894a0bf1f0aee04f0" + "content" : "223fda9a89a461afaae73b177a2dc20ed4a90f2f8757f5c65f3241b0510f00ff" }, { "alg" : "SHA3-512", - "content" : "52ac0f487ab5dd27c9f2e54fd1d84c7a620cae9d49be4072aa2b11501787bf4391ddaa13d02eccdf19e8eea46aecbea5f6064b26777c1b836108a280652e04ac" + "content" : "3996b5af57a5d5c6a0cd62b11773360fb051dd86a2ba968476806a2a5d32049b82d69a24a3c694e8fe4d735be6a28e41000cc500cc2a9fb577e058045855d2d6" } ], "licenses" : [ @@ -1060,90 +1057,79 @@ } } ], - "purl" : "pkg:maven/com.google.guava/failureaccess@1.0.1?type=jar", + "purl" : "pkg:maven/com.google.code.findbugs/jsr305@3.0.2?type=jar", "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/com.google.guava/failureaccess@1.0.1?type=jar" + "externalReferences" : [ + { + "type" : "vcs", + "url" : "https://code.google.com/p/jsr-305/" + } + ] }, { - "group" : "org.hamcrest", - "name" : "hamcrest-core", - "version" : "1.3", - "description" : "This is the core API of hamcrest matcher framework to be used by third-party framework providers. This includes the a foundation set of matcher implementations for common operations.", + "type" : "library", + "bom-ref" : "pkg:maven/com.google.j2objc/j2objc-annotations@2.8?type=jar", + "group" : "com.google.j2objc", + "name" : "j2objc-annotations", + "version" : "2.8", + "description" : "A set of annotations that provide additional information to the J2ObjC translator to modify the result of translation.", "hashes" : [ { "alg" : "MD5", - "content" : "6393363b47ddcbba82321110c3e07519" + "content" : "c50af69b704dc91050efb98e0dff66d1" }, { "alg" : "SHA-1", - "content" : "42a25dc3219429f0e5d060061f71acb49bf010a0" + "content" : "c85270e307e7b822f1086b93689124b89768e273" }, { "alg" : "SHA-256", - "content" : "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9" + "content" : "f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed" }, { "alg" : "SHA-512", - "content" : "e237ae735aac4fa5a7253ec693191f42ef7ddce384c11d29fbf605981c0be077d086757409acad53cb5b9e53d86a07cc428d459ff0f5b00d32a8cbbca390be49" + "content" : "f8263868a792b41707c9e7fe6fa5650a14cd93fbeafad20efe3772a3058fc933eb59782ec59e6eb9b9c569aa96da80134ae9fdf7547b69c44a97087efddceeff" }, { "alg" : "SHA-384", - "content" : "4b5297d2a12cc32b824153afc83f1ba9f1869ca288330f0a2f759659d09e4c420eb6ba4a1efbfa0657b625edd41293d5" + "content" : "e6087ec31fec8289158496ad2ed6ce8472d5d513808a312e0782cedac3b86c37a62a63c0b5ea3839491d109fe9e148a1" }, { "alg" : "SHA3-384", - "content" : "b14d34985c0a78cf0ba19b5a18bffd403e08adcb2afde228ddef6e16121c7046dbebf58c04d3419311c4496c48aa93be" + "content" : "10add34bfeb8612283eef89ac96747a3c9b755acd80ad526e1addaeb7efd6323c52b9bfa1a3d34adb40e1ccb963ee65d" }, { "alg" : "SHA3-256", - "content" : "f679af77deedf69b3c3066f7916583848c6fd32a950f9c0b0e2ef1da121717ba" + "content" : "b3336f8abd6b1f73b9f06d306974557000a000073bfbae6b54fda26d17dbb072" }, { "alg" : "SHA3-512", - "content" : "bca821931e438a1977b7b4356b5f8cebf485634f82159d505c48267c34e6a0f4fde9c2917331365f66dc0e52e2ca3a2db5256863584110c27ecebefc28741f63" + "content" : "d376c184a6df071c4e93b913d175b5c2e63deac37105dc20342c19bdda62e4e9598ca1e8bfb4f4fd5cdee6dd5ac3b8af49e2c5193e324d59a59ce1f7adeab627" } ], "licenses" : [ { "license" : { - "id" : "BSD-3-Clause" + "id" : "Apache-2.0" } } ], - "purl" : "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar", - "modified" : false, - "type" : "library", - "bom-ref" : "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar" + "purl" : "pkg:maven/com.google.j2objc/j2objc-annotations@2.8?type=jar", + "modified" : false } ], "dependencies" : [ { - "ref" : "pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20211018.2?type=jar", - "dependsOn" : [ - "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar" - ] - }, - { - "ref" : "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar", + "ref" : "pkg:maven/com.google.code.findbugs/jsr305@3.0.2?type=jar", "dependsOn" : [ ] }, { - "ref" : "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar", + "ref" : "pkg:maven/com.google.errorprone/error_prone_annotations@2.18.0?type=jar", "dependsOn" : [ ] }, { - "ref" : "pkg:maven/org.apache.pdfbox/pdfbox@2.0.30?type=jar", - "dependsOn" : [ - "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar", - "pkg:maven/commons-logging/commons-logging@1.2?type=jar" - ] - }, - { - "ref" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar", - "dependsOn" : [ - "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar" - ] + "ref" : "pkg:maven/com.google.guava/failureaccess@1.0.1?type=jar", + "dependsOn" : [ ] }, { "ref" : "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar", @@ -1156,12 +1142,26 @@ "pkg:maven/com.google.j2objc/j2objc-annotations@2.8?type=jar" ] }, + { + "ref" : "pkg:maven/com.google.guava/listenablefuture@9999.0-empty-to-avoid-conflict-with-guava?type=jar", + "dependsOn" : [ ] + }, + { + "ref" : "pkg:maven/com.google.j2objc/j2objc-annotations@2.8?type=jar", + "dependsOn" : [ ] + }, + { + "ref" : "pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20211018.2?type=jar", + "dependsOn" : [ + "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar" + ] + }, { "ref" : "pkg:maven/com.mendix/temp@1.0.0?type=jar", "dependsOn" : [ "pkg:maven/com.google.guava/guava@32.0.1-jre?type=jar", "pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20211018.2?type=jar", - "pkg:maven/commons-io/commons-io@2.11.0?type=jar", + "pkg:maven/commons-io/commons-io@2.17.0?type=jar", "pkg:maven/junit/junit@4.13.1?type=jar", "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar", "pkg:maven/org.apache.commons/commons-text@1.10.0?type=jar", @@ -1171,69 +1171,70 @@ ] }, { - "ref" : "pkg:maven/org.apache.httpcomponents.client5/httpclient5@5.2.1?type=jar", - "dependsOn" : [ - "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar", - "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar", - "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar" - ] - }, - { - "ref" : "pkg:maven/com.google.guava/listenablefuture@9999.0-empty-to-avoid-conflict-with-guava?type=jar", + "ref" : "pkg:maven/commons-io/commons-io@2.17.0?type=jar", "dependsOn" : [ ] }, - { - "ref" : "pkg:maven/org.apache.commons/commons-text@1.10.0?type=jar", - "dependsOn" : [ - "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar" - ] - }, { "ref" : "pkg:maven/commons-logging/commons-logging@1.2?type=jar", "dependsOn" : [ ] }, { - "ref" : "pkg:maven/com.google.code.findbugs/jsr305@3.0.2?type=jar", - "dependsOn" : [ ] + "ref" : "pkg:maven/junit/junit@4.13.1?type=jar", + "dependsOn" : [ + "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar" + ] }, { - "ref" : "pkg:maven/org.checkerframework/checker-qual@3.33.0?type=jar", + "ref" : "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar", "dependsOn" : [ ] }, { - "ref" : "pkg:maven/junit/junit@4.13.1?type=jar", + "ref" : "pkg:maven/org.apache.commons/commons-text@1.10.0?type=jar", "dependsOn" : [ - "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar" + "pkg:maven/org.apache.commons/commons-lang3@3.12.0?type=jar" ] }, { - "ref" : "pkg:maven/com.google.guava/failureaccess@1.0.1?type=jar", - "dependsOn" : [ ] + "ref" : "pkg:maven/org.apache.httpcomponents.client5/httpclient5@5.2.1?type=jar", + "dependsOn" : [ + "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar", + "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar", + "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar" + ] }, { - "ref" : "pkg:maven/com.google.errorprone/error_prone_annotations@2.18.0?type=jar", - "dependsOn" : [ ] + "ref" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5-h2@5.2?type=jar", + "dependsOn" : [ + "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar" + ] }, { "ref" : "pkg:maven/org.apache.httpcomponents.core5/httpcore5@5.2?type=jar", "dependsOn" : [ ] }, { - "ref" : "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar", - "dependsOn" : [ ] + "ref" : "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar", + "dependsOn" : [ + "pkg:maven/commons-logging/commons-logging@1.2?type=jar" + ] }, { - "ref" : "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar", + "ref" : "pkg:maven/org.apache.pdfbox/pdfbox@2.0.30?type=jar", "dependsOn" : [ + "pkg:maven/org.apache.pdfbox/fontbox@2.0.30?type=jar", "pkg:maven/commons-logging/commons-logging@1.2?type=jar" ] }, { - "ref" : "pkg:maven/com.google.j2objc/j2objc-annotations@2.8?type=jar", + "ref" : "pkg:maven/org.checkerframework/checker-qual@3.33.0?type=jar", "dependsOn" : [ ] }, { - "ref" : "pkg:maven/commons-io/commons-io@2.11.0?type=jar", + "ref" : "pkg:maven/org.hamcrest/hamcrest-core@1.3?type=jar", + "dependsOn" : [ ] + }, + { + "ref" : "pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar", "dependsOn" : [ ] } ] diff --git a/Source/widgets/Badge.mpk b/Source/widgets/Badge.mpk index fa3a0786..aa63bb9b 100644 Binary files a/Source/widgets/Badge.mpk and b/Source/widgets/Badge.mpk differ diff --git a/Source/widgets/Charts.mpk b/Source/widgets/Charts.mpk index d4f23284..f68080b5 100644 Binary files a/Source/widgets/Charts.mpk and b/Source/widgets/Charts.mpk differ diff --git a/Source/widgets/ProgressBar.mpk b/Source/widgets/ProgressBar.mpk index 2c7abf79..3600d84f 100644 Binary files a/Source/widgets/ProgressBar.mpk and b/Source/widgets/ProgressBar.mpk differ diff --git a/Source/widgets/ProgressCircle.mpk b/Source/widgets/ProgressCircle.mpk index 8cf31af6..32710441 100644 Binary files a/Source/widgets/ProgressCircle.mpk and b/Source/widgets/ProgressCircle.mpk differ diff --git a/Source/widgets/com.mendix.widget.native.Feedback.mpk b/Source/widgets/com.mendix.widget.native.Feedback.mpk index d9803712..67f2cfb5 100644 Binary files a/Source/widgets/com.mendix.widget.native.Feedback.mpk and b/Source/widgets/com.mendix.widget.native.Feedback.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.Combobox.mpk b/Source/widgets/com.mendix.widget.web.Combobox.mpk index f9e89fc4..f7d52514 100644 Binary files a/Source/widgets/com.mendix.widget.web.Combobox.mpk and b/Source/widgets/com.mendix.widget.web.Combobox.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.Datagrid.mpk b/Source/widgets/com.mendix.widget.web.Datagrid.mpk index 550c6e44..2455e9fc 100644 Binary files a/Source/widgets/com.mendix.widget.web.Datagrid.mpk and b/Source/widgets/com.mendix.widget.web.Datagrid.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.DatagridDateFilter.mpk b/Source/widgets/com.mendix.widget.web.DatagridDateFilter.mpk index 0b61aaf7..075c3fb8 100644 Binary files a/Source/widgets/com.mendix.widget.web.DatagridDateFilter.mpk and b/Source/widgets/com.mendix.widget.web.DatagridDateFilter.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.DatagridDropdownFilter.mpk b/Source/widgets/com.mendix.widget.web.DatagridDropdownFilter.mpk index 378ef0ed..d19bc683 100644 Binary files a/Source/widgets/com.mendix.widget.web.DatagridDropdownFilter.mpk and b/Source/widgets/com.mendix.widget.web.DatagridDropdownFilter.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.DatagridNumberFilter.mpk b/Source/widgets/com.mendix.widget.web.DatagridNumberFilter.mpk index 677bdf12..36ef14a3 100644 Binary files a/Source/widgets/com.mendix.widget.web.DatagridNumberFilter.mpk and b/Source/widgets/com.mendix.widget.web.DatagridNumberFilter.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.DatagridTextFilter.mpk b/Source/widgets/com.mendix.widget.web.DatagridTextFilter.mpk index 7cea3048..b5dec479 100644 Binary files a/Source/widgets/com.mendix.widget.web.DatagridTextFilter.mpk and b/Source/widgets/com.mendix.widget.web.DatagridTextFilter.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.DropdownSort.mpk b/Source/widgets/com.mendix.widget.web.DropdownSort.mpk index 036878a4..085f7962 100644 Binary files a/Source/widgets/com.mendix.widget.web.DropdownSort.mpk and b/Source/widgets/com.mendix.widget.web.DropdownSort.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.Gallery.mpk b/Source/widgets/com.mendix.widget.web.Gallery.mpk index 8e7ce6a0..91409463 100644 Binary files a/Source/widgets/com.mendix.widget.web.Gallery.mpk and b/Source/widgets/com.mendix.widget.web.Gallery.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.LanguageSelector.mpk b/Source/widgets/com.mendix.widget.web.LanguageSelector.mpk index fdc48340..55e53d04 100644 Binary files a/Source/widgets/com.mendix.widget.web.LanguageSelector.mpk and b/Source/widgets/com.mendix.widget.web.LanguageSelector.mpk differ diff --git a/Source/widgets/com.mendix.widget.web.Timeline.mpk b/Source/widgets/com.mendix.widget.web.Timeline.mpk index fda4f5e4..2d86239e 100644 Binary files a/Source/widgets/com.mendix.widget.web.Timeline.mpk and b/Source/widgets/com.mendix.widget.web.Timeline.mpk differ diff --git a/data-snapshot.zip b/data-snapshot.zip index 878da2fd..75677497 100644 Binary files a/data-snapshot.zip and b/data-snapshot.zip differ