3dspread3
#import getscript
#import parallel
#import bs58
#import subchannel
function templatelist() {
return ['loan'];
}
function template_loan() {
return `["0:0:0:Start Date","0:1:0:Principle","0:2:0:Term (in years)","0:3:0:Rate (in percent)","0:4:0:Periods per year","0:6:0:P Payment","0:7:0:D Rate","3:0:0:Due Date","3:1:0:Remaining","3:2:0:Periods left","3:3:0:Principle","3:4:0:Interest","3:5:0:Total","3:6:0:Real Paid","3:7:0:Notes","1:1:0:10000","1:0:0:=new Date('10/26/2018')","1:2:0:4","1:3:0:3.5","1:4:0:24","1:6:0:=c1:1:0/c1:2:0/c1:4:0","1:7:0:=(Math.pow(c1:3:0/100+1,1/c1:4:0)-1)*100","4:0:0:=c1:0:0","4:1:0:=c1:1:0","4:2:0:=c1:2:0*c1:4:0","4:3:0:=c4:1:0/c4:2:0","4:4:0:=c4:1:0*c$1:7:0/100","4:5:0:=Math.round(c4:3:0+c4:4:0)","5:0:0:=new Date(c4:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","5:1:0:=c4:1:0+c4:4:0-(c4:6:0===null?c4:5:0:c4:6:0)","5:2:0:=c4:2:0-1","5:3:0:=c5:1:0/c5:2:0","5:4:0:=c5:1:0*c$1:7:0/100","5:5:0:=Math.round(c5:3:0+c5:4:0)","6:0:0:=new Date(c5:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","6:1:0:=c5:1:0+c5:4:0-(c5:6:0===null?c5:5:0:c5:6:0)","6:2:0:=c5:2:0-1","6:3:0:=c6:1:0/c6:2:0","6:4:0:=c6:1:0*c$1:7:0/100","6:5:0:=Math.round(c6:3:0+c6:4:0)","7:0:0:=new Date(c6:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","7:1:0:=c6:1:0+c6:4:0-(c6:6:0===null?c6:5:0:c6:6:0)","7:2:0:=c6:2:0-1","7:3:0:=c7:1:0/c7:2:0","7:4:0:=c7:1:0*c$1:7:0/100","7:5:0:=Math.round(c7:3:0+c7:4:0)","8:0:0:=new Date(c7:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","8:1:0:=c7:1:0+c7:4:0-(c7:6:0===null?c7:5:0:c7:6:0)","8:2:0:=c7:2:0-1","8:3:0:=c8:1:0/c8:2:0","8:4:0:=c8:1:0*c$1:7:0/100","8:5:0:=Math.round(c8:3:0+c8:4:0)","9:0:0:=new Date(c8:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","9:1:0:=c8:1:0+c8:4:0-(c8:6:0===null?c8:5:0:c8:6:0)","9:2:0:=c8:2:0-1","9:3:0:=c9:1:0/c9:2:0","9:4:0:=c9:1:0*c$1:7:0/100","9:5:0:=Math.round(c9:3:0+c9:4:0)","10:0:0:=new Date(c9:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","10:1:0:=c9:1:0+c9:4:0-(c9:6:0===null?c9:5:0:c9:6:0)","10:2:0:=c9:2:0-1","10:3:0:=c10:1:0/c10:2:0","10:4:0:=c10:1:0*c$1:7:0/100","10:5:0:=Math.round(c10:3:0+c10:4:0)","11:0:0:=new Date(c10:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","11:1:0:=c10:1:0+c10:4:0-(c10:6:0===null?c10:5:0:c10:6:0)","11:2:0:=c10:2:0-1","11:3:0:=c11:1:0/c11:2:0","11:4:0:=c11:1:0*c$1:7:0/100","11:5:0:=Math.round(c11:3:0+c11:4:0)","12:0:0:=new Date(c11:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","12:1:0:=c11:1:0+c11:4:0-(c11:6:0===null?c11:5:0:c11:6:0)","12:2:0:=c11:2:0-1","12:3:0:=c12:1:0/c12:2:0","12:4:0:=c12:1:0*c$1:7:0/100","12:5:0:=Math.round(c12:3:0+c12:4:0)","13:0:0:=new Date(c12:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","13:1:0:=c12:1:0+c12:4:0-(c12:6:0===null?c12:5:0:c12:6:0)","13:2:0:=c12:2:0-1","13:3:0:=c13:1:0/c13:2:0","13:4:0:=c13:1:0*c$1:7:0/100","13:5:0:=Math.round(c13:3:0+c13:4:0)","14:0:0:=new Date(c13:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","14:1:0:=c13:1:0+c13:4:0-(c13:6:0===null?c13:5:0:c13:6:0)","14:2:0:=c13:2:0-1","14:3:0:=c14:1:0/c14:2:0","14:4:0:=c14:1:0*c$1:7:0/100","14:5:0:=Math.round(c14:3:0+c14:4:0)","15:0:0:=new Date(c14:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","15:1:0:=c14:1:0+c14:4:0-(c14:6:0===null?c14:5:0:c14:6:0)","15:2:0:=c14:2:0-1","15:3:0:=c15:1:0/c15:2:0","15:4:0:=c15:1:0*c$1:7:0/100","15:5:0:=Math.round(c15:3:0+c15:4:0)","16:0:0:=new Date(c15:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","16:1:0:=c15:1:0+c15:4:0-(c15:6:0===null?c15:5:0:c15:6:0)","16:2:0:=c15:2:0-1","16:3:0:=c16:1:0/c16:2:0","16:4:0:=c16:1:0*c$1:7:0/100","16:5:0:=Math.round(c16:3:0+c16:4:0)","17:0:0:=new Date(c16:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","17:1:0:=c16:1:0+c16:4:0-(c16:6:0===null?c16:5:0:c16:6:0)","17:2:0:=c16:2:0-1","17:3:0:=c17:1:0/c17:2:0","17:4:0:=c17:1:0*c$1:7:0/100","17:5:0:=Math.round(c17:3:0+c17:4:0)","18:0:0:=new Date(c17:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","18:1:0:=c17:1:0+c17:4:0-(c17:6:0===null?c17:5:0:c17:6:0)","18:2:0:=c17:2:0-1","18:3:0:=c18:1:0/c18:2:0","18:4:0:=c18:1:0*c$1:7:0/100","18:5:0:=Math.round(c18:3:0+c18:4:0)","19:0:0:=new Date(c18:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","19:1:0:=c18:1:0+c18:4:0-(c18:6:0===null?c18:5:0:c18:6:0)","19:2:0:=c18:2:0-1","19:3:0:=c19:1:0/c19:2:0","19:4:0:=c19:1:0*c$1:7:0/100","19:5:0:=Math.round(c19:3:0+c19:4:0)","20:0:0:=new Date(c19:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","20:1:0:=c19:1:0+c19:4:0-(c19:6:0===null?c19:5:0:c19:6:0)","20:2:0:=c19:2:0-1","20:3:0:=c20:1:0/c20:2:0","20:4:0:=c20:1:0*c$1:7:0/100","20:5:0:=Math.round(c20:3:0+c20:4:0)","21:0:0:=new Date(c20:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","21:1:0:=c20:1:0+c20:4:0-(c20:6:0===null?c20:5:0:c20:6:0)","21:2:0:=c20:2:0-1","21:3:0:=c21:1:0/c21:2:0","21:4:0:=c21:1:0*c$1:7:0/100","21:5:0:=Math.round(c21:3:0+c21:4:0)","22:0:0:=new Date(c21:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","22:1:0:=c21:1:0+c21:4:0-(c21:6:0===null?c21:5:0:c21:6:0)","22:2:0:=c21:2:0-1","22:3:0:=c22:1:0/c22:2:0","22:4:0:=c22:1:0*c$1:7:0/100","22:5:0:=Math.round(c22:3:0+c22:4:0)","23:0:0:=new Date(c22:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","23:1:0:=c22:1:0+c22:4:0-(c22:6:0===null?c22:5:0:c22:6:0)","23:2:0:=c22:2:0-1","23:3:0:=c23:1:0/c23:2:0","23:4:0:=c23:1:0*c$1:7:0/100","23:5:0:=Math.round(c23:3:0+c23:4:0)","24:0:0:=new Date(c23:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","24:1:0:=c23:1:0+c23:4:0-(c23:6:0===null?c23:5:0:c23:6:0)","24:2:0:=c23:2:0-1","24:3:0:=c24:1:0/c24:2:0","24:4:0:=c24:1:0*c$1:7:0/100","24:5:0:=Math.round(c24:3:0+c24:4:0)","25:0:0:=new Date(c24:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","25:1:0:=c24:1:0+c24:4:0-(c24:6:0===null?c24:5:0:c24:6:0)","25:2:0:=c24:2:0-1","25:3:0:=c25:1:0/c25:2:0","25:4:0:=c25:1:0*c$1:7:0/100","25:5:0:=Math.round(c25:3:0+c25:4:0)","26:0:0:=new Date(c25:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","26:1:0:=c25:1:0+c25:4:0-(c25:6:0===null?c25:5:0:c25:6:0)","26:2:0:=c25:2:0-1","26:3:0:=c26:1:0/c26:2:0","26:4:0:=c26:1:0*c$1:7:0/100","26:5:0:=Math.round(c26:3:0+c26:4:0)","27:0:0:=new Date(c26:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","27:1:0:=c26:1:0+c26:4:0-(c26:6:0===null?c26:5:0:c26:6:0)","27:2:0:=c26:2:0-1","27:3:0:=c27:1:0/c27:2:0","27:4:0:=c27:1:0*c$1:7:0/100","27:5:0:=Math.round(c27:3:0+c27:4:0)","28:0:0:=new Date(c27:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","28:1:0:=c27:1:0+c27:4:0-(c27:6:0===null?c27:5:0:c27:6:0)","28:2:0:=c27:2:0-1","28:3:0:=c28:1:0/c28:2:0","28:4:0:=c28:1:0*c$1:7:0/100","28:5:0:=Math.round(c28:3:0+c28:4:0)","29:0:0:=new Date(c28:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","29:1:0:=c28:1:0+c28:4:0-(c28:6:0===null?c28:5:0:c28:6:0)","29:2:0:=c28:2:0-1","29:3:0:=c29:1:0/c29:2:0","29:4:0:=c29:1:0*c$1:7:0/100","29:5:0:=Math.round(c29:3:0+c29:4:0)","30:0:0:=new Date(c29:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","30:1:0:=c29:1:0+c29:4:0-(c29:6:0===null?c29:5:0:c29:6:0)","30:2:0:=c29:2:0-1","30:3:0:=c30:1:0/c30:2:0","30:4:0:=c30:1:0*c$1:7:0/100","30:5:0:=Math.round(c30:3:0+c30:4:0)","31:0:0:=new Date(c30:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","31:1:0:=c30:1:0+c30:4:0-(c30:6:0===null?c30:5:0:c30:6:0)","31:2:0:=c30:2:0-1","31:3:0:=c31:1:0/c31:2:0","31:4:0:=c31:1:0*c$1:7:0/100","31:5:0:=Math.round(c31:3:0+c31:4:0)","32:0:0:=new Date(c31:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","32:1:0:=c31:1:0+c31:4:0-(c31:6:0===null?c31:5:0:c31:6:0)","32:2:0:=c31:2:0-1","32:3:0:=c32:1:0/c32:2:0","32:4:0:=c32:1:0*c$1:7:0/100","32:5:0:=Math.round(c32:3:0+c32:4:0)","33:0:0:=new Date(c32:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","33:1:0:=c32:1:0+c32:4:0-(c32:6:0===null?c32:5:0:c32:6:0)","33:2:0:=c32:2:0-1","33:3:0:=c33:1:0/c33:2:0","33:4:0:=c33:1:0*c$1:7:0/100","33:5:0:=Math.round(c33:3:0+c33:4:0)","34:0:0:=new Date(c33:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","34:1:0:=c33:1:0+c33:4:0-(c33:6:0===null?c33:5:0:c33:6:0)","34:2:0:=c33:2:0-1","34:3:0:=c34:1:0/c34:2:0","34:4:0:=c34:1:0*c$1:7:0/100","34:5:0:=Math.round(c34:3:0+c34:4:0)","35:0:0:=new Date(c34:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","35:1:0:=c34:1:0+c34:4:0-(c34:6:0===null?c34:5:0:c34:6:0)","35:2:0:=c34:2:0-1","35:3:0:=c35:1:0/c35:2:0","35:4:0:=c35:1:0*c$1:7:0/100","35:5:0:=Math.round(c35:3:0+c35:4:0)","36:0:0:=new Date(c35:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","36:1:0:=c35:1:0+c35:4:0-(c35:6:0===null?c35:5:0:c35:6:0)","36:2:0:=c35:2:0-1","36:3:0:=c36:1:0/c36:2:0","36:4:0:=c36:1:0*c$1:7:0/100","36:5:0:=Math.round(c36:3:0+c36:4:0)","37:0:0:=new Date(c36:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","37:1:0:=c36:1:0+c36:4:0-(c36:6:0===null?c36:5:0:c36:6:0)","37:2:0:=c36:2:0-1","37:3:0:=c37:1:0/c37:2:0","37:4:0:=c37:1:0*c$1:7:0/100","37:5:0:=Math.round(c37:3:0+c37:4:0)","38:0:0:=new Date(c37:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","38:1:0:=c37:1:0+c37:4:0-(c37:6:0===null?c37:5:0:c37:6:0)","38:2:0:=c37:2:0-1","38:3:0:=c38:1:0/c38:2:0","38:4:0:=c38:1:0*c$1:7:0/100","38:5:0:=Math.round(c38:3:0+c38:4:0)","39:0:0:=new Date(c38:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","39:1:0:=c38:1:0+c38:4:0-(c38:6:0===null?c38:5:0:c38:6:0)","39:2:0:=c38:2:0-1","39:3:0:=c39:1:0/c39:2:0","39:4:0:=c39:1:0*c$1:7:0/100","39:5:0:=Math.round(c39:3:0+c39:4:0)","40:0:0:=new Date(c39:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","40:1:0:=c39:1:0+c39:4:0-(c39:6:0===null?c39:5:0:c39:6:0)","40:2:0:=c39:2:0-1","40:3:0:=c40:1:0/c40:2:0","40:4:0:=c40:1:0*c$1:7:0/100","40:5:0:=Math.round(c40:3:0+c40:4:0)","41:0:0:=new Date(c40:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","41:1:0:=c40:1:0+c40:4:0-(c40:6:0===null?c40:5:0:c40:6:0)","41:2:0:=c40:2:0-1","41:3:0:=c41:1:0/c41:2:0","41:4:0:=c41:1:0*c$1:7:0/100","41:5:0:=Math.round(c41:3:0+c41:4:0)","42:0:0:=new Date(c41:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","42:1:0:=c41:1:0+c41:4:0-(c41:6:0===null?c41:5:0:c41:6:0)","42:2:0:=c41:2:0-1","42:3:0:=c42:1:0/c42:2:0","42:4:0:=c42:1:0*c$1:7:0/100","42:5:0:=Math.round(c42:3:0+c42:4:0)","43:0:0:=new Date(c42:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","43:1:0:=c42:1:0+c42:4:0-(c42:6:0===null?c42:5:0:c42:6:0)","43:2:0:=c42:2:0-1","43:3:0:=c43:1:0/c43:2:0","43:4:0:=c43:1:0*c$1:7:0/100","43:5:0:=Math.round(c43:3:0+c43:4:0)","44:0:0:=new Date(c43:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","44:1:0:=c43:1:0+c43:4:0-(c43:6:0===null?c43:5:0:c43:6:0)","44:2:0:=c43:2:0-1","44:3:0:=c44:1:0/c44:2:0","44:4:0:=c44:1:0*c$1:7:0/100","44:5:0:=Math.round(c44:3:0+c44:4:0)","45:0:0:=new Date(c44:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","45:1:0:=c44:1:0+c44:4:0-(c44:6:0===null?c44:5:0:c44:6:0)","45:2:0:=c44:2:0-1","45:3:0:=c45:1:0/c45:2:0","45:4:0:=c45:1:0*c$1:7:0/100","45:5:0:=Math.round(c45:3:0+c45:4:0)","46:0:0:=new Date(c45:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","46:1:0:=c45:1:0+c45:4:0-(c45:6:0===null?c45:5:0:c45:6:0)","46:2:0:=c45:2:0-1","46:3:0:=c46:1:0/c46:2:0","46:4:0:=c46:1:0*c$1:7:0/100","46:5:0:=Math.round(c46:3:0+c46:4:0)","47:0:0:=new Date(c46:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","47:1:0:=c46:1:0+c46:4:0-(c46:6:0===null?c46:5:0:c46:6:0)","47:2:0:=c46:2:0-1","47:3:0:=c47:1:0/c47:2:0","47:4:0:=c47:1:0*c$1:7:0/100","47:5:0:=Math.round(c47:3:0+c47:4:0)","48:0:0:=new Date(c47:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","48:1:0:=c47:1:0+c47:4:0-(c47:6:0===null?c47:5:0:c47:6:0)","48:2:0:=c47:2:0-1","48:3:0:=c48:1:0/c48:2:0","48:4:0:=c48:1:0*c$1:7:0/100","48:5:0:=Math.round(c48:3:0+c48:4:0)","49:0:0:=new Date(c48:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","49:1:0:=c48:1:0+c48:4:0-(c48:6:0===null?c48:5:0:c48:6:0)","49:2:0:=c48:2:0-1","49:3:0:=c49:1:0/c49:2:0","49:4:0:=c49:1:0*c$1:7:0/100","49:5:0:=Math.round(c49:3:0+c49:4:0)","50:0:0:=new Date(c49:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","50:1:0:=c49:1:0+c49:4:0-(c49:6:0===null?c49:5:0:c49:6:0)","50:2:0:=c49:2:0-1","50:3:0:=c50:1:0/c50:2:0","50:4:0:=c50:1:0*c$1:7:0/100","50:5:0:=Math.round(c50:3:0+c50:4:0)","51:0:0:=new Date(c50:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","51:1:0:=c50:1:0+c50:4:0-(c50:6:0===null?c50:5:0:c50:6:0)","51:2:0:=c50:2:0-1","51:3:0:=c51:1:0/c51:2:0","51:4:0:=c51:1:0*c$1:7:0/100","51:5:0:=Math.round(c51:3:0+c51:4:0)","52:0:0:=new Date(c51:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","52:1:0:=c51:1:0+c51:4:0-(c51:6:0===null?c51:5:0:c51:6:0)","52:2:0:=c51:2:0-1","52:3:0:=c52:1:0/c52:2:0","52:4:0:=c52:1:0*c$1:7:0/100","52:5:0:=Math.round(c52:3:0+c52:4:0)","53:0:0:=new Date(c52:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","53:1:0:=c52:1:0+c52:4:0-(c52:6:0===null?c52:5:0:c52:6:0)","53:2:0:=c52:2:0-1","53:3:0:=c53:1:0/c53:2:0","53:4:0:=c53:1:0*c$1:7:0/100","53:5:0:=Math.round(c53:3:0+c53:4:0)","54:0:0:=new Date(c53:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","54:1:0:=c53:1:0+c53:4:0-(c53:6:0===null?c53:5:0:c53:6:0)","54:2:0:=c53:2:0-1","54:3:0:=c54:1:0/c54:2:0","54:4:0:=c54:1:0*c$1:7:0/100","54:5:0:=Math.round(c54:3:0+c54:4:0)","55:0:0:=new Date(c54:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","55:1:0:=c54:1:0+c54:4:0-(c54:6:0===null?c54:5:0:c54:6:0)","55:2:0:=c54:2:0-1","55:3:0:=c55:1:0/c55:2:0","55:4:0:=c55:1:0*c$1:7:0/100","55:5:0:=Math.round(c55:3:0+c55:4:0)","56:0:0:=new Date(c55:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","56:1:0:=c55:1:0+c55:4:0-(c55:6:0===null?c55:5:0:c55:6:0)","56:2:0:=c55:2:0-1","56:3:0:=c56:1:0/c56:2:0","56:4:0:=c56:1:0*c$1:7:0/100","56:5:0:=Math.round(c56:3:0+c56:4:0)","57:0:0:=new Date(c56:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","57:1:0:=c56:1:0+c56:4:0-(c56:6:0===null?c56:5:0:c56:6:0)","57:2:0:=c56:2:0-1","57:3:0:=c57:1:0/c57:2:0","57:4:0:=c57:1:0*c$1:7:0/100","57:5:0:=Math.round(c57:3:0+c57:4:0)","58:0:0:=new Date(c57:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","58:1:0:=c57:1:0+c57:4:0-(c57:6:0===null?c57:5:0:c57:6:0)","58:2:0:=c57:2:0-1","58:3:0:=c58:1:0/c58:2:0","58:4:0:=c58:1:0*c$1:7:0/100","58:5:0:=Math.round(c58:3:0+c58:4:0)","59:0:0:=new Date(c58:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","59:1:0:=c58:1:0+c58:4:0-(c58:6:0===null?c58:5:0:c58:6:0)","59:2:0:=c58:2:0-1","59:3:0:=c59:1:0/c59:2:0","59:4:0:=c59:1:0*c$1:7:0/100","59:5:0:=Math.round(c59:3:0+c59:4:0)","60:0:0:=new Date(c59:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","60:1:0:=c59:1:0+c59:4:0-(c59:6:0===null?c59:5:0:c59:6:0)","60:2:0:=c59:2:0-1","60:3:0:=c60:1:0/c60:2:0","60:4:0:=c60:1:0*c$1:7:0/100","60:5:0:=Math.round(c60:3:0+c60:4:0)","61:0:0:=new Date(c60:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","61:1:0:=c60:1:0+c60:4:0-(c60:6:0===null?c60:5:0:c60:6:0)","61:2:0:=c60:2:0-1","61:3:0:=c61:1:0/c61:2:0","61:4:0:=c61:1:0*c$1:7:0/100","61:5:0:=Math.round(c61:3:0+c61:4:0)","62:0:0:=new Date(c61:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","62:1:0:=c61:1:0+c61:4:0-(c61:6:0===null?c61:5:0:c61:6:0)","62:2:0:=c61:2:0-1","62:3:0:=c62:1:0/c62:2:0","62:4:0:=c62:1:0*c$1:7:0/100","62:5:0:=Math.round(c62:3:0+c62:4:0)","63:0:0:=new Date(c62:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","63:1:0:=c62:1:0+c62:4:0-(c62:6:0===null?c62:5:0:c62:6:0)","63:2:0:=c62:2:0-1","63:3:0:=c63:1:0/c63:2:0","63:4:0:=c63:1:0*c$1:7:0/100","63:5:0:=Math.round(c63:3:0+c63:4:0)","64:0:0:=new Date(c63:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","64:1:0:=c63:1:0+c63:4:0-(c63:6:0===null?c63:5:0:c63:6:0)","64:2:0:=c63:2:0-1","64:3:0:=c64:1:0/c64:2:0","64:4:0:=c64:1:0*c$1:7:0/100","64:5:0:=Math.round(c64:3:0+c64:4:0)","65:0:0:=new Date(c64:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","65:1:0:=c64:1:0+c64:4:0-(c64:6:0===null?c64:5:0:c64:6:0)","65:2:0:=c64:2:0-1","65:3:0:=c65:1:0/c65:2:0","65:4:0:=c65:1:0*c$1:7:0/100","65:5:0:=Math.round(c65:3:0+c65:4:0)","66:0:0:=new Date(c65:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","66:1:0:=c65:1:0+c65:4:0-(c65:6:0===null?c65:5:0:c65:6:0)","66:2:0:=c65:2:0-1","66:3:0:=c66:1:0/c66:2:0","66:4:0:=c66:1:0*c$1:7:0/100","66:5:0:=Math.round(c66:3:0+c66:4:0)","67:0:0:=new Date(c66:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","67:1:0:=c66:1:0+c66:4:0-(c66:6:0===null?c66:5:0:c66:6:0)","67:2:0:=c66:2:0-1","67:3:0:=c67:1:0/c67:2:0","67:4:0:=c67:1:0*c$1:7:0/100","67:5:0:=Math.round(c67:3:0+c67:4:0)","68:0:0:=new Date(c67:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","68:1:0:=c67:1:0+c67:4:0-(c67:6:0===null?c67:5:0:c67:6:0)","68:2:0:=c67:2:0-1","68:3:0:=c68:1:0/c68:2:0","68:4:0:=c68:1:0*c$1:7:0/100","68:5:0:=Math.round(c68:3:0+c68:4:0)","69:0:0:=new Date(c68:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","69:1:0:=c68:1:0+c68:4:0-(c68:6:0===null?c68:5:0:c68:6:0)","69:2:0:=c68:2:0-1","69:3:0:=c69:1:0/c69:2:0","69:4:0:=c69:1:0*c$1:7:0/100","69:5:0:=Math.round(c69:3:0+c69:4:0)","70:0:0:=new Date(c69:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","70:1:0:=c69:1:0+c69:4:0-(c69:6:0===null?c69:5:0:c69:6:0)","70:2:0:=c69:2:0-1","70:3:0:=c70:1:0/c70:2:0","70:4:0:=c70:1:0*c$1:7:0/100","70:5:0:=Math.round(c70:3:0+c70:4:0)","71:0:0:=new Date(c70:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","71:1:0:=c70:1:0+c70:4:0-(c70:6:0===null?c70:5:0:c70:6:0)","71:2:0:=c70:2:0-1","71:3:0:=c71:1:0/c71:2:0","71:4:0:=c71:1:0*c$1:7:0/100","71:5:0:=Math.round(c71:3:0+c71:4:0)","72:0:0:=new Date(c71:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","72:1:0:=c71:1:0+c71:4:0-(c71:6:0===null?c71:5:0:c71:6:0)","72:2:0:=c71:2:0-1","72:3:0:=c72:1:0/c72:2:0","72:4:0:=c72:1:0*c$1:7:0/100","72:5:0:=Math.round(c72:3:0+c72:4:0)","73:0:0:=new Date(c72:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","73:1:0:=c72:1:0+c72:4:0-(c72:6:0===null?c72:5:0:c72:6:0)","73:2:0:=c72:2:0-1","73:3:0:=c73:1:0/c73:2:0","73:4:0:=c73:1:0*c$1:7:0/100","73:5:0:=Math.round(c73:3:0+c73:4:0)","74:0:0:=new Date(c73:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","74:1:0:=c73:1:0+c73:4:0-(c73:6:0===null?c73:5:0:c73:6:0)","74:2:0:=c73:2:0-1","74:3:0:=c74:1:0/c74:2:0","74:4:0:=c74:1:0*c$1:7:0/100","74:5:0:=Math.round(c74:3:0+c74:4:0)","75:0:0:=new Date(c74:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","75:1:0:=c74:1:0+c74:4:0-(c74:6:0===null?c74:5:0:c74:6:0)","75:2:0:=c74:2:0-1","75:3:0:=c75:1:0/c75:2:0","75:4:0:=c75:1:0*c$1:7:0/100","75:5:0:=Math.round(c75:3:0+c75:4:0)","76:0:0:=new Date(c75:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","76:1:0:=c75:1:0+c75:4:0-(c75:6:0===null?c75:5:0:c75:6:0)","76:2:0:=c75:2:0-1","76:3:0:=c76:1:0/c76:2:0","76:4:0:=c76:1:0*c$1:7:0/100","76:5:0:=Math.round(c76:3:0+c76:4:0)","77:0:0:=new Date(c76:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","77:1:0:=c76:1:0+c76:4:0-(c76:6:0===null?c76:5:0:c76:6:0)","77:2:0:=c76:2:0-1","77:3:0:=c77:1:0/c77:2:0","77:4:0:=c77:1:0*c$1:7:0/100","77:5:0:=Math.round(c77:3:0+c77:4:0)","78:0:0:=new Date(c77:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","78:1:0:=c77:1:0+c77:4:0-(c77:6:0===null?c77:5:0:c77:6:0)","78:2:0:=c77:2:0-1","78:3:0:=c78:1:0/c78:2:0","78:4:0:=c78:1:0*c$1:7:0/100","78:5:0:=Math.round(c78:3:0+c78:4:0)","79:0:0:=new Date(c78:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","79:1:0:=c78:1:0+c78:4:0-(c78:6:0===null?c78:5:0:c78:6:0)","79:2:0:=c78:2:0-1","79:3:0:=c79:1:0/c79:2:0","79:4:0:=c79:1:0*c$1:7:0/100","79:5:0:=Math.round(c79:3:0+c79:4:0)","80:0:0:=new Date(c79:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","80:1:0:=c79:1:0+c79:4:0-(c79:6:0===null?c79:5:0:c79:6:0)","80:2:0:=c79:2:0-1","80:3:0:=c80:1:0/c80:2:0","80:4:0:=c80:1:0*c$1:7:0/100","80:5:0:=Math.round(c80:3:0+c80:4:0)","81:0:0:=new Date(c80:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","81:1:0:=c80:1:0+c80:4:0-(c80:6:0===null?c80:5:0:c80:6:0)","81:2:0:=c80:2:0-1","81:3:0:=c81:1:0/c81:2:0","81:4:0:=c81:1:0*c$1:7:0/100","81:5:0:=Math.round(c81:3:0+c81:4:0)","82:0:0:=new Date(c81:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","82:1:0:=c81:1:0+c81:4:0-(c81:6:0===null?c81:5:0:c81:6:0)","82:2:0:=c81:2:0-1","82:3:0:=c82:1:0/c82:2:0","82:4:0:=c82:1:0*c$1:7:0/100","82:5:0:=Math.round(c82:3:0+c82:4:0)","83:0:0:=new Date(c82:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","83:1:0:=c82:1:0+c82:4:0-(c82:6:0===null?c82:5:0:c82:6:0)","83:2:0:=c82:2:0-1","83:3:0:=c83:1:0/c83:2:0","83:4:0:=c83:1:0*c$1:7:0/100","83:5:0:=Math.round(c83:3:0+c83:4:0)","84:0:0:=new Date(c83:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","84:1:0:=c83:1:0+c83:4:0-(c83:6:0===null?c83:5:0:c83:6:0)","84:2:0:=c83:2:0-1","84:3:0:=c84:1:0/c84:2:0","84:4:0:=c84:1:0*c$1:7:0/100","84:5:0:=Math.round(c84:3:0+c84:4:0)","85:0:0:=new Date(c84:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","85:1:0:=c84:1:0+c84:4:0-(c84:6:0===null?c84:5:0:c84:6:0)","85:2:0:=c84:2:0-1","85:3:0:=c85:1:0/c85:2:0","85:4:0:=c85:1:0*c$1:7:0/100","85:5:0:=Math.round(c85:3:0+c85:4:0)","86:0:0:=new Date(c85:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","86:1:0:=c85:1:0+c85:4:0-(c85:6:0===null?c85:5:0:c85:6:0)","86:2:0:=c85:2:0-1","86:3:0:=c86:1:0/c86:2:0","86:4:0:=c86:1:0*c$1:7:0/100","86:5:0:=Math.round(c86:3:0+c86:4:0)","87:0:0:=new Date(c86:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","87:1:0:=c86:1:0+c86:4:0-(c86:6:0===null?c86:5:0:c86:6:0)","87:2:0:=c86:2:0-1","87:3:0:=c87:1:0/c87:2:0","87:4:0:=c87:1:0*c$1:7:0/100","87:5:0:=Math.round(c87:3:0+c87:4:0)","88:0:0:=new Date(c87:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","88:1:0:=c87:1:0+c87:4:0-(c87:6:0===null?c87:5:0:c87:6:0)","88:2:0:=c87:2:0-1","88:3:0:=c88:1:0/c88:2:0","88:4:0:=c88:1:0*c$1:7:0/100","88:5:0:=Math.round(c88:3:0+c88:4:0)","89:0:0:=new Date(c88:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","89:1:0:=c88:1:0+c88:4:0-(c88:6:0===null?c88:5:0:c88:6:0)","89:2:0:=c88:2:0-1","89:3:0:=c89:1:0/c89:2:0","89:4:0:=c89:1:0*c$1:7:0/100","89:5:0:=Math.round(c89:3:0+c89:4:0)","90:0:0:=new Date(c89:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","90:1:0:=c89:1:0+c89:4:0-(c89:6:0===null?c89:5:0:c89:6:0)","90:2:0:=c89:2:0-1","90:3:0:=c90:1:0/c90:2:0","90:4:0:=c90:1:0*c$1:7:0/100","90:5:0:=Math.round(c90:3:0+c90:4:0)","91:0:0:=new Date(c90:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","91:1:0:=c90:1:0+c90:4:0-(c90:6:0===null?c90:5:0:c90:6:0)","91:2:0:=c90:2:0-1","91:3:0:=c91:1:0/c91:2:0","91:4:0:=c91:1:0*c$1:7:0/100","91:5:0:=Math.round(c91:3:0+c91:4:0)","92:0:0:=new Date(c91:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","92:1:0:=c91:1:0+c91:4:0-(c91:6:0===null?c91:5:0:c91:6:0)","92:2:0:=c91:2:0-1","92:3:0:=c92:1:0/c92:2:0","92:4:0:=c92:1:0*c$1:7:0/100","92:5:0:=Math.round(c92:3:0+c92:4:0)","93:0:0:=new Date(c92:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","93:1:0:=c92:1:0+c92:4:0-(c92:6:0===null?c92:5:0:c92:6:0)","93:2:0:=c92:2:0-1","93:3:0:=c93:1:0/c93:2:0","93:4:0:=c93:1:0*c$1:7:0/100","93:5:0:=Math.round(c93:3:0+c93:4:0)","94:0:0:=new Date(c93:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","94:1:0:=c93:1:0+c93:4:0-(c93:6:0===null?c93:5:0:c93:6:0)","94:2:0:=c93:2:0-1","94:3:0:=c94:1:0/c94:2:0","94:4:0:=c94:1:0*c$1:7:0/100","94:5:0:=Math.round(c94:3:0+c94:4:0)","95:0:0:=new Date(c94:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","95:1:0:=c94:1:0+c94:4:0-(c94:6:0===null?c94:5:0:c94:6:0)","95:2:0:=c94:2:0-1","95:3:0:=c95:1:0/c95:2:0","95:4:0:=c95:1:0*c$1:7:0/100","95:5:0:=Math.round(c95:3:0+c95:4:0)","96:0:0:=new Date(c95:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","96:1:0:=c95:1:0+c95:4:0-(c95:6:0===null?c95:5:0:c95:6:0)","96:2:0:=c95:2:0-1","96:3:0:=c96:1:0/c96:2:0","96:4:0:=c96:1:0*c$1:7:0/100","96:5:0:=Math.round(c96:3:0+c96:4:0)","97:0:0:=new Date(c96:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","97:1:0:=c96:1:0+c96:4:0-(c96:6:0===null?c96:5:0:c96:6:0)","97:2:0:=c96:2:0-1","97:3:0:=c97:1:0/c97:2:0","97:4:0:=c97:1:0*c$1:7:0/100","97:5:0:=Math.round(c97:3:0+c97:4:0)","98:0:0:=new Date(c97:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","98:1:0:=c97:1:0+c97:4:0-(c97:6:0===null?c97:5:0:c97:6:0)","98:2:0:=c97:2:0-1","98:3:0:=c98:1:0/c98:2:0","98:4:0:=c98:1:0*c$1:7:0/100","98:5:0:=Math.round(c98:3:0+c98:4:0)","99:0:0:=new Date(c98:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","99:1:0:=c98:1:0+c98:4:0-(c98:6:0===null?c98:5:0:c98:6:0)","99:2:0:=c98:2:0-1","99:3:0:=c99:1:0/c99:2:0","99:4:0:=c99:1:0*c$1:7:0/100","99:5:0:=Math.round(c99:3:0+c99:4:0)","100:0:0:=new Date(c99:0:0.getTime()+1000*60*60*24*365.25/c$1:4:0)","100:1:0:=c99:1:0+c99:4:0-(c99:6:0===null?c99:5:0:c99:6:0)"]`;
}
function controls(sheet,tabledriver) {
var controls = document.createElement('div');
controls.classList.add('controls');
var saveloadbox = document.createElement('textarea');
controls.saveloadbox=saveloadbox;
saveloadbox.classList.add('saveloadbox');
var save = document.createElement('a');
save.innerText='[save]';
save.addEventListener('click',()=>{
saveloadbox.value=JSON.stringify(sheet.history);
saveloadbox.select();
saveloadbox.setSelectionRange(0, 99999);
document.execCommand("copy");
alert("Copied to clipbord");
});
var load = document.createElement('a');
load.innerText='[load]';
function reloadwithtext(text) {
var loadcontent = text?JSON.parse(text):[];
var [x,y,z]=dimforhistory(loadcontent);
console.log(x,y,z);
sheet = createnewsheet(x,y,z);
tabledriver.remove();
tabledriver = driver(sheet);
controls.parentElement.insertBefore(tabledriver,controls.nextElementSibling);
applyhistorytosheet(sheet,loadcontent);
}
load.addEventListener('click',()=>reloadwithtext(saveloadbox.value));
var importa = document.createElement('a');
importa.innerText='[import file]';
importa.addEventListener('click',()=>{
var fi = document.createElement('input');
fi.type='file';
fi.onchange=()=>{
console.log('change happened');
window.file=fi.files[0];
fi.files[0].text().then(text=>{
console.log('We have text',text);
saveloadbox.value=text;
reloadwithtext(text);
});
};
fi.click();
});
var exporta = document.createElement('a');
exporta.innerText='[export file]';
exporta.addEventListener('click',()=>pushdownload(JSON.stringify(sheet.history),'sheet.3dspread3'));
var csavea = document.createElement('a');
csavea.innerText = '[save to cloud]';
csavea.addEventListener('click',()=>{
var overlayc=document.createElement('div');
removeonclick(overlayc);
overlayc.classList.add('overlayc');
var saveinput=document.createElement('input');
saveinput.placeholder='Save name';
if(location.pathname.includes('/doc/')) {
saveinput.value=location.pathname.split('/doc/').pop();
}
overlayc.appendChild(saveinput);
document.body.appendChild(overlayc);
saveinput.focus();
saveinput.addEventListener('keypress',e=>{
if(e.keyCode==13) {
savedocument(saveinput.value,sheet.history,err=>{
if(err) alert(err);
overlayc.remove();
});
}
});
});
var cloada = document.createElement('a');
cloada.innerText = '[load from cloud]';
cloada.addEventListener('click',()=>{
var overlayc=document.createElement('div');
removeonclick(overlayc);
overlayc.classList.add('overlayc');
document.body.appendChild(overlayc);
getdocumentlist((err,list)=>{
list.forEach(i=>{
var option=document.createElement('a');
option.classList.add('option');
var ospan=document.createElement('span');
ospan.innerText=i;
var close=document.createElement('span');
close.classList.add('close');
close.innerText='x';
option.appendChild(ospan);
option.appendChild(close);
option.href='/app/3dspread3/doc/'+i;
option.target='_blank';
overlayc.appendChild(option);
close.addEventListener('click',e=>{
e.preventDefault();
var overlayc2 = document.createElement('div');
removeonclick(overlayc2);
overlayc2.classList.add('overlayc');
overlayc2.classList.add('overlayc2');
window.overlayc2 = overlayc2;
var confirm = document.createElement('a');
confirm.innerText='Are you sure?';
confirm.classList.add('option');
overlayc2.appendChild(confirm);
document.body.appendChild(overlayc2);
confirm.addEventListener('click',e=>{
e.preventDefault();
removedocument(i,()=>{
option.remove();
overlayc2.remove();
});
return false;
});
return false;
});
});
});
});
var colab = document.createElement('a');
colab.innerText = '[colab]';
colab.addEventListener('click',()=>{
var overlayc=document.createElement('div');
removeonclick(overlayc);
overlayc.classList.add('overlayc');
var create = document.createElement('a');
create.classList.add('option');
create.innerText='Create';
var join = document.createElement('a');
join.classList.add('option');
join.innerText='Join';
overlayc.appendChild(create);
overlayc.appendChild(join);
document.body.appendChild(overlayc);
create.addEventListener('click',()=>{
create.remove();
join.remove();
var createinput=document.createElement('input');
createinput.placeholder='Room key';
createinput.value=randbs58id(10);
overlayc.appendChild(createinput);
createinput.focus();
createinput.addEventListener('keypress',e=>{
if(e.keyCode==13) {
var roomkey='3dspread3/'+createinput.value;
var ws = new WebSocket(location.protocol.replace('http','ws')+'//'+location.host+'/crcreate/'+roomkey);
window.ws=ws;
ws.onopen = ()=>{
addcolab(window.user+'/'+createinput.value);
ws.send(JSON.stringify({cmd:'getall'}));
}
ws.onmessage = message=>{
console.log('message',message);
message = JSON.parse(message.data);
message = [].concat(message).map(m=>m.msg);
applyhistorytosheet(sheet,message);
}
var explaindiv=document.createElement('div');
explaindiv.innerText='Room URL';
overlayc.insertBefore(explaindiv,createinput);
createinput.value=window.user+'/'+createinput.value;
overlayc.addEventListener('click',()=>overlayc.remove());
createinput.select();
createinput.setSelectionRange(0, 99999);
document.execCommand("copy");
alert("Copied to clipbord");
}
});
});
join.addEventListener('click',()=>{
create.remove();
join.remove();
var joininput=document.createElement('input');
joininput.placeholder='Room key';
overlayc.appendChild(joininput);
joininput.focus();
joininput.addEventListener('keypress',e=>{
if(e.keyCode==13) {
overlayc.remove();
var [roomowner,roomkey] = joininput.value.split('/');
roomkey=roomowner+'/3dspread3/'+roomkey;
var ws = new WebSocket(location.protocol.replace('http','ws')+'//'+location.host+'/crjoin/'+roomkey);
window.ws=ws;
ws.onopen = ()=>{
addcolab(joininput);
ws.send(JSON.stringify({cmd:'getall'}));
}
ws.onmessage = message=>{
console.log('message',message);
message = JSON.parse(message.data);
message = [].concat(message).map(m=>m.msg);
applyhistorytosheet(sheet,message);
}
}
});
});
});
var templatemenu=document.createElement('a');
templatemenu.innerText='[use template]';
templatemenu.addEventListener('click',()=>{
var overlayc=document.createElement('div');
removeonclick(overlayc);
overlayc.classList.add('overlayc');
var uitemplatelist=document.createElement('div');
uitemplatelist.classList.add('uitemplatelist');
templatelist().forEach(templatename=>{
var templatelink=document.createElement('a');
templatelink.innerText=templatename;
templatelink.addEventListener('click',()=>{
saveloadbox.value=window['template_'+templatename]();
load.click();
overlayc.remove();
});
uitemplatelist.appendChild(templatelink);
});
overlayc.appendChild(uitemplatelist);
document.body.appendChild(overlayc);
});
var setserver=document.createElement('a');
setserver.innerText='[set js provider]';
setserver.addEventListener('click',()=>{
var overlayc=document.createElement('div');
removeonclick(overlayc);
overlayc.classList.add('overlayc');
var remoteserveri=document.createElement('input');
remoteserveri.placeholder='Remote server url';
remoteserveri.addEventListener('keypress',e=>{
if(e.keyCode==13) {
window.jsserver = remoteserveri.value;
overlayc.remove();
}
});
overlayc.appendChild(remoteserveri);
document.body.appendChild(overlayc);
});
var sortb = document.createElement('a');
sortb.innerText='[sort]';
var sortoverlayc=null;
var sortrange=null;
sortb.addEventListener('click',()=>{
//if(sortoverlayc) {
// return document.body.append(sortoverlayc);
//}
sortrange=contiguousrange(sheet,textarea.activetd.x,textarea.activetd.y,sheet.z);
var overlayc=document.createElement('div');
sortoverlayc=overlayc;
var overlayi=document.createElement('form');
overlayc.append(overlayi);
removeonclick(overlayc);
overlayc.classList.add('overlayc');
overlayi.classList.add('overlayi');
var rowcolumnselect=document.createElement('div');
rowcolumnselect.innerText="Sort: ";
var columnr=document.createElement('input');
columnr.type='radio';
columnr.name='rowcolumn';
columnr.value='column';
var rowr=document.createElement('input');
rowr.type='radio';
rowr.checked=true;
rowr.name='rowcolumn';
rowr.value='row';
rowcolumnselect.append(rowr);
rowcolumnselect.append('Row');
rowcolumnselect.append(columnr);
rowcolumnselect.append('Column');
var viewdataselect=document.createElement('div');
viewdataselect.innerText='Order: ';
var datar=document.createElement('input');
datar.type='radio';
datar.checked='true';
datar.name='viewdata';
datar.value='data';
var viewr=document.createElement('input');
viewr.type='radio';
viewr.name='viewdata';
viewr.value='view';
var viewrtitle=document.createElement('span');
viewrtitle.innerText='Rows';
viewdataselect.append(datar);
viewdataselect.append('Data');
viewdataselect.append(viewr);
viewdataselect.append(viewrtitle);
var sortbutton=document.createElement('button');
sortbutton.innerText='Sort!';
sortbutton.style.display='none';
var sortlinesdiv = document.createElement('div');
console.log('sortrange',sortrange);
createsortline(sortrange[1],sortrange[4],sortlinesdiv,sortbutton);
overlayi.append(rowcolumnselect);
overlayi.append(viewdataselect);
overlayi.append(sortlinesdiv);
overlayc.append(sortbutton);
document.body.append(overlayc);
rowr.addEventListener('click',()=>viewrtitle.innerText='Rows');
columnr.addEventListener('click',()=>viewrtitle.innerText='Columns');
sortbutton.addEventListener('click',()=>{
var order=[];
for(var x=sortrange[0];x<=sortrange[3];++x) {
order.push(x); //Fill it initially
}
sortlinesdiv.childNodes.forEach(sortline=>{
var elems=sortline.children;
var column=parseInt(elems[0].value);
if(!column) return;
var mapfunc=elems[1].value;
var compfunc=elems[2].value?eval(elems[2].value):stdcompare;
var array=order.map(row=>sheet[row][column][sheet.z].oc)
console.log('array',array);
if(mapfunc) array=array.map(eval(mapfunc));
console.log('mapped array',array);
order.sort((a,b)=>compfunc(array[a-sortrange[0]],array[b-sortrange[0]]));
console.log('order',order);
var ucarray = order.map((row,index)=>sheet[row].slice(sortrange[1],sortrange[4]+1).map(i=>{
var uc = i[0].uc;
if(uc[0]=='=') {
var offset=index+sortrange[0]-row;
console.log('offset',offset,row,index,sortrange[0]);
uc = translateFormulaSpacially(uc,[offset,0,0]);
}
return uc;
}));
console.log('ucarray',ucarray);
var modified=new Set();
for(var x=sortrange[0];x<=sortrange[3];++x) {
for(var y=sortrange[1];y<=sortrange[4];++y) {
var uc=ucarray[x-sortrange[0]][y-sortrange[1]];
assigntocell(sheet,x,y,sheet.z,ucarray[x-sortrange[0]][y-sortrange[1]]).forEach(m=>modified.add(m));
}
}
renderaltered(modified);
console.log('order',order);
});
overlayc.remove();
});
});
var help = document.createElement('a');
help.classList.add('help');
help.href='https://jssocial.pw/ppkey/fget/3dspread2/upload/w3uWRteRa7.html';
help.target='_blank';
help.innerText='[Help]';
var spacer = document.createElement('span');
spacer.innerText=' ';
[save,load,importa,exporta,csavea,cloada,colab,templatemenu,spacer,setserver,sortb,help].forEach(e=>controls.appendChild(e));
return controls;
}
function get3dspreadCSS() {
return `
#changez {
width:3em;
}
.selectedtd {
border:3px solid #0000ff55;
}
.tmpselectedtd {
border:2px solid #00aaff44;
}
.uitemplatelist {
background:white;
}
.uitemplatelist a {
color:blue;
textdecoration:underline;
cursor:pointer;
}
body {
display:flex;
flex-flow:column;
font-family:helvetica,sans;
font-size:15px;
}
.controls {
display:flex;
flex-flow:row;
}
.controls > * {
cursor:pointer;
}
.help {
margin-left:auto;
}
table {
border-collapse: collapse;
}
td {
margin:0;
padding:0;
width:256px;
border:1px solid #0003;
line-height: 24px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
thead td {
text-align:center;
background: #0453;
font-weight:700;
}
.rhead {
text-align:center;
padding:0 6px;
width:auto;
background: #0452;
}
.corner {
width:auto;
background:#fff;
}
.cellinput {
resize:none;
margin:-1px 0 0 -1px;
box-sizing:border-box;
}
.formulabar {
display:flex;
align-items:center;
}
.formulabar > textarea {
resize:none;
box-sizing:border-box;
width:100%;
height:2.3em;
padding:0.4em;
}
.saveloadbox {
margin-right:16px;
height:8em;
}
td.adder {
width:15px;
line-height:15px;
cursor:pointer;
}
.overlayc {
position: absolute;
top: 0;
left: 0;
background: #0004;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
flex-wrap:wrap;
}
.overlayi {
display: flex;
flex-flow:column;
padding:15px;
background:white;
border-radius:4px;
border:1px solid black;
}
.option {
font-weight:700;
font-size:18px;
padding:8px;
background:#8b90dd;
border-radius:32px;
border:1.5px solid #dddbdb;
margin:8px;
cursor:pointer;
}
.close {
margin-left:8px;
color:black;
text-decoration:none;
}
`
}
function createnewsheet(x,y,z) {
x=x||10;
y=y||10;
z=z||1;
var retr=new Array(x);
for(var xi=0;xi<x;++xi) {
retr[xi]=new Array(y);
for(var yi=0;yi<y;++yi) {
retr[xi][yi]=new Array(z);
for(var zi=0;zi<z;++zi) {
retr[xi][yi][zi]={uc:"",oc:null,up:new Set(),down:new Set(),location:{x:xi,y:yi,z:zi,a:`${xi}:${yi}:${zi}`}};
}
}
}
retr.history=[];
return retr;
}
function sum(list) {
return list.reduce((a,b)=>a+b);
}
function median(list) {
var sorted = list.sort();
var index = list.length/2-0.5;
return (sorted[Math.floor(index)]+sorted[Math.ceil(index)])/2;
}
function min(list) {
var min=Infinity;
list.forEach(i=>{
if(i<min) {
min=i;
}
});
return min;
}
function max(list) {
var min=-Infinity;
list.forEach(i=>{
if(i>min) {
min=i;
}
});
return min;
}
function maxindex(list) {
var max=-Infinity
var idx=-1;
list.forEach((v,i)=>{
if(v>max) {
max=v;
idx=i;
}
});
return idx;
}
function E(cmd) {
if(window.jsserver) {
var xmlr=new XMLHttpRequest();
xmlr.open('GET',window.jsserver+'/'+cmd,false);
xmlr.send();
return JSON.parse(xmlr.responseText);
}
else {
return eval(cmd);
}
}
function contiguousrange(sheet,x,y,z) {
var minx=x;
var miny=y;
var minz=z;
var maxx=x;
var maxy=y;
var maxz=z;
var didexpand=true;
while(didexpand) {
didexpand=false;
var test;
//Expand up
outminx:
if(minx-1>=0) {
for(var sy=miny;sy<=maxy;++sy) {
for(var sz=minz;sz<=maxz;++sz) {
if(sheet[minx-1][sy][sz].oc!==null) {
--minx;
didexpand=true;
break outminx;
}
}
}
}
//Expand down
outmaxx:
if(maxx+1<sheet.length) {
for(var sy=miny;sy<=maxy;++sy) {
for(var sz=minz;sz<=maxz;++sz) {
if(sheet[maxx+1][sy][sz].oc!==null) {
++maxx;
didexpand=true;
break outmaxx;
}
}
}
}
//Expand left
outminy:
if(miny-1>=0) {
for(var sx=minx;sx<=maxx;++sx) {
for(var sz=minz;sz<=maxz;++sz) {
if(sheet[sx][miny-1][sz].oc!==null) {
--miny;
didexpand=true;
break outminy;
}
}
}
}
//Expand right
outmaxy:
if(maxy+1<sheet[0].length) {
for(var sx=minx;sx<=maxx;++sx) {
for(var sz=minz;sz<=maxz;++sz) {
if(sheet[sx][maxy+1][sz].oc!==null) {
++maxy;
didexpand=true;
break outmaxy;
}
}
}
}
//Expand in
outminz:
if(minz-1>=0) {
for(var sx=minx;sx<=maxx;++sx) {
for(var sy=miny;sy<=maxy;++sy) {
if(sheet[sx][sy][minz-1].oc!==null) {
--minz;
didexpand=true;
break outminz;
}
}
}
}
//Expand out
outmaxz:
if(maxz+1<sheet[0][0].length) {
for(var sx=minx;sx<=maxx;++sx) {
for(var sy=miny;sy<=maxy;++sy) {
if(sheet[sx][sy][maxz+1].oc!==null) {
++maxz;
didexpand=true;
break outmaxz;
}
}
}
}
}
return [minx,miny,minz,maxx,maxy,maxz];
}
function assigntocellhelper(sheet,cell,uc,lockset,willrecalc,isfirst) {
if(lockset.has(cell)) return lockset;
lockset.add(cell);
if(!isfirst) {
cell.up.forEach(parent=>{
if(willrecalc.has(parent)) {
assigntocellhelper(sheet,parent,parent.uc,lockset,willrecalc);
}
});
}
cell.uc=uc;
cell.up.forEach(u=>u.down.delete(cell));
cell.up=new Set();
var oc=null;
if(uc=='') {
cell.oc=null;
}
else if(uc[0]=="=") {
//This is a formula
var rregexp = /c\$?([0-9]+):\$?([0-9]+):\$?([0-9]+)c\$?([0-9]+):\$?([0-9]+):\$?([0-9]+)/g; //This is a regex for a range
var erregexp = /c\$?([0-9]+):\$?([0-9]+):\$?([0-9]+)([udlrio])/g; //Auto expand range up
var cregexp = /c\$?([0-9]+):\$?([0-9]+):\$?([0-9]+)/g; //This is a regex for a non-range address
var suc=uc.slice(1);
var cmd=suc;
(cmd.match(rregexp)||[]).forEach(range=>{ //translate range into javascript
var [x1,y1,z1,x2,y2,z2]=range.slice(1).replace('c',':').split(':').map(i=>{
if(i[0]=='$') return parseInt(i.slice(1));
return parseInt(i);
});
console.log(x1,y1,z1,x2,y2,z2);
var expressionparts=[];
for(var xi=x1;xi<=x2;++xi) {
for(var yi=y1;yi<=y2;++yi) {
for(var zi=z1;zi<=z2;++zi) {
expressionparts.push(`sheet[${xi}][${yi}][${zi}].oc`);
var link = sheet[xi][yi][zi];
cell.up.add(link);
link.down.add(cell);
}
}
}
cmd=cmd.replace(range,'['+expressionparts.join(',')+']');
});
(cmd.match(erregexp)||[]).forEach(range=>{
var d=range.slice(-1);
var [y,x,z]=range.slice(1,-1).split(':');
console.log({y,x,z});
var expressionparts=[];
if(d=='d') {
for(y=y;y<sheet.length&&sheet[y][x][z].uc;++y) {
expressionparts.push(`sheet[${y}][${x}][${z}].oc`);
var link=sheet[y][x][z];
cell.up.add(link);
link.down.add(cell);
}
}
if(d=='u') {
for(y=y;y>=0&&sheet[y][x][z].uc;--y) {
expressionparts.push(`sheet[${y}][${x}][${z}].oc`);
var link=sheet[y][x][z];
cell.up.add(link);
link.down.add(cell);
}
}
if(d=='l') {
for(x=x;x>=0&&sheet[y][x][z].uc;--x) {
expressionparts.push(`sheet[${y}][${x}][${z}].oc`);
var link=sheet[y][x][z];
cell.up.add(link);
link.down.add(cell);
}
}
if(d=='r') {
for(x=x;x<sheet[0].length&&sheet[y][x][z].uc;++x) {
expressionparts.push(`sheet[${y}][${x}][${z}].oc`);
var link=sheet[y][x][z];
cell.up.add(link);
link.down.add(cell);
}
}
if(d=='i') {
for(z=z;z>=0&&sheet[y][x][z].uc;--z) {
expressionparts.push(`sheet[${y}][${x}][${z}].oc`);
var link=sheet[y][x][z];
cell.up.add(link);
link.down.add(cell);
}
}
if(d=='o') {
for(z=z;z<sheet[0][0].length&&sheet[y][x][z].uc;++z) {
expressionparts.push(`sheet[${y}][${x}][${z}].oc`);
var link=sheet[y][x][z];
cell.up.add(link);
link.down.add(cell);
}
}
//Link one further;
if(y>=0&&x>=0&&z>=0&&y<sheet.length&&x<sheet[0].length&&z<sheet[0][0].length) { //If the one further location is legal
var link=sheet[y][x][z];
cell.up.add(link);
link.down.add(cell);
}
console.log({x,y,z});
cmd=cmd.replace(range,'['+expressionparts.join(',')+']');
});
cmd=cmd.replace(cregexp,"sheet[$1][$2][$3].oc");
console.log('cmd',cmd);
try {
cell.oc = eval(cmd);
}
catch(e) {
console.log('cell err',e);
cell.oc = 'Err';
}
(suc.match(cregexp)||[]).forEach(link=>{ //Translate address into javasciprt
var [lx,ly,lz]=link.slice(1).split(':').map(i=>{
if(i[0]=='$') return parseInt(i.slice(1));
return parseInt(i);
});
var link = sheet[lx][ly][lz];
cell.up.add(link);
link.down.add(cell);
});
}
else {
try {
cell.oc=JSON.parse(uc);
}
catch(e) {
if(uc[0]=="'") {
cell.oc=uc.slice(1);
}
else {
cell.oc=uc;
}
}
}
cell.down.forEach(out=>assigntocellhelper(sheet,out,out.uc,lockset,willrecalc));
return lockset; //Returns what updated
}
function alldown(cell,downset) {
if(downset.has(cell)) return;
downset.add(cell);
cell.down.forEach(sub=>alldown(sub,downset));
return downset;
}
function assigntocell(sheet,x,y,z,uc,blockws) {
var cell = sheet[x][y][z];
if(cell.uc==uc) return new Set(); //Do nothing
var histadd=x+':'+y+':'+z+':'+uc
sheet.history.push(histadd);
if(!blockws && window.ws) {
var message=JSON.stringify({cmd:'msg',msg:histadd});
console.log('sending message',message);
ws.send(JSON.stringify({cmd:"msg",msg:histadd}));
}
var willrecalc = alldown(cell,new Set());
var changed = assigntocellhelper(sheet,cell,uc,new Set(),willrecalc,true);
return changed;
}
function applyhistorytosheet(sheet,history,blockws) {
if(typeof(history)=='string') return applyhistorytosheet(sheet,JSON.parse(history));
var modified=new Set();
history.forEach(h=>{
var [x,y,z,...uc] = h.split(':');
uc=uc.join(':');
try {
assigntocell(sheet,x,y,z,uc,blockws).forEach(cell=>{
modified.add(cell);
});
}
catch(e) {
console.log(e,x,y,z,uc);
}
});
renderaltered(modified);
}
function stringify(dv) {
if(dv===null) return "";
if(dv===Infinity) return "Infinity";
dv=JSON.stringify(dv);
if(dv[0]=='"') dv=dv.slice(1,-1);
return dv;
}
function getSelectedTds() {
if(window.chrome) { //We have to do selection ourselves
return document.querySelectorAll('.selectedtd');
}
//Not chrome so we use the browser's selection
var s=window.getSelection();
var tds=[];
for(var c=0;c<s.rangeCount;++c) {
var range = s.getRangeAt(c);
for(var b=range.startOffset;b<range.endOffset;++b) {
tds.push(range.startContainer.childNodes[b]);
}
}
return tds;
}
function getAboveSelectedTd(td,selectedset) {
var retr=td;
var x=td.x;
var y=td.y;
while(x&&selectedset.has(sheet[x-1][y][sheet.z].td)) {
--x;
retr=sheet[x-1][y][sheet.z].td;
}
return td;
}
function getTopSelectedAbove(td,selectedset) {
var retr=td;
var x=td.x;
var y=td.y;
while(x&&selectedset.has(sheet[x-1][y][sheet.z].td)) {
--x;
retr=sheet[x][y][sheet.z].td;
}
return retr;
}
function getXYZlistForSelection() {
if(window.chrome) { //Not on firefox
var tds=getSelectedTds();
var retr=[];
tds.forEach(td=>retr.push([td.x,td.y,td.z]));
return retr;
}
var s = window.getSelection();
var ranges=[];
for(var c=0;c<s.rangeCount;++c) {
ranges.push(s.getRangeAt(c));
}
return ranges.map(r=>r.cloneContents().childNodes[0]).map(n=>[n.dataset.x,n.dataset.y,n.dataset.z].map(e=>parseInt(e)));
}
function selection2ucarray(sheet) {
var targets = getXYZlistForSelection();
var minX=Infinity;
var minY=Infinity;
var minZ=Infinity;
targets.forEach(t=>{
console.log({t,targets});
t[3]=sheet[t[0]][t[1]][t[2]].uc;
t[4]=stringify(sheet[t[0]][t[1]][t[2]].oc);
if(t[0]<minX) minX=t[0];
if(t[1]<minY) minY=t[1];
if(t[2]<minZ) minZ=t[2];
});
targets.forEach(t=>{
t[0]-=minX;
t[1]-=minY;
t[2]-=minZ;
});
var maxX=-Infinity;
var maxY=-Infinity;
targets.forEach(t=>{
if(t[0]>maxX) maxX=t[0];
if(t[1]>maxY) maxY=t[0];
});
var textgrid=[];
for(var x=0;x<=maxX;++x) {
textgrid[x]=[];
}
console.log({minX,minY,maxX,maxY,textgrid});
targets.forEach(t=>{
console.log({t,minX,minY,sheet,index:t[0]+minX});
textgrid[t[0]][t[1]]=stringify(sheet[t[0]+minX][t[1]+minY][t[2]].oc);
});
textgrid=textgrid.map(r=>r.join('\t')).join('\n');
return [targets,minX,minY,minZ,textgrid];
}
function absoluteOffset(elem) {
var left=0;
var top=0;
while(elem) {
left+=elem.offsetLeft;
top+=elem.offsetTop;
elem=elem.offsetParent;
}
return [left,top];
}
function offsetuc(uc,deltas) {
var regexp = /c(\$?[0-9]+):(\$?[0-9]+):(\$?[0-9]+)/g;
var matchAddresses = uc.match(regexp)||[];
console.log('matchAddresses',matchAddresses);
matchAddresses.forEach(sample=>{
var [ax,ay,az]=sample.slice(1).split(':').map((val,index)=>{
if(val[0]=='$') return val;
return parseInt(val)+deltas[index];
});
uc=uc.replace(sample,`c${ax}:${ay}:${az}`);
});
return uc;
}
function renderaltered(altered) {
console.log('rendering altered',altered);
altered.forEach(cell=>{
if(cell.td) {
var text=stringify(cell.oc);
console.log('rendering',cell,text,cell.oc);
cell.td.innerText=text;
}
});
}
function translateFormulaSpacially(uc,deltas,regexp) {
regexp = regexp || /c(\$?[0-9]+):(\$?[0-9]+):(\$?[0-9]+)/g;
var matchAddresses = uc.match(regexp)||[];
console.log('matchAddresses',matchAddresses);
matchAddresses.forEach(sample=>{
var [ax,ay,az]=sample.slice(1).split(':').map((val,index)=>{
if(val[0]=='$') return val;
return parseInt(val)+deltas[index];
});
uc=uc.replace(sample,`c${ax}:${ay}:${az}`);
});
return uc;
}
function driver(sheet) {
return mirroredformuladriver(sheet);
}
function mirroredformuladriver(sheet) {
var tabledriver=basicdriver(sheet);
var textarea=tabledriver.querySelector('.cellinput');
var retr = document.createElement('div');
var formuladiv=document.createElement('div');
var formulabar=document.createElement('textarea');
formulabar.noblur=true;
formuladiv.classList.add('formulabar');
formuladiv.append('F(x)=',formulabar);
retr.append(formuladiv,tabledriver);
textarea.addEventListener('input',()=>formulabar.value=textarea.value);
formulabar.addEventListener('input',()=>textarea.value=formulabar.value);
formulabar.addEventListener('blur',e=>{
if(e.relatedTarget!=textarea) {
textarea.onblur(e);
//e.preventDefault();
//return false;
}
});
textarea.addEventListener('focus',()=>formulabar.value=textarea.value);
return retr;
}
function basicdriver(sheet) {
sheet = sheet || createnewsheet(20,10,1);
window.sheet=sheet;
var table=document.createElement('table');
var thead=document.createElement('thead');
var theadtr = document.createElement('tr');
var corner = document.createElement('td');
var currentz = 0;
sheet.z = currentz;
corner.classList.add('corner');
theadtr.append(corner);
for(var thy=0;thy<sheet[0].length;++thy) {
var theadtd=document.createElement('td');
theadtd.innerText=thy;
theadtr.append(theadtd);
}
var addcolumn = document.createElement('td');
addcolumn.innerText='+';
addcolumn.classList.add('adder');
theadtr.append(addcolumn);
thead.append(theadtr);
var tbody=document.createElement('tbody');
var recentUCCopy = null;
var recentContentCopy = null;
tbody.oncopy = e=>{
recentUCCopy = selection2ucarray(sheet);
console.log({recentUCCopy});
if(window.chrome) { //We are not firefox
recentContentCopy = recentUCCopy[4];
e.preventDefault();
if(e.clipboardData) {
e.clipboardData.setData('text/plain',recentContentCopy);
}
else if(window.clipboardData) {
e.clipboardData.setData('Text',recentContentCopy);
}
else {
console.log("Custom copy not supported");
}
console.log({recentContentCopy});
return;
}
recentContentCopy = window.getSelection().toString();
}
if(!document.body.deletebinded) {
document.body.deletebinded=true;
document.body.addEventListener('keydown',e=>{
console.log('tbody keydown',e);
if(e.keyCode==8 || e.keyCode==46) { //This is a delete event
console.log('delete event');
var tds = getSelectedTds();
console.log('tds',tds);
var changed=new Set();
tds.forEach(td=>{
assigntocell(sheet,td.x,td.y,sheet.z,"").forEach(cell=>changed.add(cell));
});
changed.forEach(cell=>{
if(cell.td) {
cell.td.innerText=stringify(cell.oc);
}
});
}
});
}
table.appendChild(thead);
table.appendChild(tbody);
var textarea=document.createElement('textarea');
textarea.classList.add('cellinput');
textarea.style.position='absolute';
textarea.style.display='none';
window.textarea=textarea;
var shiftKey=false;
textarea.onkeydown=(e)=>{
console.log(e.keyCode);
if(e.keyCode==16) { //Shift key
shiftKey=true;
e.preventDefault();
return false;
}
if(e.keyCode==13) { //Return key
textarea.blur();
sheet[textarea.activetd.x+1][textarea.activetd.y][sheet.z].td.click();
e.preventDefault();
return false;
}
if(e.keyCode==9) { //Tab key
textarea.blur();
sheet[textarea.activetd.x][textarea.activetd.y+1][sheet.z].td.click();
e.preventDefault();
return false;
}
if(e.keyCode==38 && textarea.selectionEnd==0 && textarea.activetd.x!=0) { //Up key
textarea.blur();
sheet[textarea.activetd.x-1][textarea.activetd.y][sheet.z].td.click();
e.preventDefault();
return false;
}
if(e.keyCode==40 && textarea.selectionStart==textarea.value.length && textarea.activetd.x!=sheet.length-1) { //Down key
textarea.blur();
sheet[textarea.activetd.x+1][textarea.activetd.y][sheet.z].td.click();
e.preventDefault();
return false;
}
if(e.keyCode==37 && textarea.selectionEnd==0 && textarea.activetd.y!=0) { //Left key
textarea.blur();
sheet[textarea.activetd.x][textarea.activetd.y-1][sheet.z].td.click();
e.preventDefault();
return false;
}
if(e.keyCode==39 && textarea.selectionStart==textarea.value.length && textarea.activetd.y!=sheet[0].length-1) { //Right key
textarea.blur();
sheet[textarea.activetd.x][textarea.activetd.y+1][sheet.z].td.click();
e.preventDefault();
return false;
}
}
textarea.onkeyup=(e)=>{
if(e.keyCode==16) {
shiftKey=false;
}
}
textarea.onpaste=e=>{
var paste = (e.clipboardData || window.clipboardData).getData('text');
console.log('paste',paste);
console.log('recentContentCopy',recentContentCopy);
window.c1=paste;
window.c2=recentContentCopy;
if(recentContentCopy&&paste==recentContentCopy.split('\r').join('')) {
console.log('From here','Copy UC');
var x=textarea.activetd.x;
var y=textarea.activetd.y;
var deltas=[x-recentUCCopy[1],y-recentUCCopy[2],sheet.z-recentUCCopy[3]];
var regexp = /c(\$?[0-9]+):(\$?[0-9]+):(\$?[0-9]+)/g;
recentUCCopy[0].forEach(i=>{
console.log(i);
var uc=i[3];
var matchAddresses = uc.match(regexp)||[];
console.log('matchAddresses',matchAddresses);
matchAddresses.forEach(sample=>{
var [ax,ay,az]=sample.slice(1).split(':').map((val,index)=>{
if(val[0]=='$') return val;
return parseInt(val)+deltas[index];
});
uc=uc.replace(sample,`c${ax}:${ay}:${az}`);
});
if(i[0]==0&&i[1]==0) textarea.value=uc;
while(x+i[0]>=sheet.length) {
addrow.click();
}
while(y+i[1]>=sheet[0].length) {
addcolumn.click();
}
assigntocell(sheet,x+i[0],y+i[1],sheet.z,uc);
sheet[x+i[0]][y+i[1]][sheet.z].td.innerText=stringify(sheet[x+i[0]][y+i[1]][sheet.z].oc);
});
e.preventDefault();
}
else {
//Copy from clipboard
var x=textarea.activetd.x;
var y=textarea.activetd.y;
paste.split('\n').forEach((line,xo)=>{
line.split('\t').forEach((uc,yo)=>{
if(xo==0&&yo==0) textarea.value=uc;
while(x+xo>=sheet.length) {
addrow.click();
}
while(y+yo>=sheet[0].length) {
addcolumn.click();
}
assigntocell(sheet,x+xo,y+yo,sheet.z,uc);
sheet[x+xo][y+yo][sheet.z].td.innerText=stringify(sheet[x+xo][y+yo][sheet.z].oc);
});
});
e.preventDefault();
}
}
textarea.onblur=(e)=>{
console.log('blur',e);
if(shiftKey || (e.relatedTarget&&e.relatedTarget.noblur==true)) {
e.preventDefault();
textarea.focus();
console.log('shiftBlur');
return false;
}
textarea.style.display='none';
var targ= textarea.activetd;
var modified = assigntocell(sheet,targ.x,targ.y,sheet.z,textarea.value);
textarea.value="";
renderaltered(modified);
targ.innerText=stringify(sheet[targ.x][targ.y][sheet.z].oc);
console.log(sheet[targ.x][targ.y][sheet.z].oc);
}
var tbodyonmousemove=(e)=>{
if(!window.chrome) return; //Already does what it should
if(!e.ctrlKey) return; //Ctrl key isn't down
if(e.buttons!=1) return; //Our mouse isn't down
var starttd=e.target;
var endtd=starttd;
tbody.onmousemove=null; //Set it to nothing while we are completing the rest of the action
tbody.onmousemove=(e)=>{
endtd=e.target;
document.querySelectorAll('.tmpselectedtd').forEach(e=>e.classList.remove('tmpselectedtd'));
var startx=Math.min(starttd.x,endtd.x);
var endx=Math.max(starttd.x,endtd.x);
var starty=Math.min(starttd.y,endtd.y);
var endy=Math.max(starttd.y,endtd.y);
for(var x=startx;x<=endx;++x) {
for(var y=starty;y<=endy;++y) {
sheet[x][y][sheet.z].td.classList.add('tmpselectedtd');
}
}
};
tbody.onmouseup=(e)=>{ //Action is ending
tbody.onmousemove=tbodyonmousemove;
tbody.onmouseup=null;
console.log({starttd,endtd});
document.querySelectorAll('.tmpselectedtd').forEach(e=>e.classList.remove('tmpselectedtd'));
var startx=Math.min(starttd.x,endtd.x);
var endx=Math.max(starttd.x,endtd.x);
var starty=Math.min(starttd.y,endtd.y);
var endy=Math.max(starttd.y,endtd.y);
for(var x=startx;x<=endx;++x) {
for(var y=starty;y<=endy;++y) {
sheet[x][y][sheet.z].td.classList.add('selectedtd');
}
}
}
};
tbody.onmousemove=tbodyonmousemove;
var onclick=(e)=>{
var targ=e.target;
if(e.shiftKey) {
e.preventDefault();
e.stopPropagation();
console.log('shiftKey');
var insertIndex=textarea.selectionStart;
var insertText=`c${targ.x}:${targ.y}:${targ.z}`
textarea.value=textarea.value.slice(0,insertIndex)+insertText+textarea.value.slice(insertIndex);
textarea.focus();
textarea.selectionEnd=insertIndex+insertText.length;
return false;
}
if(e.ctrlKey) {
console.log("Ctrl-click",e);
if(!window.chrome) return; //This is probably firefox, which already does what it should. Do nothing more.
targ.classList.toggle('selectedtd');
return;
}
textarea.value=sheet[targ.x][targ.y][sheet.z].uc;
var offset=absoluteOffset(targ);
textarea.style.width=targ.offsetWidth+'px';
textarea.style.height=targ.offsetHeight+'px';
textarea.style.left=offset[0]+'px';
textarea.style.top=offset[1]+'px';
textarea.style.display='inline';
textarea.focus();
textarea.activetd=targ;
if(window.chrome) {
document.querySelectorAll('.selectedtd').forEach(e=>e.classList.remove('selectedtd'));
}
}
for(var x=0;x<sheet.length;++x) {
var tr=document.createElement('tr');
var htd=document.createElement('td');
htd.classList.add('rhead');
htd.innerText=x;
tr.append(htd);
tbody.appendChild(tr);
for(var y=0;y<sheet[x].length;++y) {
var td=document.createElement('td');
td.innerText=stringify(sheet[x][y][sheet.z].oc);
tr.appendChild(td);
sheet[x][y][sheet.z].td=td;
td.x=x;
td.y=y;
td.z=sheet.z
td.dataset.x=x;
td.dataset.y=y;
td.dataset.z=sheet.z;
td.onclick=onclick;
td.ondrag=ondrag;
/*input.onblur=(e)=>{
console.log('onblur')
var targ= e.target
var modified = assigntocell(sheet,targ.x,targ.y,0,targ.value);
modified.forEach(cell=>cell.input.value=stringify(cell.oc));
targ.value=stringify(sheet[targ.x][targ.y][0].oc);
console.log(sheet[targ.x][targ.y][0].oc);
};*/
}
}
var tr=document.createElement('tr');
var addrow = document.createElement('td');
var changez = document.createElement('td');
changez.innerText=' z: ';
var changezinput = document.createElement('input');
changezinput.id="changez";
changezinput.value=currentz;
changez.append(changezinput);
addrow.innerText='+';
addrow.classList.add('adder');
addrow.classList.add('rhead');
if(window.chrome) {
changez.addEventListener('click',e=>{
e.preventDefault();
getSelectedTds().forEach(t=>t.classList.remove('selectedtd'));
});
}
changezinput.addEventListener('change',()=>{
var value=parseInt(changezinput.value);
if(isNaN(value) || value==currentz) return;
//We are about to rerender the document;
var oldz=currentz;
currentz=value;
sheet.z=value;
for(var x=0;x<sheet.length;++x) { //Ensure sheet is expanded
for(var y=0;y<sheet[x].length;++y) {
if(!sheet[x][y][currentz]) {
sheet[x][y][currentz]={uc:'',oc:null,up:new Set(),down:new Set(),location:{x,y,z:currentz,a:`${x}:${y}:${currentz}`}};
}
}
}
for(var x=0;x<sheet.length;++x) { //Adjust tds content to reflect content of the new z
for(var y=0;y<sheet[x].length;++y) {
var td=sheet[x][y][oldz].td;
td.z=currentz;
td.dataset.z=currentz;
td.innerText=stringify(sheet[x][y][currentz].oc);
}
}
for(var x=0;x<sheet.length;++x) { //Assign and unassign tds
for(var y=0;y<sheet[x].length;++y) {
var td=sheet[x][y][oldz].td;
sheet[x][y][currentz].td=td;
delete sheet[x][y][oldz].td;
}
}
});
addrow.addEventListener('click',()=>{
var cx=sheet.length;
var cy=sheet[0].length;
var cz=sheet[0][0].length;
var row=[];
sheet.push(row);
for(var y=0;y<cy;++y) {
var log=[];
row.push(log);
for(var z=0;z<cz;++z) {
log.push({uc:"",oc:null,up:new Set(),down:new Set(),location:{x,y,z,a:`${x}:${y}:${z}`}});
}
}
var tr=document.createElement('tr');
var rhead=document.createElement('td');
rhead.innerText=cx;
rhead.classList.add('rhead');
tr.append(rhead);
for(var y=0;y<cy;++y) {
var td=document.createElement('td');
td.innerText=stringify(sheet[cx][y][sheet.z].oc);
tr.appendChild(td);
sheet[cx][y][sheet.z].td=td;
td.x=cx;
td.y=y;
td.z=sheet.z;
td.dataset.x=cx;
td.dataset.y=y;
td.dataset.z=sheet.z;
td.onclick=onclick;
}
tbody.insertBefore(tr,tbody.lastElementChild);
});
addcolumn.addEventListener('click',()=>{
var cx=sheet.length;
var cy=sheet[0].length;
var cz=sheet[0][0].length;
sheet.forEach((row,x)=>{
var log=[];
row.push(log);
for(var z=0;z<cz;++z) {
log.push({uc:"",oc:null,up:new Set(),down:new Set(),location:{x,y:cy,z,a:`${x}:${cy}:${z}`}})
}
});
var headtd=document.createElement('td');
headtd.innerText=cy;
theadtr.insertBefore(headtd,theadtr.lastElementChild);
sheet.forEach((row,x)=>{
var tr=sheet[x][0][sheet.z].td.parentElement;
var td=document.createElement('td');
td.innerText=stringify(sheet[x][cy][sheet.z].oc);
tr.appendChild(td);
sheet[x][cy][sheet.z].td=td;
td.x=x;
td.y=cy;
td.z=sheet.z;
td.dataset.x=x;
td.dataset.y=cy;
td.dataset.z=sheet.z;
td.onclick=onclick;
});
});
tr.append(addrow);
tr.append(changez);
tbody.append(tr);
table.appendChild(textarea);
const INSERT=0;
const NORMAL=1;
var mode=INSERT;
var normalbuffer=[];
var normalcount='';
window.onkeydown=e=>{
if(e.keyCode==27) {
normalbuffer=[];
normalcount='';
mode=NORMAL;
return false;
}
if(e.keyCode==68 && e.ctrlKey) { //Fill down
e.preventDefault();
var altered=new Set();
var tds = getSelectedTds();
console.log('tds',tds);
var tdset = new Set(tds);
tds.forEach(td=>{
var top=getTopSelectedAbove(td,tdset);
if(top==td) return;
console.log(top,td);
var uc=sheet[top.x][top.y][sheet.z].uc;
console.log('from uc',uc);
uc=offsetuc(uc,[td.x-top.x,td.y-top.y,0]); //Those are deltas
console.log('to uc',uc);
assigntocell(sheet,td.x,td.y,sheet.z,uc).forEach(i=>altered.add(i));
});
renderaltered(altered);
}
if(mode==NORMAL) {
if(e.keyCode==123) { //F12
return true; //Don't prevent default
}
e.preventDefault();
console.log('window',e);
var altered=new Set();
if(e.key==='0' && normalcount==='') { //Move to begining
var targettd=sheet[textarea.activetd.x][0][sheet.z].td;
if(targettd) targettd.click();
normalbuffer=[];
normalcount='';
}
else if(e.keyCode>=48 && e.keyCode<=57) { //Adjust normal count
normalcount+=e.key;
console.log('normalcount',normalcount);
}
else { //Wasn't a number
normalbuffer.push(e.key);
}
console.log(parseInt(normalcount)||1,normalbuffer.join(''));
if(e.key=='i'){
normalbuffer=[];
normalcount='';
mode=INSERT;
}
if(e.key=='I') {
var targettd=sheet[textarea.activetd.x][0][sheet.z].td;
if(targettd) {
var wasshiftkey=shiftKey;
shiftKey=false; //Essencially we are not shift-clicking.
textarea.blur();
targettd.click();
shiftKey=wasshiftkey;
}
normalbuffer=[];
normalcount='';
mode=INSERT;
}
if(normalbuffer.join('')=='dd') {
normalcount=parseInt(normalcount)||1;
var x=textarea.activetd.x;
textarea.value='';
for(var c=0;c<normalcount;++c) {
for(var y=0;y<sheet[x].length;++y) {
assigntocell(sheet,x,y,sheet.z,'').forEach(alt=>altered.add(alt));
}
++x;
if(x>=sheet.length) {
break;
}
}
normalbuffer=[];
normalcount='';
}
if(e.key=='x') {
normalcount=parseInt(normalcount)||1;
var x=textarea.activetd.x;
var y=textarea.activetd.y;
console.log('normalcount',normalcount);
textarea.value='';
for(var c=0;c<normalcount;++c) {
assigntocell(sheet,x,y,sheet.z,'').forEach(alt=>altered.add(alt));
++y;
if(y>=sheet[0].length) {
y=0;
++x;
if(x>=sheet.length) {
break;
}
}
}
normalbuffer=[];
normalcount='';
}
if(e.key=='G') {
var wasshiftkey=shiftKey;
shiftKey=false; //Essencially we are not shift-clicking.
var target=Math.min(parseInt(normalcount)||Infinity,sheet.length-1);
sheet[target][0][sheet.z].td.click();
normalbuffer=[];
normalcount='';
shiftKey=wasshiftkey;
}
if(normalbuffer.join('')=='gg') {
var target=Math.max(parseInt(normalcount)||0,0);
textarea.blur();
sheet[target][0][sheet.z].td.click();
normalbuffer=[];
normalcount='';
}
renderaltered(altered);
}
};
return table;
}
function convertarrastringto3dspread(data) {
data = JSON.parse(data);
var [x,y,z]=data;
data = data.slice(3);
var sheet = createnewsheet(x,y,z);
for(var xi=0;xi<x;++xi) {
for(var yi=0;yi<y;++yi) {
for(var zi=0;zi<z;++zi) {
var uc=data.shift();
console.log('uc',uc);
if(uc) {
assigntocell(sheet,xi,yi,zi,uc);
}
}
}
}
return sheet;
}
function convert3dspreadtoucarraystring(sheet) {
var retr=[];
retr.push(sheet.length);
retr.push(sheet[0].length);
retr.push(sheet[0][0].length);
sheet.forEach(r1=>r1.forEach(r2=>r2.forEach(c=>retr.push(c.uc))));
return stringify(retr);
}
function removeonclick(elem) {
elem.addEventListener('click',e=>{
if(e.target==elem) {
console.log(e);
elem.remove();
}
});
}
function reinitializewithdata(data) {
document.body.childNodes.forEach((i,e)=>i.remove());
document.body.appendChild(driver(convertarrastringto3dspread(data)));
}
function pushdownload(text,filename) {
var blob = new Blob([text], {type: "text/plain"});
var url = window.URL.createObjectURL(blob);
var a = document.createElement("a");
a.href = url;
a.download = filename;
a.click();
}
function addcolab(i,cb) {
getcolablist((err,list)=>{
if(list.indexOf(i)!=-1) list=list.filter(a=>a!=i);
list.unshift(i);
writecolablist(list,cb);
});
}
function removecolab(i,cb) {
getcolablist((err,list)=>{
list = list.filter(a=>a!=i);
writecolablist(list,cb);
});
}
function removedocument(i,cb) {
getdocumentlist((err,list)=>{
list = list.filter(a=>a!=i);
writedocumentlist(list,cb);
});
}
function getcolablist(cb) {
var xmlr = new XMLHttpRequest();
xmlr.onreadystatechange=()=>{
if(xmlr.readyState=== XMLHttpRequest.DONE) {
console.log('ready');
if(!xmlr.responseText) {
return cb(null,[]);
}
try {
cb(null,JSON.parse(xmlr.responseText));
}
catch(e) {
cb(e);
}
}
};
xmlr.open('GET','/skey/get/3dspread3/colabs',true);
xmlr.send();
}
function getdocumentlist(cb) {
var xmlr = new XMLHttpRequest();
xmlr.onreadystatechange=()=>{
if(xmlr.readyState=== XMLHttpRequest.DONE) {
console.log('ready');
if(!xmlr.responseText) {
return cb(null,[]);
}
try {
cb(null,JSON.parse(xmlr.responseText));
}
catch(e) {
cb(e);
}
}
};
xmlr.open('GET','/skey/get/3dspread3/documents',true);
xmlr.send();
}
function writecolablist(list,cb) {
var xmlr = new XMLHttpRequest();
xmlr.onreadystatechange=()=>{
if(xmlr.readyState=== XMLHttpRequest.DONE && cb) {
cb();
}
};
xmlr.open('POST','/skey/set/3dspread3/colabs',true);
xmlr.send(JSON.stringify(list));
}
function writedocumentlist(list,cb) {
var xmlr = new XMLHttpRequest();
xmlr.onreadystatechange=()=>{
if(xmlr.readyState=== XMLHttpRequest.DONE) {
cb();
}
};
xmlr.open('POST','/skey/set/3dspread3/documents',true);
xmlr.send(JSON.stringify(list));
}
function savedocumentsub(name,history,cb) {
var xmlr = new XMLHttpRequest();
xmlr.onreadystatechange=()=>{
if(xmlr.readyState=== XMLHttpRequest.DONE) {
cb();
}
};
xmlr.open('POST','/skey/set/3dspread3/documents/'+name,true);
xmlr.send(JSON.stringify(history));
}
function savedocument(name,history,cb) {
parallel([
cb=>savedocumentsub(name,history,cb),
cb=>getdocumentlist((err,list)=>{
if(err) return cb(err);
console.log('document list',list);
list = list.filter(i=>i!=name);
list.unshift(name);
writedocumentlist(list,cb);
})
],cb);
}
function loaddocument(name,cb) {
var xmlr = new XMLHttpRequest();
xmlr.onreadystatechange=()=>{
if(xmlr.readyState=== XMLHttpRequest.DONE) {
cb(null,JSON.parse(xmlr.responseText));
}
};
xmlr.open('POST','/skey/get/3dspread3/documents/'+name,true);
xmlr.send();
}
function createsortline(lowindex,highindex,parentelem,sortbutton) {
var nextcreated=false;
var retr = document.createElement('div');
var select = document.createElement('select');
var nulloption = document.createElement('option');
select.append(nulloption);
for(var c=lowindex;c<=highindex;++c) {
var option = document.createElement('option');
option.value=c;
option.innerText=c;
select.append(option);
}
var mapinput = document.createElement('input');
mapinput.placeholder='(optional) Map function';
mapinput.style.display='none';
var compareinput = document.createElement('input');
compareinput.placeholder='(optional) Compare function';
compareinput.style.display='none';
var remove=document.createElement('span');
remove.innerText='x';
remove.style.display='none';
remove.style.color='red';
remove.style.cursor='pointer';
retr.append(select);
retr.append(mapinput);
retr.append(compareinput);
retr.append(remove);
parentelem.append(retr);
select.addEventListener('change',()=>{
if(select.value.length) {
//Show map and compare function inputs
mapinput.style.color='black';
compareinput.style.color='black';
mapinput.style.display='inline';
compareinput.style.display='inline';
remove.style.display='inline';
if(sortbutton) sortbutton.style.display='inline';
if(!nextcreated) {
nextcreated=true;
var next=createsortline(lowindex,highindex,parentelem);
}
}
else {
//Gray map and compare function inputs
mapinput.style.color='gray';
compareinput.style.color='gray';
}
});
remove.addEventListener('click',()=>retr.remove());
}
function stdcompare(a,b) {
if(a>b) {
return 1;
}
else if(b<a) {
return -1;
}
else {
return 0;
}
}
function dimforhistory(history) {
var maxX=19;
var maxY=9;
var maxZ=0;
history.forEach(i=>{
var [x,y,z,...uc]=i.split(':').slice(0,3).map(c=>parseInt(c));
console.log(x,y,z);
maxX=Math.max(x,maxX);
maxY=Math.max(y,maxY);
maxZ=Math.max(z,maxZ);
});
return [maxX+1,maxY+1,maxZ+1];
}
function sheetfromsuburl(suburl,cb) {
var [cmd,...location]=suburl.split('/');
location=location.join('/');
if(cmd=='doc') {
loaddocument(location,(err,history)=>{
var [x,y,z]=dimforhistory(history);
sheet = createnewsheet(x,y,z);
applyhistorytosheet(sheet,history);
cb(null,sheet);
});
}
}
function buildwithinitialsheet(sheet) {
document.body.childNodes.forEach((i,e)=>i.remove());
var tabledriver = driver(sheet);
var ctrls=controls(sheet,tabledriver);
document.body.appendChild(ctrls);
document.body.appendChild(tabledriver);
document.body.appendChild(ctrls.saveloadbox);
}
function mean(array) {
return sum(array)/array.length;
}
function variance(array) {
var m=mean(array);
var variance=mean(array.map(a=>(m-a)*(m-a)));
return variance;
}
function softmaxinterpolate(domainSamples, rangeSamples) {
return function(domain) {
const presoftmaxweights = domainSamples.map(i => -Math.abs(i - domain));
const unscaledsoftmax = presoftmaxweights.map(i => Math.exp(i));
const softmaxsum = unscaledsoftmax.reduce((a, b) => a + b, 0);
const softmaxweights = unscaledsoftmax.map(i => i / softmaxsum);
const scaledranges = rangeSamples.map((r, idx) => r * softmaxweights[idx]);
return scaledranges.reduce((a, b) => a + b, 0);
};
}
function randint(min, max) {
if(max===undefined) return randint(0,min);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function range(a,b,c) {
var start,end,step;
if(arguments.length<1) throw 'We need an argument'
if(arguments.length==1) {
start=0;
end=a;
step=1;
}
else {
start=a;
end=b;
step=c||1;
}
var out=[];
for(var i=start;i<end;i+=step) {
out.push(i);
}
return out;
}
function main() {
var suburl=appsubchannel();
window.suburl=suburl;
document.title='3dspread3';
add_style(get3dspreadCSS());
if(suburl) {
return sheetfromsuburl(suburl,(err,sheet)=>buildwithinitialsheet(sheet));
}
window.addEventListener('load',()=>{
buildwithinitialsheet(createnewsheet(20,10,1));
});
}
main();
3dspread3