From 28584ec871f13ff93a6fab36a7f0fae0a2967ce4 Mon Sep 17 00:00:00 2001 From: Jehy Date: Mon, 12 Feb 2018 17:17:46 +0300 Subject: [PATCH] build using Node.JS and webpack --- .eslintrc.json | 56 + .gitignore | 4 + README.md | 3 +- build.sh | 4 - lib/barcodes.min.js | 2 - lib/slider/js/bootstrap-slider.js | 388 --- package.json | 47 + passbook.html | 244 -- passbook.js | 792 ----- passbook.min.css | 1 - passbook.min.js | 1 - src/css/custom.css | 38 + {lib/slider => src}/css/slider.css | 0 src/index.ejs | 183 + src/js/bootstrap-slider.js | 387 +++ src/js/index.js | 19 + src/js/javascript-barcodes.js | 4054 +++++++++++++++++++++++ src/js/passbook.js | 802 +++++ passbook.less => src/less/passbook.less | 0 {lib/slider => src}/less/slider.less | 0 webpack.config.js | 7 + webpack.dev.js | 63 + webpack.prod.js | 83 + 23 files changed, 5744 insertions(+), 1434 deletions(-) create mode 100644 .eslintrc.json create mode 100644 .gitignore delete mode 100755 build.sh delete mode 100644 lib/barcodes.min.js delete mode 100644 lib/slider/js/bootstrap-slider.js create mode 100644 package.json delete mode 100644 passbook.html delete mode 100644 passbook.js delete mode 100644 passbook.min.css delete mode 100644 passbook.min.js create mode 100644 src/css/custom.css rename {lib/slider => src}/css/slider.css (100%) create mode 100644 src/index.ejs create mode 100644 src/js/bootstrap-slider.js create mode 100644 src/js/index.js create mode 100644 src/js/javascript-barcodes.js create mode 100644 src/js/passbook.js rename passbook.less => src/less/passbook.less (100%) rename {lib/slider => src}/less/slider.less (100%) create mode 100644 webpack.config.js create mode 100644 webpack.dev.js create mode 100644 webpack.prod.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..88d3aeb --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,56 @@ +{ + "parserOptions": { + "ecmaVersion": 2017, + "sourceType": "module", + "ecmaFeatures": { + "jsx": false + } + }, + "env": { + "browser": true, + "node": true, + "mocha": true + }, + "extends": "airbnb-base", + "plugins": [ + "standard", + "promise" + ], + "rules": { + "strict": [ + "error", + "global" + ], + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": [ + "webpack.prod.js", + "webpack.dev.js", + "test/**/*.js" + ] + } + ], + "no-mixed-operators": "off", + "max-len": [ + "error", + 160 + ], + "prefer-destructuring": "off", + "one-var": "off", + "padded-blocks": "off", + "no-plusplus": "off", + "arrow-spacing": "off", + "object-curly-spacing": "off", + "prefer-const": "warn", + "no-unused-vars": "warn", + "object-shorthand": "warn", + "no-param-reassign": "warn", + "no-console": "warn", + "no-multi-spaces": "off", + "linebreak-style": [ + "error", + "unix" + ] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c655822 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea +node_modules +dist/* +package-lock.json diff --git a/README.md b/README.md index d8c56fe..1053622 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,7 @@ Passbook editor for Bootstrap A Bootstrap 3 based editor for IOS Passbook-style cards. -You can see the documentation and some samples -[here](http://rawgithub.com/usrz/bootstrap-passbook/master/passbook.html). +You can see the documentation and some samples after running `npm run build` script and opening dist/index.html LICENSE ======= diff --git a/build.sh b/build.sh deleted file mode 100755 index c6a1962..0000000 --- a/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -lessc -x passbook.less > passbook.min.css -uglifyjs passbook.js > passbook.min.js diff --git a/lib/barcodes.min.js b/lib/barcodes.min.js deleted file mode 100644 index 2b75221..0000000 --- a/lib/barcodes.min.js +++ /dev/null @@ -1,2 +0,0 @@ -var Barcode=function(){var e=function(e,t,r){var i=n[e];if(i==null)throw new Error('Unsupported barcode type "'+e+'"');var s=i(t,r);this.parameters=s.parameters||r||{},this.format=e,this.rows=s.rows,this.cols=s.cols,this.data=s.data,this.contents=t};e.prototype.createCanvas=function(e,n){var r=t(e,n);canvas=document.createElement("canvas"),canvas.width=r.x*this.cols,canvas.height=r.y*this.rows;var i=canvas.getContext("2d");for(var s=0,o=0;s=0&&r=0&&ns.n_scale&&s.setScale(i.n_scale),s.n_scale>i.n_scale&&i.setScale(s.n_scale),o=e.bc_add(i,s,r),o.n_scale>r&&(o.n_scale=r),o.toString()}function i(t,n,r){var i,s,o;return typeof r=="undefined"&&(r=e.scale),r=r<0?0:r,i=e.bc_init_num(),s=e.bc_init_num(),o=e.bc_init_num(),i=e.php_str2num(t.toString()),s=e.php_str2num(n.toString()),i.n_scale>s.n_scale&&s.setScale(i.n_scale),s.n_scale>i.n_scale&&i.setScale(s.n_scale),o=e.bc_sub(i,s,r),o.n_scale>r&&(o.n_scale=r),o.toString()}function s(t,n,r){var i,s;return typeof r=="undefined"&&(r=e.scale),r=r<0?0:r,i=e.bc_init_num(),s=e.bc_init_num(),i=e.bc_str2num(t.toString(),r),s=e.bc_str2num(n.toString(),r),e.bc_compare(i,s,r)}function o(t){return t=parseInt(t,10),isNaN(t)?!1:t<0?!1:(e.scale=t,!0)}function u(t,n,r){var i,s,o;typeof r=="undefined"&&(r=e.scale),r=r<0?0:r,i=e.bc_init_num(),s=e.bc_init_num(),o=e.bc_init_num(),i=e.php_str2num(t.toString()),s=e.php_str2num(n.toString()),i.n_scale>s.n_scale&&s.setScale(i.n_scale),s.n_scale>i.n_scale&&i.setScale(s.n_scale),o=e.bc_divide(i,s,r);if(o===-1)throw new Error(11,"(BC) Division by zero");return o.n_scale>r&&(o.n_scale=r),o.toString()}function a(t,n,r){var i,s,o;return typeof r=="undefined"&&(r=e.scale),r=r<0?0:r,i=e.bc_init_num(),s=e.bc_init_num(),o=e.bc_init_num(),i=e.php_str2num(t.toString()),s=e.php_str2num(n.toString()),i.n_scale>s.n_scale&&s.setScale(i.n_scale),s.n_scale>i.n_scale&&i.setScale(s.n_scale),o=e.bc_multiply(i,s,r),o.n_scale>r&&(o.n_scale=r),o.toString()}function f(e,n){var r,i;return r="0."+Array(n+1).join("0")+"5",e.toString().substring(0,1)=="-"&&(r="-"+r),i=t(e,r,n),i}var e={PLUS:"+",MINUS:"-",BASE:10,scale:0,bc_num:function(){this.n_sign=null,this.n_len=null,this.n_scale=null,this.n_value=null,this.toString=function(){var t,n;return n=this.n_value.join(""),t=(this.n_sign==e.PLUS?"":this.n_sign)+n.substr(0,this.n_len),this.n_scale>0&&(t+="."+n.substr(this.n_len,this.n_scale)),t},this.setScale=function(e){while(this.n_scalee)this.n_value.pop(),this.n_scale--;return this}},bc_new_num:function(t,n){var r;return r=new e.bc_num,r.n_sign=e.PLUS,r.n_len=t,r.n_scale=n,r.n_value=e.safe_emalloc(1,t+n,0),e.memset(r.n_value,0,0,t+n),r},safe_emalloc:function(e,t,n){return Array(e*t+n)},bc_init_num:function(){return new e.bc_new_num(1,0)},_bc_rm_leading_zeros:function(e){while(e.n_value[0]===0&&e.n_len>1)e.n_value.shift(),e.n_len--},php_str2num:function(t){var n;return n=t.indexOf("."),n==-1?e.bc_str2num(t,0):e.bc_str2num(t,t.length-n)},CH_VAL:function(e){return e-"0"},BCD_CHAR:function(e){return e+"0"},isdigit:function(e){return isNaN(parseInt(e,10))?!1:!0},bc_str2num:function(t,n){var r,i,s,o,u,a,f;r=t.split(""),s=0,o=0,u=0,a=!1,(r[s]==="+"||r[s]==="-")&&s++;while(r[s]==="0")s++;while(r[s]%1===0)s++,o++;r[s]==="."&&s++;while(r[s]%1===0)s++,u++;if(r[s]||o+u===0)return e.bc_init_num();u=e.MIN(u,n),o===0&&(a=!0,o=1),i=e.bc_new_num(o,u),s=0,r[s]==="-"?(i.n_sign=e.MINUS,s++):(i.n_sign=e.PLUS,r[s]==="+"&&s++);while(r[s]==="0")s++;f=0,a&&(i.n_value[f++]=0,o=0);for(;o>0;o--)i.n_value[f++]=e.CH_VAL(r[s++]);if(u>0){s++;for(;u>0;u--)i.n_value[f++]=e.CH_VAL(r[s++])}return i},cint:function(e){typeof e=="undefined"&&(e=0);var t=parseInt(e,10);return isNaN(t)&&(t=0),t},MIN:function(e,t){return e>t?t:e},MAX:function(e,t){return e>t?e:t},ODD:function(e){return e&1},memset:function(e,t,n,r){var i;for(i=0;i0&&e.n_value[n++]===0)t--;return t!==0?!1:!0},bc_out_of_memory:function(){throw new Error("(BC) Out of memory")}};e.bc_add=function(t,n,r){var i,s,o;if(t.n_sign===n.n_sign)i=e._bc_do_add(t,n,r),i.n_sign=t.n_sign;else{s=e._bc_do_compare(t,n,!1,!1);switch(s){case-1:i=e._bc_do_sub(n,t,r),i.n_sign=n.n_sign;break;case 0:o=e.MAX(r,e.MAX(t.n_scale,n.n_scale)),i=e.bc_new_num(1,o),e.memset(i.n_value,0,0,o+1);break;case 1:i=e._bc_do_sub(t,n,r),i.n_sign=t.n_sign}}return i},e._one_mult=function(t,n,r,i,s,o){var u,a,f,l;if(i===0)e.memset(s,0,0,r);else if(i==1)e.memcpy(s,o,t,n,r);else{f=n+r-1,l=o+r-1,u=0;while(r-->0)a=t[f--]*i+u,s[l--]=a%e.BASE,u=Math.floor(a/e.BASE);u!=0&&(s[l]=u)}},e.bc_divide=function(t,n,r){var i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x,T,N,C,k;if(e.bc_is_zero(n))return-1;if(e.bc_is_zero(t))return e.bc_new_num(1,r);n.n_scale===0&&n.n_len===1&&n.n_value[0]===1&&(s=e.bc_new_num(t.n_len,r),s.n_sign=t.n_sign==n.n_sign?e.PLUS:e.MINUS,e.memset(s.n_value,t.n_len,0,r),e.memcpy(s.n_value,0,t.n_value,0,t.n_len+e.MIN(t.n_scale,r))),m=n.n_scale,l=n.n_len+m-1;while(m>0&&n.n_value[l--]===0)m--;d=t.n_len+m,h=t.n_scale-m,hd+r?(g=r+1,N=!0):(N=!1,v>d?g=r+1:g=d-v+r+1),s=e.bc_new_num(g-r,r),e.memset(s.n_value,0,0,g),T=e.safe_emalloc(1,v,1),T===null&&e.bc_out_of_memory();if(!N){C=Math.floor(10/(n.n_value[l]+1)),C!=1&&(e._one_mult(o,0,d+h+y+1,C,o,0),e._one_mult(n.n_value,l,v,C,n.n_value,l)),w=0,v>d?c=v-d:c=0;while(w<=d+r-v){n.n_value[l]==o[w]?E=9:E=Math.floor((o[w]*10+o[w+1])/n.n_value[l]),n.n_value[l+1]*E>(o[w]*10+o[w+1]-n.n_value[l]*E)*10+o[w+2]&&(E--,n.n_value[l+1]*E>(o[w]*10+o[w+1]-n.n_value[l]*E)*10+o[w+2]&&E--),S=0;if(E!==0){T[0]=0,e._one_mult(n.n_value,l,v,E,T,1),a=w+v,f=v;for(b=0;b9?(p-=10,x=1):x=0,o[a--]=p;x==1&&(o[a]=(o[a]+1)%10)}s.n_value[c++]=E,w++}}return s.n_sign=t.n_sign==n.n_sign?e.PLUS:e.MINUS,e.bc_is_zero(s)&&(s.n_sign=e.PLUS),e._bc_rm_leading_zeros(s),s},e._bc_do_add=function(t,n,r){var i,s,o,u,a,f,l,c,h,p;s=e.MAX(t.n_scale,n.n_scale),o=e.MAX(t.n_len,n.n_len)+1,i=e.bc_new_num(o,e.MAX(s,r)),c=t.n_scale,h=n.n_scale,u=t.n_len+c-1,a=n.n_len+h-1,f=s+o-1;if(c!=h)if(c>h)while(c>h)i.n_value[f--]=t.n_value[u--],c--;else while(h>c)i.n_value[f--]=n.n_value[a--],h--;c+=t.n_len,h+=n.n_len,l=0;while(c>0&&h>0)p=t.n_value[u--]+n.n_value[a--]+l,p>=e.BASE?(l=1,p-=e.BASE):l=0,i.n_value[f]=p,f--,c--,h--;if(c===0)while(h-->0)p=n.n_value[a--]+l,p>=e.BASE?(l=1,p-=e.BASE):l=0,i.n_value[f--]=p;else while(c-->0)p=t.n_value[u--]+l,p>=e.BASE?(l=1,p-=e.BASE):l=0,i.n_value[f--]=p;return l==1&&(i.n_value[f]+=1),e._bc_rm_leading_zeros(i),i},e._bc_do_sub=function(t,n,r){var i,s,o,u,a,f,l,c,h,p,d;o=e.MAX(t.n_len,n.n_len),s=e.MAX(t.n_scale,n.n_scale),a=e.MIN(t.n_len,n.n_len),u=e.MIN(t.n_scale,n.n_scale),i=e.bc_new_num(o,e.MAX(s,r)),f=t.n_len+t.n_scale-1,l=n.n_len+n.n_scale-1,c=o+s-1,h=0;if(t.n_scale!=u)for(p=t.n_scale-u;p>0;p--)i.n_value[c--]=t.n_value[f--];else for(p=n.n_scale-u;p>0;p--)d=0-n.n_value[l--]-h,d<0?(d+=e.BASE,h=1):(h=0,i.n_value[c--]=d);for(p=0;p0;p--)d=t.n_value[f--]-h,d<0?(d+=e.BASE,h=1):h=0,i.n_value[c--]=d;return e._bc_rm_leading_zeros(i),i},e.MUL_BASE_DIGITS=80,e.MUL_SMALL_DIGITS=e.MUL_BASE_DIGITS/4,e.bc_multiply=function(t,n,r){var i,s,o,u,a;return s=t.n_len+t.n_scale,o=n.n_len+n.n_scale,u=t.n_scale+n.n_scale,a=e.MIN(u,e.MAX(r,e.MAX(t.n_scale,n.n_scale))),i=e._bc_rec_mul(t,s,n,o,u),i.n_sign=t.n_sign==n.n_sign?e.PLUS:e.MINUS,i.n_len=o+s+1-u,i.n_scale=a,e._bc_rm_leading_zeros(i),e.bc_is_zero(i)&&(i.n_sign=e.PLUS),i},e.new_sub_num=function(t,n,r){var i=new e.bc_num;return i.n_sign=e.PLUS,i.n_len=t,i.n_scale=n,i.n_value=r,i},e._bc_simp_mul=function(t,n,r,i,s){var o,u,a,f,l,c,h,p,d;d=n+i+1,o=e.bc_new_num(d,0),l=n-1,c=i-1,f=d-1,p=0;for(h=0;h=0&&a<=c)p+=t.n_value[u--]*r.n_value[a++];o.n_value[f--]=Math.floor(p%e.BASE),p=Math.floor(p/e.BASE)}return o.n_value[f]=p,o},e._bc_shift_addsub=function(t,n,r,i){var s,o,u,a;u=n.n_len,n.n_value[0]===0&&u--;if(t.n_len+t.n_scale>=r+u){s=t.n_len+t.n_scale-r-1,o=n.n_len=1,a=0;if(i){while(u--)t.n_value[s]-=n.n_value[o--]+a,t.n_value[s]<0?(a=1,t.n_value[s--]+=e.BASE):(a=0,s--);while(a)t.n_value[s]-=a,t.n_value[s]<0?t.n_value[s--]+=e.BASE:a=0}else{while(u--)t.n_value[s]+=n.n_value[o--]+a,t.n_value[s]>e.BASE-1?(a=1,t.n_value[s--]-=e.BASE):(a=0,s--);while(a)t.n_value[s]+=a,t.n_value[s]>e.BASE-1?t.n_value[s--]-=e.BASE:a=0}return!0}throw new Error("len + scale < shift + count")},e._bc_rec_mul=function(t,n,r,i,s){var o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S;return n+i0){var a=e.substr(i,o[1]-i),f=[];f=a.match(/([\x09\x0a\x0d\x20-\x7e]{5,})/g);if(f==null)f=[];else for(var r=0;r0){var d=a.substr(l,h[1]-l);d.length>0&&(d.length==1&&t.length>0&&t[t.length-1][0]==900?t.push([913,d]):d.length%6==0?t.push([924,d]):t.push([901,d]))}p>0&&t.push([900,h[0]]),l=h[1]+p}}u>0&&t.push([902,o[0]]),i=o[1]+u}return t},y=function(e,n,r){r=r||!0;var i=[];switch(e){case 900:var s=0,o=[],f=n.length;for(var l=0;l0){f>6?(g=n.substring(6),n=n.substring(0,6),y=6):(g="",y=n.length);if(y==6){var w=a(""+b(n.charAt(0)),"1099511627776");w=t(w,a(""+b(n.charAt(1)),"4294967296")),w=t(w,a(""+b(n.charAt(2)),"16777216")),w=t(w,a(""+b(n.charAt(3)),"65536")),w=t(w,a(""+b(n.charAt(4)),"256")),w=t(w,""+b(n.charAt(5)));do{var E=C(w,"900");w=u(w,"900"),i.unshift(E)}while(w!="0")}else for(var l=0;l0){f>44?(g=n.substring(44),n=n.substring(0,44)):g="";var w="1"+n;do{var E=C(w,"900");w=u(w,"900"),i.unshift(E)}while(w!="0");n=g}break;case 913:i.push(b(n))}return r&&i.unshift(e),i},b=function(e){return e.charCodeAt(0)},w=function(e,t){var n=8,r=928-t;while(n>0){var i=2<=i)break;--n}if(e<0||e>8)t<41?e=2:t<161?e=3:t<321?e=4:t<864?e=5:e=n;return e>n&&(e=n),e},E=function(e,t){var n=m[t],r=2<0;--a){var f=u*n[a]%929,l=929-f;s[a]=(s[a-1]+l)%929}f=u*n[0]%929,l=929-f,s[0]=l%929}for(var a=0;a925)return!1;var f=w(n,a),l=2<30&&(d=30);var m=Math.ceil(p/d),b=d*m;if(m<3||m>90)m<3?m=3:m>90&&(m=90),d=Math.ceil(b/m),b=d*m;b>928&&(Math.abs(_aspectRatio-493/32)0&&(b-m==p?(--m,b-=m):s=s.concat(S(0,N,900)));var C=b-l;s.unshift(C);var k=E(s,f);s=s.concat(k);var L={rows:m,cols:(d+2)*17+35,data:new Array,parameters:{aspectRatio:r,errorCorrectionLevel:f}},A,O=0,M=0;for(var _=0;_2&&(M=0)}return L};n.pdf417=k;var L=function(){function o(e,t){if(typeof e.length=="undefined")throw new Error(e.length+"/"+t);var n=function(){var n=0;while(n=7&&S(e),d==null&&(d=C(l,c,v)),T(d,t)},y=function(e,t){for(var n=-1;n<=7;n+=1){if(e+n<=-1||p<=e+n)continue;for(var r=-1;r<=7;r+=1){if(t+r<=-1||p<=t+r)continue;0<=n&&n<=6&&(r==0||r==6)||0<=r&&r<=6&&(n==0||n==6)||2<=n&&n<=4&&2<=r&&r<=4?h[e+n][t+r]=!0:h[e+n][t+r]=!1}}},b=function(){var e=0,t=0;for(var n=0;n<8;n+=1){g(!0,n);var r=i.getLostPoint(m);if(n==0||e>r)e=r,t=n}return t},w=function(){for(var e=8;e>n&1)==1;h[Math.floor(n/3)][n%3+p-8-3]=r}for(var n=0;n<18;n+=1){var r=!e&&(t>>n&1)==1;h[n%3+p-8-3][Math.floor(n/3)]=r}},x=function(e,t){var n=c<<3|t,r=i.getBCHTypeInfo(n);for(var s=0;s<15;s+=1){var o=!e&&(r>>s&1)==1;s<6?h[s][8]=o:s<8?h[s+1][8]=o:h[p-15+s][8]=o}for(var s=0;s<15;s+=1){var o=!e&&(r>>s&1)==1;s<8?h[8][p-s-1]=o:s<9?h[8][15-s-1+1]=o:h[8][15-s-1]=o}h[p-8][8]=!e},T=function(e,t){var n=-1,r=p-1,s=7,o=0,u=i.getMaskFunction(t);for(var a=p-1;a>0;a-=2){a==6&&(a-=1);for(;;){for(var f=0;f<2;f+=1)if(h[r][a-f]==null){var l=!1;o>>s&1)==1);var c=u(r,a-f);c&&(l=!l),h[r][a-f]=l,s-=1,s==-1&&(o+=1,s=7)}r+=n;if(r<0||p<=r){r-=n,n=-n;break}}}},N=function(e,t){var n=0,r=0,s=0,u=new Array(t.length),a=new Array(t.length);for(var f=0;f=0?v.getAt(m):0}}var g=0;for(var h=0;hh*8)throw new Error("code length overflow. ("+f.getLengthInBits()+">"+h*8+")");f.getLengthInBits()+4<=h*8&&f.put(0,4);while(f.getLengthInBits()%8!=0)f.putBit(!1);for(;;){if(f.getLengthInBits()>=h*8)break;f.put(r,8);if(f.getLengthInBits()>=h*8)break;f.put(s,8)}return N(f,o)};return m.addData=function(e){var t=f(e);v.push(t),d=null},m.getData=function(){return h},m.isDark=function(e,t){if(e<0||p<=e||t<0||p<=t)throw new Error(e+","+t);return h[e][t]},m.getModuleCount=function(){return p},m.make=function(){g(!1,b())},m};e.stringToBytes=function(e){var t=new Array;for(var n=0;n>>8),t.push(o&255)):t.push(r)}}return t}};var t={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},n={L:1,M:0,Q:3,H:2},r={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},i=function(){var e=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],n=1335,i=7973,u=21522,a={},f=function(e){var t=0;while(e!=0)t+=1,e>>>=1;return t};return a.getBCHTypeInfo=function(e){var t=e<<10;while(f(t)-f(n)>=0)t^=n<=0)t^=i<5&&(n+=3+s-5)}for(var r=0;r=256)t-=255;return e[t]},r}(),u=function(){var e=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16]],t=function(e,t){var n={};return n.totalCount=e,n.dataCount=t,n},r={},i=function(t,r){switch(r){case n.L:return e[(t-1)*4+0];case n.M:return e[(t-1)*4+1];case n.Q:return e[(t-1)*4+2];case n.H:return e[(t-1)*4+3];default:return undefined}};return r.getRSBlocks=function(e,n){var r=i(e,n);if(typeof r=="undefined")throw new Error("bad rs block @ typeNumber:"+e+"/errorCorrectLevel:"+n);var s=r.length/3,o=new Array;for(var u=0;u>>7-t%8&1)==1},n.put=function(e,t){for(var r=0;r>>t-r-1&1)==1)},n.getLengthInBits=function(){return t},n.putBit=function(n){var r=Math.floor(t/8);e.length<=r&&e.push(0),n&&(e[r]|=128>>>t%8),t+=1},n},f=function(n){var r=t.MODE_8BIT_BYTE,i=n,s=e.stringToBytes(n),o={};return o.getMode=function(){return r},o.getLength=function(e){return s.length},o.write=function(e){for(var t=0;t10&&(r=10),i=Number(n.errorCorrectionLevel)||1,i<0&&(ecl=0),i>3&&(ecl=3);switch(i){case 0:s="L";break;case 1:s="M";break;case 2:s="Q";break;case 3:s="H"}}var o=e(r,s);return o.addData(t),o.make(),{rows:o.getModuleCount(),cols:o.getModuleCount(),data:o.getData(),parameters:{errorCorrectionLevel:i,version:r}}}}();n.qrcode=L;var A=function(){var e=function(){var e=new Array,t={};return t.writeByte=function(t){e.push(t&255)},t.writeShort=function(e){t.writeByte(e),t.writeByte(e>>>8)},t.writeBytes=function(e,n,r){n=n||0,r=r||e.length;for(var i=0;i0&&(t+=","),t+=e[n];return t+="]",t},t},t=function(){var e=0,t=0,n=0,r="",i={},s=function(e){r+=String.fromCharCode(o(e&63))},o=function(e){if(!(e<0)){if(e<26)return 65+e;if(e<52)return 97+(e-26);if(e<62)return 48+(e-52);if(e==62)return 43;if(e==63)return 47}throw new Error("n:"+e)};return i.writeByte=function(r){e=e<<8|r&255,t+=8,n+=1;while(t>=6)s(e>>>t-6),t-=6},i.flush=function(){t>0&&(s(e<<6-t),e=0,t=0);if(n%3!=0){var i=3-n%3;for(var o=0;o255)e.writeByte(255),e.writeBytes(n,s,255),s+=255;e.writeByte(n.length-s),e.writeBytes(n,s,n.length-s),e.writeByte(0),e.writeString(";")};var u=function(e){var t=e,n=0,r=0,i={};return i.write=function(e,i){if(e>>>i!=0)throw new Error("length over");while(n+i>=8)t.writeByte(255&(e<>>=8-n,r=0,n=0;r=e<0&&t.writeByte(r)},i},a=function(t){var n=1<'+ - '
'+ - '
'+ - '
'+ - '
'+ - '
'+ - '
'+ - '') - .insertBefore(this.element) - .append(this.element); - this.id = this.element.data('slider-id')||options.id; - if (this.id) { - this.picker[0].id = this.id; - } - - if (typeof Modernizr !== 'undefined' && Modernizr.touch) { - this.touchCapable = true; - } - - var tooltip = this.element.data('slider-tooltip')||options.tooltip; - - this.tooltip = this.picker.find('.tooltip'); - this.tooltipInner = this.tooltip.find('div.tooltip-inner'); - - this.orientation = this.element.data('slider-orientation')||options.orientation; - switch(this.orientation) { - case 'vertical': - this.picker.addClass('slider-vertical'); - this.stylePos = 'top'; - this.mousePos = 'pageY'; - this.sizePos = 'offsetHeight'; - this.tooltip.addClass('right')[0].style.left = '100%'; - break; - default: - this.picker - .addClass('slider-horizontal') - .css('width', this.element.outerWidth()); - this.orientation = 'horizontal'; - this.stylePos = 'left'; - this.mousePos = 'pageX'; - this.sizePos = 'offsetWidth'; - this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px'; - break; - } - - this.min = this.element.data('slider-min')||options.min; - this.max = this.element.data('slider-max')||options.max; - this.step = this.element.data('slider-step')||options.step; - this.value = this.element.data('slider-value')||options.value; - if (this.value[1]) { - this.range = true; - } - - this.selection = this.element.data('slider-selection')||options.selection; - this.selectionEl = this.picker.find('.slider-selection'); - if (this.selection === 'none') { - this.selectionEl.addClass('hide'); - } - this.selectionElStyle = this.selectionEl[0].style; - - - this.handle1 = this.picker.find('.slider-handle:first'); - this.handle1Stype = this.handle1[0].style; - this.handle2 = this.picker.find('.slider-handle:last'); - this.handle2Stype = this.handle2[0].style; - - var handle = this.element.data('slider-handle')||options.handle; - switch(handle) { - case 'round': - this.handle1.addClass('round'); - this.handle2.addClass('round'); - break - case 'triangle': - this.handle1.addClass('triangle'); - this.handle2.addClass('triangle'); - break - } - - if (this.range) { - this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); - this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); - } else { - this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; - this.handle2.addClass('hide'); - if (this.selection == 'after') { - this.value[1] = this.max; - } else { - this.value[1] = this.min; - } - } - this.diff = this.max - this.min; - this.percentage = [ - (this.value[0]-this.min)*100/this.diff, - (this.value[1]-this.min)*100/this.diff, - this.step*100/this.diff - ]; - - this.offset = this.picker.offset(); - this.size = this.picker[0][this.sizePos]; - - this.formater = options.formater; - - this.layout(); - - if (this.touchCapable) { - // Touch: Bind touch events: - this.picker.on({ - touchstart: $.proxy(this.mousedown, this) - }); - } else { - this.picker.on({ - mousedown: $.proxy(this.mousedown, this) - }); - } - - if (tooltip === 'show') { - this.picker.on({ - mouseenter: $.proxy(this.showTooltip, this), - mouseleave: $.proxy(this.hideTooltip, this) - }); - } else { - this.tooltip.addClass('hide'); - } - }; - - Slider.prototype = { - constructor: Slider, - - over: false, - inDrag: false, - - showTooltip: function(){ - this.tooltip.addClass('in'); - //var left = Math.round(this.percent*this.width); - //this.tooltip.css('left', left - this.tooltip.outerWidth()/2); - this.over = true; - }, - - hideTooltip: function(){ - if (this.inDrag === false) { - this.tooltip.removeClass('in'); - } - this.over = false; - }, - - layout: function(){ - this.handle1Stype[this.stylePos] = this.percentage[0]+'%'; - this.handle2Stype[this.stylePos] = this.percentage[1]+'%'; - if (this.orientation == 'vertical') { - this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%'; - this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; - } else { - this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%'; - this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; - } - if (this.range) { - this.tooltipInner.text( - this.formater(this.value[0]) + - ' : ' + - this.formater(this.value[1]) - ); - this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; - } else { - this.tooltipInner.text( - this.formater(this.value[0]) - ); - this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; - } - }, - - mousedown: function(ev) { - - // Touch: Get the original event: - if (this.touchCapable && ev.type === 'touchstart') { - ev = ev.originalEvent; - } - - this.offset = this.picker.offset(); - this.size = this.picker[0][this.sizePos]; - - var percentage = this.getPercentage(ev); - - if (this.range) { - var diff1 = Math.abs(this.percentage[0] - percentage); - var diff2 = Math.abs(this.percentage[1] - percentage); - this.dragged = (diff1 < diff2) ? 0 : 1; - } else { - this.dragged = 0; - } - - this.percentage[this.dragged] = percentage; - this.layout(); - - if (this.touchCapable) { - // Touch: Bind touch events: - $(document).on({ - touchmove: $.proxy(this.mousemove, this), - touchend: $.proxy(this.mouseup, this) - }); - } else { - $(document).on({ - mousemove: $.proxy(this.mousemove, this), - mouseup: $.proxy(this.mouseup, this) - }); - } - - this.inDrag = true; - var val = this.calculateValue(); - this.element.trigger({ - type: 'slideStart', - value: val - }).trigger({ - type: 'slide', - value: val - }); - return false; - }, - - mousemove: function(ev) { - - // Touch: Get the original event: - if (this.touchCapable && ev.type === 'touchmove') { - ev = ev.originalEvent; - } - - var percentage = this.getPercentage(ev); - if (this.range) { - if (this.dragged === 0 && this.percentage[1] < percentage) { - this.percentage[0] = this.percentage[1]; - this.dragged = 1; - } else if (this.dragged === 1 && this.percentage[0] > percentage) { - this.percentage[1] = this.percentage[0]; - this.dragged = 0; - } - } - this.percentage[this.dragged] = percentage; - this.layout(); - var val = this.calculateValue(); - this.element - .trigger({ - type: 'slide', - value: val - }) - .data('value', val) - .prop('value', val); - return false; - }, - - mouseup: function(ev) { - if (this.touchCapable) { - // Touch: Bind touch events: - $(document).off({ - touchmove: this.mousemove, - touchend: this.mouseup - }); - } else { - $(document).off({ - mousemove: this.mousemove, - mouseup: this.mouseup - }); - } - - this.inDrag = false; - if (this.over == false) { - this.hideTooltip(); - } - this.element; - var val = this.calculateValue(); - this.element - .trigger({ - type: 'slideStop', - value: val - }) - .data('value', val) - .prop('value', val); - return false; - }, - - calculateValue: function() { - var val; - if (this.range) { - val = [ - (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step), - (this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step) - ]; - this.value = val; - } else { - val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step); - this.value = [val, this.value[1]]; - } - return val; - }, - - getPercentage: function(ev) { - if (this.touchCapable) { - ev = ev.touches[0]; - } - var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size; - percentage = Math.round(percentage/this.percentage[2])*this.percentage[2]; - return Math.max(0, Math.min(100, percentage)); - }, - - getValue: function() { - if (this.range) { - return this.value; - } - return this.value[0]; - }, - - setValue: function(val) { - this.value = val; - - if (this.range) { - this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); - this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); - } else { - this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; - this.handle2.addClass('hide'); - if (this.selection == 'after') { - this.value[1] = this.max; - } else { - this.value[1] = this.min; - } - } - this.diff = this.max - this.min; - this.percentage = [ - (this.value[0]-this.min)*100/this.diff, - (this.value[1]-this.min)*100/this.diff, - this.step*100/this.diff - ]; - this.layout(); - } - }; - - $.fn.slider = function ( option, val ) { - return this.each(function () { - var $this = $(this), - data = $this.data('slider'), - options = typeof option === 'object' && option; - if (!data) { - $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options)))); - } - if (typeof option == 'string') { - data[option](val); - } - }) - }; - - $.fn.slider.defaults = { - min: 0, - max: 10, - step: 1, - orientation: 'horizontal', - value: 5, - selection: 'before', - tooltip: 'show', - handle: 'round', - formater: function(value) { - return value; - } - }; - - $.fn.slider.Constructor = Slider; - -}( window.jQuery ); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2756223 --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "bootstrap-passbook", + "version": "1.0.0", + "description": "Passbook editor for Bootstrap", + "scripts": { + "lint": "node ./node_modules/eslint/bin/eslint.js ./src/js", + "build-dev": "node ./node_modules/webpack/bin/webpack.js --env=dev --progress --profile --colors", + "build": "node ./node_modules/webpack/bin/webpack.js --env=prod --progress --profile --colors", + "prepare": "npm run build", + "test": "npm run build-dev && npm run lint" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/usrz/bootstrap-passbook.git" + }, + "dependencies": { + "bootstrap": "3.3.7", + "font-awesome": "4.7.0", + "jquery": "3.2.1" + }, + "devDependencies": { + "babel-core": "6.25.0", + "babel-loader": "7.1.1", + "babel-preset-env": "1.6.0", + "clean-webpack-plugin": "0.1.16", + "css-loader": "0.28.4", + "eslint": "4.16.0", + "eslint-config-airbnb-base": "12.1.0", + "eslint-plugin-import": "2.2.0", + "eslint-plugin-promise": "3.5.0", + "eslint-plugin-standard": "3.0.1", + "extract-text-webpack-plugin": "3.0.0", + "file-loader": "1.1.6", + "html-webpack-plugin": "2.29.0", + "less": "3.0.0", + "less-loader": "4.0.5", + "style-loader": "0.20.1", + "webpack": "3.2.0", + "webpack-bundle-analyzer": "2.8.2" + }, + "author": "Pier Fumagalli ", + "license": "Apache", + "bugs": { + "url": "https://github.com/usrz/bootstrap-passbook/issues" + }, + "homepage": "https://github.com/usrz/bootstrap-passbook#readme" +} diff --git a/passbook.html b/passbook.html deleted file mode 100644 index 34cbe6b..0000000 --- a/passbook.html +++ /dev/null @@ -1,244 +0,0 @@ - - - - Passbook - - - - - - - - - - - - - - - - - - - - - Fork me on GitHub - - - - -
- -

A IOS Passbook editor for Bootstrap

- -

- A fully editable IOS Passbook - implementation which can be used to generate data in a visual way to be loaded into your iPhone. -

- -

- This is still in the early stages, but this editor allows to edit - in a fashion much similar to the native Passbook app all - sort of information related to passes. -

- -

An example

- -

- The passbook below is created for you in edit mode. - Click around, fill in some text, play with barcodes, and at the end hit - the little save button - to preview the final pass. -

- -

- Images can be pasted directly from your clipboard, barcodes are generated - on-the-fly using our JavaScript - library, and clicking on the background of the card allows you to - select the pass type and colors. -

- -

- -

API and use

- -

- The API is still rudimentary... This implementation relies on a couple - of components: -

- - - -

- To create a Passbook editor, use the usual jQuery/Boostrap way by calling - $('myElement').passbook();. The element supports a - couple of data points, namely data-passbook-type and - data-passbook-transport: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameValueDescription
passbook-typeboarding-passUsed to edit a boarding pass
couponDisplay a coupon pass
eventDisplay a ticket or an event pass
store cardDisplay a store card pass
genericDisplay a generic pass
passbook-transpoetairIndicates a boarding pass for a plane
boatIndicates a boarding pass for a boat
busIndicates a boarding pass for a bus
trainIndicates a boarding pass for a train
genericIndicates a generic boarding pass
- -

Interaction with passes

- -

- The $('myElement').passbook(…); function - can also be used to interact (minimally) with the pass: -

- - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescription
editForce the pass to be in "edit mode".
saveWhen in edit mode, save the changes and return in view mode.
flipFlip the pass around.
dataReturn the internal structure of the pass (the internal API - not for the fainthearted).
- -

Future enhancements

- -

- Hoping we can get some much needed finishing touches: -

- -
    -
  • import/export: it shouldn't be difficult to implement, - quickly loading JSON on creation, and saving the results out.
  • -
  • events: again, should be trivial to implement, but hopefully - we will have events for flipped (when the pass is - flipped), saved (after hitting the save button) and - editing (when entering in edit mode).
  • -
  • read-only mode: meh, self-explanatory.
  • -
  • varcode pasting: allow barcodes to be pasted like - images, parsed (possibly by a backend) and re-rendered on the pass.
  • -
- -
- - diff --git a/passbook.js b/passbook.js deleted file mode 100644 index b758c08..0000000 --- a/passbook.js +++ /dev/null @@ -1,792 +0,0 @@ -/* ========================================================================== */ -+function ($) { "use strict"; - - var TYPE_BOARDING_PASS = 'boarding-pass'; - var TYPE_COUPON = 'coupon'; - var TYPE_EVENT = 'event'; - var TYPE_STORE_CARD = 'store-card'; - var TYPE_GENERIC = 'generic'; - - var TRANSPORT_AIR = 'air'; - var TRANSPORT_BOAT = 'boat'; - var TRANSPORT_BUS = 'bus'; - var TRANSPORT_TRAIN = 'train'; - var TRANSPORT_GENERIC = 'generic'; - - var TYPE_BOARDING_PASS_C = 'passbook-boarding-pass'; - var TYPE_COUPON_C = 'passbook-coupon'; - var TYPE_EVENT_C = 'passbook-event'; - var TYPE_STORE_CARD_C = 'passbook-store-card'; - var TYPE_C = [ TYPE_BOARDING_PASS_C, - TYPE_COUPON_C, - TYPE_EVENT_C, - TYPE_STORE_CARD_C ].join(' '); - - var TRANSPORT_AIR_C = 'passbook-transport-air'; - var TRANSPORT_BOAT_C = 'passbook-transport-boat'; - var TRANSPORT_BUS_C = 'passbook-transport-bus'; - var TRANSPORT_TRAIN_C = 'passbook-transport-train'; - var TRANSPORT_C = [ TRANSPORT_AIR_C, - TRANSPORT_BOAT_C, - TRANSPORT_BUS_C, - TRANSPORT_TRAIN_C ].join(' '); - - - /* ======================================================================== */ - /* STATIC HELPER FUNCTIONS */ - /* ======================================================================== */ - - var _flip = function(event) { - event.data.flip(); - event.preventDefault(); - event.stopPropagation(); - } - - var _edit_save = function(event) { - var passbook = event.data; - if (passbook.$container.hasClass('passbook-edit')) { - passbook.save(); - } else { - passbook.edit(); - } - event.preventDefault(); - event.stopPropagation(); - } - - var _content_edited = function(event) { - var $target = $(event.target); - $target.text($target.text().trim()); - event.preventDefault(); - event.stopPropagation(); - } - - var _remove_empty_extra_fields = function(event) { - /* Do not remove extra fields if we're left with less than 1 */ - if ($(this).parent('tr').children('th,td').length < 2) return true; - - /* Find our label and value fields */ - var column = $(this).parent('tr').children('th,td').index(this) + 1; - var label = $(this).parents('table').find('th:nth-child(' + column + ')'); - var value = $(this).parents('table').find('td:nth-child(' + column + ')'); - - /* Do not wipe if we have ANY content */ - if (label.text().length != 0) return; - if (value.text().length != 0) return; - - /* Wipe the column */ - label.remove(); - value.remove(); - } - - var _add_empty_extra_fields = function(event) { - var header = $(this).parents('table.passbook-extra-fields').find('tr'); - $(header[0]).append($('') - .on('blur', _content_edited) - .on('blur', _remove_empty_extra_fields)); - $(header[1]).append($('') - .on('blur', _content_edited) - .on('blur', _remove_empty_extra_fields)); - } - - var _remove_empty_back_fields = function(event) { - var $this = $(this); - - /* Figure out label and value (row and cell) */ - var label, value, labelRow, valueRow; - if ($this.prop("tagName") == 'TH') { - label = $this; - labelRow = $this.parents('tr'); - valueRow = labelRow.next('tr'); - value = valueRow.find('td'); - - } else if ($this.prop("tagName") == 'TD') { - value = $this; - valueRow = $this.parents('tr'); - labelRow = valueRow.prev('tr'); - label = labelRow.find('th');; - } - - /* Check if there is some content */ - if (label.text().length != 0) return; - if (value.text().length != 0) return; - - /* Wipe the two label and value rows */ - labelRow.remove(); - valueRow.remove(); - - } - - var _add_empty_back_fields = function(event) { - $(this).parents('.passbook-back-fields').find('table') - .append($('') - .append($('') - .on('blur', _content_edited) - .on('blur', _remove_empty_back_fields) - ) // - ) // - .append($('') - .append($('') - .on('blur', _content_edited) - .on('blur', _remove_empty_back_fields) - ) // - ); - } - - var _find_passbook = function(from) { - /* Easy way out? */ - var data = $(from).data('passbook'); - - if (data != null) return data; - - /* Look in the current element, and all its parents */ - var parent = $(from).parent()[0]; - while ((data == null) && (parent != null)) { - var $current = $(parent); - data = $current.data('passbook'); - parent = $current.parent()[0]; - } - - /* Return whatever we got */ - return data; - } - - - - /* ======================================================================== */ - /* BARCODE CONSTRUCTION */ - /* ======================================================================== */ - - var barcode_popover = function() { - var passbook = _find_passbook(this); - return $($('
') - .append($('
') - .append($('')) - ) //
- .append($('
') - .append($('
') - .append($('') - .on('click', passbook, barcode_pdf417)) - .append($('') - .on('click', passbook, barcode_qrcode)) - ) //
- .append($('
') - .append($('') - .on('click', passbook, barcode_dismiss)) - .append($('') - .on('click', passbook, barcode_confirm)) - ) //
- ) //
- ); // - }; - - var barcode_shown = function(event) { - var passbook = event.data; - var $container = passbook.$container; - - $container.find('input[name="barcode"]').val(passbook.barcode); - if (passbook.barcodeType == 'pdf417') { - $container.find('button[name="pdf417"]').addClass('btn-primary').removeClass('btn-default'); - $container.find('button[name="qrcode"]').addClass('btn-default').removeClass('btn-primary'); - } else if (passbook.barcodeType == 'qrcode') { - $container.find('button[name="qrcode"]').addClass('btn-primary').removeClass('btn-default'); - $container.find('button[name="pdf417"]').addClass('btn-default').removeClass('btn-primary'); - } else { - $container.find('button[name="qrcode"]').addClass('btn-default').removeClass('btn-primary'); - $container.find('button[name="pdf417"]').addClass('btn-default').removeClass('btn-primary'); - } - } - - var barcode_pdf417 = function(event) { - var passbook = event.data; - var $container = passbook.$container; - $container.find('button[name="pdf417"]').addClass('btn-primary').removeClass('btn-default btn-warning'); - $container.find('button[name="qrcode"]').addClass('btn-default').removeClass('btn-primary btn-warning'); - } - - var barcode_qrcode = function(event) { - var passbook = event.data; - var $container = passbook.$container; - $container.find('button[name="pdf417"]').addClass('btn-default').removeClass('btn-primary btn-warning'); - $container.find('button[name="qrcode"]').addClass('btn-primary').removeClass('btn-default btn-warning'); - } - - var barcode_confirm = function(event) { - var passbook = event.data; - var $container = passbook.$container; - - /* Barcode value */ - var barcode = $container.find('input[name="barcode"]').val(); - if ((barcode == null) || (barcode == '')) { - passbook.barcode = ''; - passbook.barcodeType = ''; - $container.find('.passbook-barcode') - .removeClass('passbook-barcode-qrcode passbook-barcode-pdf417') - .removeAttr('style'); - $container.find('.passbook-barcode').popover('hide') - .next('.popover').css('display', 'none'); - return; - }; - - /* Barcode type */ - var barcodeType; - var pdf417 = $container.find('button[name="pdf417"]'); - var qrcode = $container.find('button[name="qrcode"]'); - if (pdf417.hasClass('btn-primary')) { - barcodeType = 'pdf417'; - } else if (qrcode.hasClass('btn-primary')) { - barcodeType = 'qrcode'; - } else { - pdf417.addClass('btn-warning'); - qrcode.addClass('btn-warning'); - return; - } - - /* Save and dismiss */ - passbook.barcode = barcode; - passbook.barcodeType = barcodeType; - var code = new Barcode(barcodeType, barcode, { version: 6 }); - var image = code.createImageData(3); - $container.find('.passbook-barcode') - .css('background-image', 'url(' + image + ')') - .css('background-size', (code.cols * 3) + 'px ' + (code.rows * 3) + 'px') - .removeClass('passbook-barcode-qrcode passbook-barcode-pdf417') - .addClass('passbook-barcode-' + barcodeType); - $container.find('.passbook-barcode').popover('hide') - .next('.popover').css('display', 'none'); - } - - var barcode_dismiss = function(event) { - var passbook = event.data; - var $container = passbook.$container; - $container.find('.passbook-barcode').popover('hide') - .next('.popover').css('display', 'none'); - } - - /* ======================================================================== */ - /* COLOR PICKER */ - /* ======================================================================== */ - - var passbook_change_type = function(event) { - event.data.type = $(event.currentTarget).attr('name'); - } - - var passbook_picker_toggle = function(event) { - if (event.target != event.currentTarget) return; - - var passbook = event.data; - var $container = passbook.$container; - var $picker = $($container.find('.passbook-picker')); - - if ($picker.css('display') != 'none') { - $picker.removeAttr('style') - .off('click') - .empty(); - return; - } - - $picker.on('click', event.data, passbook_picker_toggle) - var r, g, b, k; - var _change_color = function(event) { - var passbook = event.data; - var rb = Math.round(r.getValue()); - var gb = Math.round(g.getValue()); - var bb = Math.round(b.getValue()); - var shading = (k.getValue() - 128) / 128; - passbook.color = 'rgb(' + rb + "," + gb + "," + bb + ")"; - passbook.shading = (k.getValue() - 128) / 128; - } - - var components = passbook.color.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/); - var rc = Number(components[1]); - var gc = Number(components[2]); - var bc = Number(components[3]); - var kc = passbook.shading + 0.5 * 128; - - var id = Math.floor(Math.random() * 999999); - $picker.css('display', 'block') - .append($('
') - .append($('
') - .append($('')) - .append($('')) - .append($('')) - .append($('')) - .append($('')) - ) //
- .append($('
')) - .append($('
')) - .append($('
')) - .append($('
')) - ) //
- - /* Enable sliders and tooltips */ - $picker.find('.passbook-slider').slider(); - $picker.find('button').tooltip({container: $picker}).on('click', passbook, passbook_change_type); - - r = $picker.find('div.slider-r input.passbook-slider').on('slide', event.data, _change_color).data('slider') - g = $picker.find('div.slider-g input.passbook-slider').on('slide', event.data, _change_color).data('slider') - b = $picker.find('div.slider-b input.passbook-slider').on('slide', event.data, _change_color).data('slider') - k = $picker.find('div.slider-k input.passbook-slider').on('slide', event.data, _change_color).data('slider') - } - - var transport_toggle = function(event) { - var passbook = event.data; - var transport = passbook.transport; - - if (transport == TRANSPORT_AIR) { - passbook.transport = TRANSPORT_BOAT; - } else if (transport == TRANSPORT_BOAT) { - passbook.transport = TRANSPORT_BUS; - } else if (transport == TRANSPORT_BUS) { - passbook.transport = TRANSPORT_TRAIN; - } else if (transport == TRANSPORT_TRAIN) { - passbook.transport = TRANSPORT_GENERIC; - } else if (transport == TRANSPORT_GENERIC) { - passbook.transport = TRANSPORT_AIR; - } - } - - /* ======================================================================== */ - /* THUMBNAIL AND IMAGE PASTING */ - /* ======================================================================== */ - - var read_image = function(event) { - - /* Check if we have something to load */ - var items = (event.clipboardData || event.originalEvent.clipboardData).items; - if ((!items) || (!items[0])) { - console.warn('No items to load'); - return; - } - - /* Check we have an image */ - if (!items[0].type.match(/image\//)) { - console.warn('Cannot load type ' + items[0].type); - return; - } - - /* Load the "file" as a data URL */ - $(new FileReader()).on('load', event.data, function(event) { - - /* Create an image from the contents */ - $(new Image()).on('load', event.data, function(event) { - var width = this.width; - var height = this.height; - var data = this.src; - - /* We might have to rescale the image */ - if (event.data.size) { - if ((width > event.data.size[0]) || (height > event.data.size[1])) { - var stretchX = event.data.size[0] / width; - var stretchY = event.data.size[1] / height; - if (stretchY < stretchX) stretchX = stretchY; - if (stretchX < stretchY) stretchY = stretchX; - width = Math.floor(width * stretchX); - height = Math.floor(height * stretchY); - console.log('Rescaling to ' + width + 'x' + height); - } - - /* Use a canvas to resize the image */ - var canvas = $('').attr({ width: width, height: height })[0]; - var context = canvas.getContext('2d'); - context.drawImage(this, 0, 0, width, height); - data = canvas.toDataURL(); - } - - /* Slap the thumbnail as a background source for the target */ - if (event.data.handler) event.data.handler({ width: width, height: height, data: data}); - - /* Trigger loading of the image source */ - })[0].src = event.target.result; - - /* Trigger reading the pasted item */ - })[0].readAsDataURL(items[0].getAsFile()); - } - - var thumbnail_shown = function(event) { - var passbook = event.data; - - /* A handler to slap the image in the thumbnail */ - var handler = function(image) { - var target = passbook.$container.find('.passbook-thumbnail'); - var background = 'url(' + image.data + ')'; - target.css({ width: image.width, - height: image.height, - background: 'url(' + image.data + ')' }) - .addClass('passbook-has-image') - .popover('hide') - .next('.popover').css('display', 'none'); - } - - /* Trigger our handler on paste */ - $(document).on('paste', { passbook: passbook, size: [90, 90], handler: handler }, read_image); - } - - var thumbnail_hidden = function(event) { - $(document).off('paste'); - } - - var logo_shown = function(event) { - var passbook = event.data; - - /* A handler to slap the image in the thumbnail */ - var handler = function(image) { - var target = passbook.$container.find('.passbook-logo'); - var background = 'url(' + image.data + ')'; - target.css({ width: image.width, - height: image.height, - background: 'url(' + image.data + ')' }) - .addClass('passbook-has-image') - .popover('hide') - .next('.popover').css('display', 'none'); - } - - /* Trigger our handler on paste */ - $(document).on('paste', { passbook: passbook, size: [160, 50], handler: handler }, read_image); - } - - var logo_hidden = function(event) { - $(document).off('paste'); - } - - var clear_image = function(event) { - var image = $(event.target).parent('.passbook-has-image'); - image.removeAttr('style').removeClass('passbook-has-image'); - event.preventDefault(); - event.stopPropagation(); - } - - /* ======================================================================== */ - /* CONSTRUCTOR */ - /* ======================================================================== */ - - var Passbook = function (element) { - this.$container = $($('
')) - .append($('
') - .append($('
') - .append($('
')) - .append($('') - .append($('') - .append($(' - .append($('') - .append($(' - ) //
')) - .append($('')) - ) //
')) - ) //
- .append($('
') - .append($('
')) - ) //
- .append($('
')) - .append($('') - .append($('') - .append($('') - .append($(' - ) // - .append($('') - .append($('') - .append($(' - ) // - ) //
')) - .append($('')) - ) //
')) - .append($('')) - ) //
- .append($('') - .append($('
').on('click', this, _add_empty_extra_fields)) - .append($('
')) - .append($('')) - ) //
- .append($('') - .append($('
').on('click', this, _add_empty_extra_fields)) - .append($('
')) - .append($('')) - ) //
- .append($('
')) - .append($('
').on('click', this, _flip)) - .append($('
').on('click', this, _edit_save)) - ) //
- .append($('
') - .append($('
').on('click', this, _flip)) - .append($('
') - .append($('')) - .append($('
').on('click', this, _add_empty_back_fields)) - ) //
- ) // - ) // - ; // - - /* Other initialization, after the HTML is done, */ - var $element = $(element); - $element.append(this.$container); - - /* Current properties */ - this.type = $element.data('passbook-type') || TYPE_GENERIC; - this.transport = $element.data('passbook-transport') || TRANSPORT_GENERIC; - this.barcode = ''; - this.barcodeType = ''; - } - - - /* ======================================================================== */ - /* CONSTANTS */ - /* ======================================================================== */ - - Object.defineProperty(Passbook.prototype, 'TYPE_BOARDING_PASS', { value: TYPE_BOARDING_PASS }); - Object.defineProperty(Passbook.prototype, 'TYPE_COUPON', { value: TYPE_COUPON }); - Object.defineProperty(Passbook.prototype, 'TYPE_EVENT', { value: TYPE_EVENT }); - Object.defineProperty(Passbook.prototype, 'TYPE_STORE_CARD', { value: TYPE_STORE_CARD }); - Object.defineProperty(Passbook.prototype, 'TYPE_GENERIC', { value: TYPE_GENERIC }); - - Object.defineProperty(Passbook.prototype, 'TRANSPORT_AIR', { value: TRANSPORT_AIR }); - Object.defineProperty(Passbook.prototype, 'TRANSPORT_BOAT', { value: TRANSPORT_BOAT }); - Object.defineProperty(Passbook.prototype, 'TRANSPORT_BUS', { value: TRANSPORT_BUS }); - Object.defineProperty(Passbook.prototype, 'TRANSPORT_TRAIN', { value: TRANSPORT_TRAIN }); - Object.defineProperty(Passbook.prototype, 'TRANSPORT_GENERIC', { value: TRANSPORT_GENERIC }); - - - /* ======================================================================== */ - /* FUNCTIONS */ - /* ======================================================================== */ - - Passbook.prototype.edit = function() { - /* Check if we're editing */ - if (this.mode == 'edit') return; - - /* Trim all the content */ - this.$container.find('th,td').not('.passbook-logo') - .attr('contenteditable', true) - .on('blur', this, _content_edited); - - /* Remove extra fields when empty */ - this.$container.find('.passbook-extra-fields [contenteditable]') - .on('blur', this, _remove_empty_extra_fields); - this.$container.find('.passbook-back-fields [contenteditable]') - .on('blur', this, _remove_empty_back_fields); - - /* Popover for barcode */ - this.$container.find('.passbook-barcode') - .on('shown.bs.popover', this, barcode_shown) - .popover({ animation: false, - html: true, - placement: 'top', - trigger: 'click', - title: 'Barcode contents', - content: barcode_popover }); - - /* Popover for thumbnail */ - this.$container.find('.passbook-thumbnail') - .on('shown.bs.popover', this, thumbnail_shown) - .on('hidden.bs.popover', this, thumbnail_hidden) - .popover({ animation: false, - html: false, - placement: 'left', - trigger: 'click', - content: 'Paste a logo' }); - - /* Popover for thumbnail */ - this.$container.find('.passbook-logo') - .on('shown.bs.popover', this, logo_shown) - .on('hidden.bs.popover', this, logo_hidden) - .popover({ animation: false, - html: false, - placement: 'right', - trigger: 'click', - content: 'Paste a thumbnail' }); - - /* Other editors for colors, type, transport... */ - this.$container.find('.passbook-front').on('click', this, passbook_picker_toggle); - this.$container.find('.passbook-transport').on('click', this, transport_toggle); - this.$container.find('.passbook-clear').on('click', this, clear_image); - - /* Class marker */ - this.$container.addClass('passbook-edit'); - } - - Passbook.prototype.save = function() { - /* Check if we're editing */ - if (this.mode != 'edit') return; - - this.$container.find('[contenteditable]') - .removeAttr('contenteditable') - .off('blur'); - this.$container.removeClass('passbook-edit'); - this.$container.find('.passbook-barcode') - .off('shown.bs.popover') - .popover('destroy'); - this.$container.find('.passbook-thumbnail') - .off('shown.bs.popover') - .popover('destroy'); - this.$container.find('.passbook-logo') - .off('shown.bs.popover') - .popover('destroy'); - - this.$container.find('.passbook-front').off('click'); - this.$container.find('.passbook-transport').off('click'); - - this.$container.find('.passbook-picker') - .removeAttr('style') - .empty(); - } - - Passbook.prototype.flip = function() { - this.$container.toggleClass('passbook-flipped'); - } - - /* ======================================================================== */ - /* PROPERTIES */ - /* ======================================================================== */ - - Object.defineProperty(Passbook.prototype, "type", { - get: function () { - if (this.$container.hasClass(TYPE_BOARDING_PASS_C)) return TYPE_BOARDING_PASS; - if (this.$container.hasClass(TYPE_COUPON_C)) return TYPE_COUPON; - if (this.$container.hasClass(TYPE_EVENT_C)) return TYPE_EVENT; - if (this.$container.hasClass(TYPE_STORE_CARD_C)) return TYPE_STORE_CARD; - return TYPE_GENERIC; - }, - set: function(value) { - var cls; - if (value == TYPE_BOARDING_PASS) cls = TYPE_BOARDING_PASS_C; - else if (value == TYPE_COUPON) cls = TYPE_COUPON_C; - else if (value == TYPE_EVENT) cls = TYPE_EVENT_C; - else if (value == TYPE_STORE_CARD) cls = TYPE_STORE_CARD_C; - else if (value == TYPE_GENERIC) cls = null; - else throw ('Unsupported passbook type "' + value + '"'); - - this.$container.removeClass(TYPE_C); - if (cls != null) this.$container.addClass(cls); - } - }); - - Object.defineProperty(Passbook.prototype, "transport", { - get: function () { - /* Transport available only in boarding passes */ - if (!this.$container.hasClass(TYPE_BOARDING_PASS_C)) return null; - - /* Transport available only in boarding passes */ - if (this.$container.hasClass(TRANSPORT_AIR_C)) return this.TRANSPORT_AIR; - if (this.$container.hasClass(TRANSPORT_BOAT_C)) return this.TRANSPORT_BOAT; - if (this.$container.hasClass(TRANSPORT_BUS_C)) return this.TRANSPORT_BUS; - if (this.$container.hasClass(TRANSPORT_TRAIN_C)) return this.TRANSPORT_TRAIN; - return TRANSPORT_GENERIC; - }, - set: function(value) { - var cls; - if (value == TRANSPORT_AIR) cls = TRANSPORT_AIR_C; - else if (value == TRANSPORT_BOAT) cls = TRANSPORT_BOAT_C; - else if (value == TRANSPORT_BUS) cls = TRANSPORT_BUS_C; - else if (value == TRANSPORT_TRAIN) cls = TRANSPORT_TRAIN_C; - else if (value == TRANSPORT_GENERIC) cls = null; - else throw ('Unsupported transport type "' + value + '"'); - - /* Set the class irregardless of pass type */ - this.$container.removeClass(TRANSPORT_C); - if (cls != null) this.$container.addClass(cls); - } - }); - - Object.defineProperty(Passbook.prototype, "color", { - get: function () { - return this.$container.find('.passbook-color').css('background-color'); - }, - set: function (color) { - color = $('
').css('color'); - if ((color == null) || (color == '')) return; - this.$container.find('.passbook-color').css('background-color', color); - } - }); - - Object.defineProperty(Passbook.prototype, "shading", { - get: function () { - var shading = this.$container.find('.passbook-shading').css('opacity'); - shading = Math.round(((Number(shading) / 2) * 3) * 100) / 100; - if (shading < 0) shading = 0; - else if (shading > 1) shading = 1; - return this.$container.hasClass('passbook-white') ? shading : -shading; - }, - set: function (shading) { - if (shading < 0) { - shading = -shading; - this.$container.removeClass('passbook-white'); - this.$container.find('.passbook-color').css('color', 'rgba(0,0,0,' + shading + ')'); - this.$container.find('.passbook-shading').css('opacity', shading / 3 * 2); - } else { - this.$container.addClass('passbook-white'); - this.$container.find('.passbook-color').css('color', 'rgba(255,255,255,' + shading + ')'); - this.$container.find('.passbook-shading').css('opacity', shading / 3 * 2); - } - } - }); - - Object.defineProperty(Passbook.prototype, "foreground", { - get: function () { - /* Get (and parse) the color */ - var color = this.color; - var matches = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(color); - if (matches == null) throw 'Invalid color ' + color + ' found???'; - var r = Number(matches[1]); - var g = Number(matches[2]); - var b = Number(matches[3]); - - /* Get the shading (alpha) and calculate */ - var shading = this.shading; - var rf, gf, bf; - if (shading < 0) { - shading = - shading; - rf = Math.round(0 * shading + r * (1 - shading)); - gf = Math.round(0 * shading + g * (1 - shading)); - bf = Math.round(0 * shading + b * (1 - shading)); - } else { - rf = Math.round(255 * shading + rb * (1 - shading)); - gf = Math.round(255 * shading + gb * (1 - shading)); - bf = Math.round(255 * shading + bb * (1 - shading)); - } - - /* Build CSS color and return */ - return 'rgb(' + rf + ", " + gf + ", " + bf + ")"; - }, - set: function () { - throw 'Foreground is a read-only property'; - } - }); - - Object.defineProperty(Passbook.prototype, "mode", { - get: function () { - if (this.$container.hasClass('passbook-edit')) { - return 'edit'; - } else { - return 'view'; - } - }, - set: function () { - throw 'Mode is a read-only property'; - } - }); - - /* ======================================================================== */ - /* JQUERY INTEGRATION */ - /* ======================================================================== */ - - /* Initialize a "Passbook" object and structure */ - $.fn.passbook = function (option) { - var returnValue = null; - var eachReturnValue = this.each(function() { - var $this = $(this); - var data = $this.data('passbook'); - - if (!data) { - data = $this.data('passbook', (data = new Passbook($this))); - } - - if (option == 'edit') data.edit(); - if (option == 'save') data.save(); - if (option == 'flip') data.flip(); - if ((option == 'data') && (!returnValue)) returnValue = data; - }); - return returnValue || eachReturnValue; - } - -}(jQuery); \ No newline at end of file diff --git a/passbook.min.css b/passbook.min.css deleted file mode 100644 index acd4112..0000000 --- a/passbook.min.css +++ /dev/null @@ -1 +0,0 @@ -div.passbook-container{width:320px;min-width:320px;max-width:320px;height:450px;min-height:450px;max-height:450px;position:relative;perspective:1000;-webkit-perspective:1000;font-family:"Helvetica Neue","Helvetica","Arial",sans-serif;color:#000}div.passbook-container table td,div.passbook-container table th{text-align:center;vertical-align:top}div.passbook-container table td:last-child,div.passbook-container table th:last-child{font-weight:400;text-align:right}div.passbook-container table td:first-child,div.passbook-container table th:first-child{font-weight:400;text-align:left}div.passbook-container .passbook-color{background-color:#325bb9}div.passbook-container .passbook-shading{opacity:1}div.passbook-container.passbook-white{color:#fff}div.passbook-container.passbook-white .passbook-shading{filter:invert(100%);-webkit-filter:invert(100%)}div.passbook-container div.passbook-flipper{width:320px;min-width:320px;max-width:320px;height:450px;min-height:450px;max-height:450px;position:relative}div.passbook-container div.passbook-front{width:320px;min-width:320px;max-width:320px;height:450px;min-height:450px;max-height:450px;border-style:none;border-radius:6px;backface-visibility:hidden;-webkit-backface-visibility:hidden;z-index:2;position:absolute;left:0;top:0}div.passbook-container div.passbook-front:before,div.passbook-container div.passbook-front:after{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAalpVFh0WE1MOmNvbS5hZG9iZS54bXAAAQAAADiNdZNdb4IwFIbv/RUNu4YCajYb7MUguzMzbkv0skJ13YCStkb892v5mKSpXNFz3ue8pyc9SYvaqqmoIqCtylqidu2Rgh8p0v8mDD3QSdTv2ttvtiDlgoJlsAhCD88AAIkoTmiXvQ24Pq29b6UaBOH1eg2u84CLM4xWqxUMYxjHvlb48lYr0vq1fOqLjHUyKnPBGsV4DcyZHPlFrT1v0PRfb6TY6e5Uy6BrOsh5BU0GRkEIXRht2QPMZB5iRf4PNRdRdncqckhLWtFaSc1FTk4Pzu3WkqY3w3cqMZ2jHZW8vJgRfNVM4SiBrrBNpbxqBJVS5/FyQKYxW7+/18PP8QBMgzbwLpi+KelyY0/TmK0/uAwObgMzerRlLS33GdMD7Tp+CRPoTNhgyksuPhqSU9OYHXLaHB7ZHJw2RY7k5fhD8+ncxzf7Ss5wKoZOdaJfAtrwgp1uGVEUx2G08MPIj+efUYzCCIW6D0tj0amgRHHxyXmJu2YrcwTzYCCn+XGpoLVV/crCYWfxTJPj/uPZH/jYOdNSxPPgAAAC4klEQVR42u2dQU7iYBiGS2LUxBtoQtG9Lh0uYQxbuAKz9hCEWQxk2DGLCVsxHgA34wH0AJoYHI07XGDUmGcW/Dg6Fmn/FtrS90ncGJDypK1/v37fW8eJESAHFIAvQAVoAifAGdAHhuanb353Yl5TMe8pADknSwBbQAn4BpwCf4AXgvNi3ntq/lYJ2FpUaRtmr+kCt8yOW/MZFWBjEcTtAN+BK+bPlfnsnTSKKwK/gAHxMzDbUkyDOBf4YU78SWNots1NorgV4Kv5b5l0+mZbV5IibxM4In0cAZtxy9sHLkgvF8B+XAvgA+CR9PNovktuXvKWgRqLRw1YnrW8NaDN4tIG1ma55/1k8WlHvieac16N7FCL9JxoTrJZ4yAqeXvAUwYFPgF7YeUVgEuyyyVQsJW3ChwjjoFVG4FVuXulGlRePiWFgXkWIPJBBLbk7AOtIMXQoXx51hOLfgR25GoinWnytklGGT6pDIDtzwQ25WgqzUny1oFr+ZnKNbDuJbAsN74pewnsyotvul7XvHfy4pu7d9fIjPpKRDBKbwXW5SMw9bG8JUYdTiIYv4GlcTvGjXwE5gZwHWAXeJaPwDwDuw6jXjphR8UBGvJgTcMBevJgTc9h1Lwt7DhzUOk+DH0HeJAHax4kMAKBOoRDHsLn8mDNuZYxESxjtJAOuZDWpVzISzkVE0IWE1xUzrLhtZylgqodo4KqSvrW1HVTKRwl3da05/1tTd1YD0xXrR3hKKu5yB7v5iK1t/mmOa3B8l6OJnLPZw2WavGdSkdN5vb4azLXmMNEWhq0sSfYoI1GvT5Q1bChPXbDhhp3BcKMu2rgOoKBa438K3TClmhDJ97EnrQzIC/62BMF7yj6ye9hO9voJ4WPKf7uf+KJv1MAoyJAkxMB6lHFSXoIbd5JOigGWUHcSYyCLwOHzD4K/tB8Vvqj4CfI1MMIIl6Qu/x7HEaDUc/2pMdh9Mxrxo/DcIn5cRh/AY9LJb2h3Y5pAAAAAElFTkSuQmCC');position:absolute;background-repeat:repeat;background-size:8px 8px}div.passbook-container div.passbook-front .passbook-moreinfo{position:absolute;right:15px;top:410px;font-family:FontAwesome;text-align:right;font-size:20px;display:block;cursor:pointer;opacity:.5}div.passbook-container div.passbook-front .passbook-moreinfo:before{content:'\00f05a'}div.passbook-container div.passbook-front .passbook-editsave{position:absolute;left:15px;top:410px;font-family:FontAwesome;text-align:left;font-size:20px;display:block;cursor:pointer;opacity:.5}div.passbook-container div.passbook-front .passbook-editsave:before{content:'\00f044'}div.passbook-container div.passbook-front table.passbook-header{position:relative;top:5px;width:305px;height:50px;margin:0 5px}div.passbook-container div.passbook-front table.passbook-header .passbook-logo{position:relative;background-color:rgba(0,0,0,0.4);width:50px;height:50px;margin:5px 5px 0 5px;display:none}div.passbook-container div.passbook-front table.passbook-header .passbook-logo.passbook-has-image{display:table-cell}div.passbook-container div.passbook-front table.passbook-header .passbook-title{text-align:left;font-size:19px;padding:12px 3px 0 8px;font-weight:300}div.passbook-container div.passbook-front table.passbook-header .passbook-header-label{padding-top:3px;text-align:right;font-size:12px;line-height:12px}div.passbook-container div.passbook-front table.passbook-header .passbook-header-value{text-align:right;font-size:22px;line-height:22px;padding-top:4px}div.passbook-container div.passbook-front div.passbook-thumbnail{position:relative;background-color:rgba(0,0,0,0.4);width:90px;height:90px;float:right;margin:20px 15px 0 5px;display:none}div.passbook-container div.passbook-front div.passbook-thumbnail.passbook-has-image{display:block}div.passbook-container div.passbook-front div.passbook-transport{display:none;z-index:999}div.passbook-container div.passbook-front table.passbook-primary{position:relative;top:12px;margin:0 15px;height:90px;max-width:290px;margin-bottom:20px;clear:left}div.passbook-container div.passbook-front table.passbook-primary .passbook-primary-label-2,div.passbook-container div.passbook-front table.passbook-primary .passbook-primary-value-2{display:none}div.passbook-container div.passbook-front table.passbook-primary td{font-size:30px;line-height:35px}div.passbook-container.passbook-edit table.passbook-header td.passbook-logo{display:table-cell}div.passbook-container.passbook-edit div.passbook-front div.passbook-thumbnail{display:block}div.passbook-container.passbook-edit .passbook-editsave:before{content:'\00f046' !important}div.passbook-container.passbook-boarding-pass div.passbook-front div.passbook-thumbnail{display:none}div.passbook-container.passbook-boarding-pass div.passbook-front .passbook-transport{position:absolute;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAqCAYAAADFw8lbAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAgZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAQAAADiNfZTBjpswEIbveQpEz2BgiapYgNoN6qqHVaPtVkpOlQMOcWtsZBuFvH1tIA1ynXLCM/83/3iMyQY4tF2LFfKGljIJh9xHNT9iqN9NGPjeKFG/c3//uvO2XGBvHaZh5Bcrz/MyUZ/gW/llxvUq989KdRCAy+USXp5CLhoQbzYbECUgSQKtCOSVKTQETH6YitzqlFhWgnSKcOaZNTryXuW+P2umZzJS5HR3YjIcmw4r3gKTAXEYAReGB/IAM5mHWF39hbpe0HFPdQUwxS1mSmoudnJ6cG63AXWTWXGnMtM5fMOS096M4Acjqogz4Arb1Ja3ncBS6nyxnpFlzNbv7/WKOE1nYhm1iW+C6K2iiZj1y5itPzgdDv9x2J254vqbE6T6yhQWuvm5djLTjxWLWuYg4Y4MmO5Loo9n3H+qSzgTNrjllIvvHaqw2aUdctocHtkcnDZ1BWV//IWr5SnebsAzasBSDJxqU6O+3xVHnc/Uqn5LUGI+TUgRa3J/CGp8Qj1VfvHMkagJa3ZIyp8vmGE94xd67c6fkiHsWJOBiba8wL9mY8/u7jJ9H+Arr8npWiKFiySK0yCKgyR5j9cwiuFHPXNLY9FbgZHi4p1zWoxDbs3SewqjiVzmV8smS6ujKar/XMVKk7e/YLH6A0/8iKVnGzG4AAABIElEQVRYw+3YvWrCUBjGcT8GK2jauZv34FqsihQkovjR2xCdvJDOgh+dalR6Iy5eg9jqYByk0EGfQCbJeQMO8YmeF/5j4MdJTk5IJKJHjx49dzOxMCCjqIuWaOFRH6VZsAay0FHRFxM2iT4F7IQJ+4DGPliDaWUlrMWGHflgH5keg6GAnbJhBwJ2FjbsE9PB8IH+L8VmUCeA2qiH1sLKziVsVbjwGimxJhnU6Rs9hwF6QG/n0AoZco/evW59Cf0G1Ar9+SBbqs0UR6kASqCyC1Yhmwzv0Bd3RamROeH96SAbDMhX9KNA2izIvIB0VrLOgCwIG8dmQm7YkUUfZI0B6RweWwVyx4I0hVPHdr/SKP6U5NwzuulRVv/x0qNHz43NCcUhXd/DIOmHAAAAAElFTkSuQmCC');width:42px;height:42px;left:134px;top:70px;background-color:transparent;opacity:.4;display:block}div.passbook-container.passbook-boarding-pass div.passbook-front .passbook-primary{width:290px;height:70px}div.passbook-container.passbook-boarding-pass div.passbook-front .passbook-primary .passbook-primary-label-2,div.passbook-container.passbook-boarding-pass div.passbook-front .passbook-primary .passbook-primary-value-2{display:table-cell}div.passbook-container.passbook-boarding-pass div.passbook-front .passbook-primary th{font-size:11px;font-weight:400px}div.passbook-container.passbook-boarding-pass div.passbook-front .passbook-primary td{font-weight:100;font-size:40px;line-height:42px}div.passbook-container.passbook-boarding-pass.passbook-transport-air div.passbook-transport{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAqCAYAAADFw8lbAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAgNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAQAAADiNfZTNjpswFIX3eQpE12BgyCIWoOkEtepi1Gg6lZJV5YBD3Bob2UYhb18bSINcZ1jhe893z/VvNsCh7VqskDe0lEk45D6q+RFD/W/CwPdGifqT+/vXnbflAnvrMA0jv1h5npeJ+gTfyi8zrke5f1aqgwBcLpfw8hRy0YB4s9mAKAFJEmhFIK9MoSFg8tNU5FanxLISpFOEM8+M0ZH3Kvf9WTN9k5Eip7sTk+HYdFjxFpgMiMMIuDA8kAeYyTzE6uof1PWCjnOqK4ApbjFTUnOxk9ML53YbUDeZFXcqM53DNyw57c0S/GREFXEGXGGb2vK2E1hKnS/WM7KM2fr9vV4Rp+lMLKM28V0QPVU0EbN+GbP1B6fD4QOH3Zkrrs+cINU3prDQzc+1k5l+rFjUMhsJd2TAdF8SvT3j/FNdwpmwwS2nXPzoUIXNLO2Q0+bwyObgtKkrKPvjb1wtd/F2A15QA5Zi4FSbGvX9rjjqfKZW9VuCEnM0IUWsyf0hqPEJ9VT5xQtHoias2SEpf+10Gn+l1+78nAxhx5oMTKzlBP63Gjt295bp2wBfeU1O1xIpXCRRnAZRHCTJe7yGUQxjfXItjUVvBUaKi3fOaTEucWuG3lMYTeQyv1o2WVodTVH9bhUrTd7ewGL1Fwf8h9ZX0ysBAAACg0lEQVRYw+3YS6jOeRzH8ZfLcdwWrmPOYpJjyKVYKMNkkEmRLCamho2DLBApUiiMBYvJNKesbHTKYTWhEEVsxk5CCYlxG5OZGhyXcTuPzVf9+/c8x3me+ctv6nzqu/x+/+/nd/l8v7+HLnWpag3AaAxPHXQmHuIPbEW3VEH74jxKaMeSlFd1ZYCW8CcmpAo6FLczsGfREKtdlxrsTxnQEu7gasSmlEDHoy0H24bTWJUSaDf8mgO9j1EpntX5eJuDPZTiOe2HiznQUrhCctpcBvQRjuAA9mBSCqBj8bgMbAnP8Du+L+pjS7EI42rI7Y4TFUCPYXCRq/JLFH6Ar2vI31AB9C1WFwk6Gf9G8csYVmX+NLypAPsIU4sc3a5lih+s0mJGBFCpQlyKtluI9ueKb+yE4ddhENbidQegJbSiEZ9jIPrU6rfLcoWfR89ejOVYh+1oRkvYz2/R40udjCf4C3dxBeeiuzVjTRyhnh1BNmBvFR/8WNEeP76i+mNLmcSXsbKvyrTKouNN7E7zh7Z+bS7xHr6JKWkKZmNBeO567IxdONWB4WfjNS7Edp+MC7snnjNNmNHZC3c4V/S7Kgx/XsbeKsWP6BVnsHutN/6zaHXvi+6qMv/LMrNpNo6jvghr+jYO8vuifarMn53Jz8et8NlC1IKncX4aa8jfUQGyDXOKbKGzMBG9a8itD0spB3o0/qyol4C+6sRFWpYC6O4yYDewLaaqJnzxqSGH4GYO8hXmpvYMaSqzmrtTg6zDmRzkTYz5L4b+MTQttjnfr+/i55RA9+WmnjMxsrXih1QgR+LvDGgLeqT4lt+WgbwSU3tyGojrAfkPpktUCwPyBVbo0v9M7wCFmE0EOE2LvwAAAABJRU5ErkJggg==')}div.passbook-container.passbook-boarding-pass.passbook-transport-boat div.passbook-transport{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAqCAYAAADFw8lbAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAgFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAQAAADiNfZTNjpswFIX3eQpE12BgyCIWoOkEtepi1Gg6lZJV5YBD3Bob2UYhb18bSINcZ1jhe893z/VvNsCh7VqskDe0lEk45D6q+RFD/W/CwPdGifqT+/vXnbflAnvrMA0jv1h5npeJ+gTfyi8zrke5f1aqgwBcLpfw8hRy0YB4s9mAKAFJEmhFIK9MoSFg8tNU5FanxLISpFOEM8+M0ZH3Kvf9WTN9k5Eip7sTk+HYdFjxFpgMiMMIuDA8kAeYyTzE6uof1PWCjnOqK4ApbjFTUnOxk9ML53YbUDeZFXcqM53DNyw57c0S/GREFXEGXGGb2vK2E1hKnS/WM7KM2fr9vV4Rp+lMLKM28V0QPVU0EbN+GbP1B6fD4QOH3Zkrrs+cINU3prDQzc+1k5l+rFjUMhsJd2TAdF8SvT3j/FNdwpmwwS2nXPzoUIXNLO2Q0+bwyObgtKkrKPvjb1wtd/F2A15QA5Zi4FSbGvX9rjjqfKZW9VuCEnM0IUWsyf0hqPEJ9VT5xQtHoias2SEpf+mB+kqv3fk5GcKONRmYUMsI/O80NuxuLdOXAb7ympyuJVK4SKI4DaI4SJL3eA2jGG6iDFgai94KjBQX75zTYlzh1gy9p3Aml/nVssnS6miK6merWGny9gQWq79jDYdvtjX8cAAAAuFJREFUWMPtmFuITlEUxz8zrlPD1LhMER7klhmU4oWEKEIa+sjbuDRIROTBwySUN1GkKZ48DJoxUUpkEHn70vBAo9zqwzDJ5zpjjP+qv9od5+xz2WvOvHyrfjXfvqz1n73PPmvtk8kUrWixbQi4DO6Cesu43RxzCQweCKGloBP0gROWcSc55l3aAmVVloD14BNFXAGrArjKMR9BLeeWpiF0FIP2JeQ9GJGG0JHgjYPQl2kJLVcQOrw/BZ4B7eAp6HEQ2k0f4uuUtsgS8MQT8A/xa7P1mW2PwSBNoZXgNZ2vA9MMFoAfoMnTLrSwb76nPUtfr0CFptCZ4DOdT/TpL/B96fe4FHzap9JXF4Wr2WLQS+dHwBaDveAXuMffW4n8/YB9ezxzjtGXPOuLNIVucjg8YWzQFHooYtD7YBt5GHHOfk2hZ0OCPQN1ntQoqXY7+2xzT2sKvREQRAqNBuPkTqBYYTzbKvhcdwb4uK5ZhLR7nMsr5zyYwjGTQSPLuaFgGA+X7MQkjpHTfQH89HmXlmgIrfKkTFndhUY6PQjy7HvOPF4GXrAtzzHlnCNzbxr+5P08RkPoXK5CjqXdP8tyNczVyVOQFC4ffFYu65mf4+7UaAidA3YahcRybqvf8/YFjOYuFALGtIGl9CU+d4HZmgdqFtPkb8sJ/s7ndjpXylaYXAQzNAVW8arRFbEymsf83x1hvNwQjjNGYpNt2QE6YmSZXm7rCp9KyUYHY8WqU6XsWgseJUyJtUZ1FBeJuTqKSHm2Wh1zdx0zUtL5shPNrLAC7ZpCkbEPHFDw02IT2qoQ4CgPiKufZpvQzQoBpFg+p+Bno03oOOPKkZQmfupx8SE31bFhB6rRMcgtcEdhV0JtWUj2CSPnUwPEoYdXn1ArcwwkldZbx3808peUBodA30LyfBiH41ZMX/vxQheEVFzVcb99tg2A0NtJPkmuSXlVpZZdmbSCquFbIA2qM0Ur2v/2F0RI8nsDEGpaAAAAAElFTkSuQmCC')}div.passbook-container.passbook-boarding-pass.passbook-transport-bus div.passbook-transport{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAqCAYAAADFw8lbAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAgNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAQAAADiNfZTNjpswFIX3eQpE12AgRGosgtoEtepi1GhmKiWrygGHuDU2so1C3r42kAa5Tlnhe893z/Vv1sO+aRuskNc3lEnYb3xU8ROG+t+Ege8NEvV74x9e9t6OC+ytwjSM/HzheV4mqjN8Lb5MuB5t/ItSLQTger2G12XIRQ3i9XoNogQkSaAVgbwxhfqAyQ9jkXudAstSkFYRzjwzRifeqY3vT5rxG40UOT+cmAyHpsOSN8BkQBxGwIXhnjzBTOYpVpV/obYTdJhTVQJMcYOZkpqLnZxeOLdbj9rRLH9QmekcvmLJaWeW4AcjKo8z4Arb1I43rcBS6ny+mpB5zNYfHvXyOE0nYh61ie+C6KmikZj085itPzodjv9x2F+44vrMCVJ+YwoL3fxUO5no54pZLbORcE96TA8F0dszzD/VJZwJG9xxysVbi0psZmmHnDbHZzZHp01VQtmdfuFyvov3G7BFNZiLgVNtalSPu+Ko85la1e8JSszRhBSxeuP3QYXPqKPKz7cciYqweo+k/Lnt5Fd6ay+fkj5sWZ2BkbR8wL9GQ7/uzjJ9F+ALr8j5ViCF8ySK0yCKgyR5j1cwiuHHZQYsjUXvBEaKi3fOaT4scGOG3jKMRnKeX8ybLKyOxqh+tfKFJu8vYL74A8uqhxVz+K9rAAACBUlEQVRYw+2ZSyhEURjHJyXklbCwpZlQKIyNkiSUZGNtKwuLSRZSRlJmTI2FPEeSBYuJKVnZSGZj4RHJZjaMGCWN8srk8T91pqbTvcPc812P3K9+m5n6z68z537ncU0mo4z6chWDdtAPFoAXbIHtOGyAZeAEnaAGZOghl8l/gAndgndJIuAEjIBCKsk6sEsgp8Y1GACpMpJt4E4IfgTzYBAMJYidj+KpgvASSNMiaQaXCoFHIFnyX+pRGV27lrBhlbB9AtEulewLUJBo2KZK2BVoAVWgWgNWsBhnztYnKur/5CF4BW8aiZfbnKjojhBwBmaBA7gkYf3UzXusKNokIxrgDxd1sbk+Ryk6oeNKVylMBynRMZ2X5AiVqEtH0RJD1BAlEHXqKGqhFF3RUbSVso++8B26gxg3X/HIRL8TQ/TXiYZBiFAozPe2pKI+UASy+THiWVJyne/GskA3eKIQvVE40q5KjqRFyPNSiJ6DXOG7SQlRNn3yhLwpClG2V7TFfF7G5bWKsiNMX0xeqdBLpRv+GpjmJ0WKmxIfzwv+m/bk/yuioz8gGdJyacZ6podPfvHu6QDsSRBUkAxoGc1olYMHIfBQ62VWTNkURGdkj7LiKnQM0iVFexVEPTKBOQoP1ThIkhS18nvRaOY96JDdgeeDBtAIakEK0c7ezDMZFcYbB6NU6gPw+3VYJ4miuQAAAABJRU5ErkJggg==')}div.passbook-container.passbook-boarding-pass.passbook-transport-train div.passbook-transport{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAqCAYAAADFw8lbAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAgNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAQAAADiNfZTNjpswFIX3eQpE12BgmEUsQNMJatXFqNE0lZJV5YBD3Bob2UYhb18bSINcZ1jhe893z/VvNsCh7VqskDe0lEk45D6q+RFD/W/CwPdGifqT+/u3rbfhAnvPYRpGfrHyPC8T9Qm+l19mXI9y/6xUBwG4XC7h5SnkogHxer0GUQKSJNCKQF6ZQkPA5KepyK1OiWUlSKcIZ54ZoyPvVe77s2b6JiNFTncnJsOx6bDiLTAZEIcRcGF4IA8wk3mI1dU/qOsFHedUVwBT3GKmpOZiJ6cXzu02oG4yK+5UZjqH71hy2psl+MmIKuIMuMI2teFtJ7CUOl88z8gyZuv393pFnKYzsYzaxHdB9FTRRMz6ZczWH5wOhw8ctmeuuD5zglTfmMJCNz/XTmb6sWJRy2wk3JIB031J9PaM8091CWfCBjeccvGjQxU2s7RDTpvDI5uD06auoOyPv3G13MXbDXhFDViKgVNtatT3u+Ko85la1W8JSszRhBSxJveHoMYn1FPlF68ciZqwZouk/LUTiLCv9NqdX5Ih7FiTgYm1nMD/VmPH7t4yfRvgG6/J6VoihYskitMgioMk2cUpjGJoTomlseiNwEhxseOcFuMSt2boPYXRRC7zq2WTpdXRFNXvVrHS5O0NLFZ/ARYMh+UC2mzrAAACVElEQVRYw+2Y2ytlURzHz4NLJA0eRKZEYRoRJlFEeSPyIt6MjAdPyiVKyj8wklve50HUefCiEOPBPZeUmvIwqampyaXjyP0231W/U6vV2Sx7XZ72rz4Pe+/1+65va6/9W2ttn88LL6SjFKyAFwWWQIlJk60gKHT6ByxK8FfIC5Ke9igEl2FG55tkfmeYXKb3RbfREYfX2CiZ3+aQP6nb6E+Hjtol83sd8ld1G91w6OgK/JLgxiF/U7fRdaGDLTAD/GBWAj+1F3XWTRr9AWJc6kSBCVtGKxS18sCzDaNFilo54MGGUdXa98kz6hk1bLRQUSvbltF6Ra1KW3X0CAyALhf0g0NbRnVi1Og1XR+90xQbyW1ufho1GgDVtGYn0rr/lkG2XA6BOBANmsEdPVszZdQv3C+gEX7N6Dn4KOSt0bMV3UbnSHhBuM82KPdvGA3S+s7voPbp2axuoz0kfAv6QDIV/g3J+TlHhT4FfOd2Tx26jSaBPa7jADfPZLmmvND1Ds1z7ZFFR997xZJ0R1Mo0+TZPhKU05fbxNFCR2eRFqEdyysjHSuRQUfoUTBG8y9cfAbj1G4YpNv8rcNGY557lQfgg0PbRGHJZB9VhC2jrdxXG5DYTRWDC2r/BL7aMJkGjrkROgFTEpxxOb9Bqmmjk5o2I+MmTVa5qJ1O3NK+VHvE0d+RUEesnta5YFn4nROr22ifsCrlutTJF1anbp0mWY085cQHFPUGOa1/dIZSjija2oWEd0G8omYCt3tiTOtYqWqp9oVEGzS9pSZO8xHU+LywGP8B93C0ZJBcREsAAAAASUVORK5CYII=')}div.passbook-container.passbook-edit.passbook-boarding-pass .passbook-transport:hover{opacity:1}div.passbook-container.passbook-coupon div.passbook-front .passbook-primary thead{display:table-footer-group}div.passbook-container.passbook-coupon div.passbook-front .passbook-primary td{font-weight:100;font-size:54px;line-height:54px}div.passbook-container.passbook-coupon div.passbook-front .passbook-primary th{font-size:18px;line-height:18px}div.passbook-container.passbook-event div.passbook-front .passbook-primary th{font-size:12px;line-height:12px}div.passbook-container.passbook-event div.passbook-front .passbook-primary td{font-size:18px;line-height:20px}div.passbook-container.passbook-store-card div.passbook-front div.passbook-thumbnail{display:none}div.passbook-container.passbook-store-card div.passbook-front .passbook-primary thead{display:table-footer-group}div.passbook-container.passbook-store-card div.passbook-front .passbook-primary td{font-weight:100;font-size:54px;line-height:54px}div.passbook-container.passbook-store-card div.passbook-front .passbook-primary th{font-size:18px;line-height:18px}div.passbook-container.passbook-boarding-pass div.passbook-front:before{position:absolute;content:'';background-position:-4px 0;width:4px;height:8px;top:58px}div.passbook-container.passbook-boarding-pass div.passbook-front:after{position:absolute;content:'';width:4px;height:8px;top:58px;left:316px}div.passbook-container.passbook-coupon div.passbook-front{border-radius:0;padding-top:5px}div.passbook-container.passbook-coupon div.passbook-front:before{position:absolute;content:'';background-position:0 -4px;top:0;width:320px;height:4px}div.passbook-container.passbook-coupon div.passbook-front:after{position:absolute;content:'';background-repeat:repeat-x;width:320px;height:4px;bottom:0}div.passbook-container.passbook-event div.passbook-front:before{position:absolute;content:'';background-position:0 -65px;background-size:80px 80px;width:80px;height:15px;left:120px}div.passbook-container table.passbook-extra-fields{position:relative;clear:both;width:290px;margin:8px 15px}div.passbook-container table.passbook-extra-fields.passbook-secondary{display:none}div.passbook-container table.passbook-extra-fields th{font-size:11px;line-height:11px;font-weight:400}div.passbook-container table.passbook-extra-fields td{font-size:16px;font-weight:400}div.passbook-container.passbook-boarding-pass table.passbook-secondary{display:table}div.passbook-container .popover{color:#000}div.passbook-container .passbook-barcode{position:absolute;left:23px;top:330px;background:url('data:image/gif;base64,R0lGODdhAgE5AIAAAAAAAP///ywAAAAAAgE5AAAC/4SPqRfNblp4sipJaYVo+59F3EdiYmktgLmO3IWC6hy2sq299H7WbAmb9E6eYCyFG9qOP6Zw0XyyjE7eLFpUZq28qI8U/N5yTDH5eAarvEpqmRsmbsRT+NolxW+7+PTTHwelQwPUtsO2NJdQaEenmJT41xiIyMiXh7knh1QTeLlVR9i3GWrZiPWIKjnZMQppKooJuKjWutp5WBt65QoLC6da+chKK6tVa2YYi3aHpLnsmhy52/wMrJeKfUssnDl8bGzltB1Jdu082G1d/W0X3NtO/Ao/Bo4LjcKLzpm7T6lNTVA9dwDpBZzUbVYsc8rclNJVRdkzRPrOHeynUJW8f//hfhVjCEnfRIhvQm7ieMnioHMZtW38aI/USpjlGhYbeWPcPZz3PPW7uFBmx3jc6CmU5jBbvpvRMLJbRZFpzhjy3g3ltzGhUJRPQVGV2rOZyHRNbTFixsqqI3IIjW6lGRAtWpBAw9a0ZVfu17QFr9blonXaTIF596p1Oq9kRZtmSVbtu/Yl3piC2cIdrNcbVq6V1002KfDs4JRvE/8V57YyS8aZj4oFN/c16KT+impWN/pUal8uu+aeXZonYo2yaXsmrRr279WJXZvGjKy4VOKfFz8nFzci39sGlwPeHf362M00aYO0K81zdsW6ufv1jvqqc4642X/2ePe8bK/u8SP/F62ZZOlBNpxSfuB3WGhkkXefgUL5V+BUAQrYnHIMRmZhbA0OpF9++znYWXjMAdjhY/IF11t1PzkmEXw6WWjedxdGyF+Jtg0oYYentdaiZY0tJd50LhIVX0sTChgYiSeVt2KOPaoEJHXzPWWikTZuh2ONpbkxXoJKhuhkcj8+BGRb7mGIJHhhIkgkgPxpCSacvA2k4YgsepiVmnKKuKSC+7wJ4jj1kYkThEGJKeVLSYaX6Jh9kTmlimKiGSOYVaJ4pGSL0plipRomaJ1zjRppqHVfHtdelu2Miumcke7EaKdC9gcffYESaaaqWHmJK1i+EtanpwRK2mWtl63ZK0En/06aoaz4cPkhg6fG6uOrNN46o7K6QtrqkLu26ayVWzJWaa6YXmluhcxuyKOf4+mY7KCr7oXutbXheam6bNJ6L7TuBgswsNcVSu1ptt6LqraU7XsgiP76S7CP8n5bZsB2IpvtxWsBxauECa8HclkHd5ywqXeWLOO2v5Gs1MfQSetwtID+mazJGBsc4cYrD+tmvC+HHI7NM4Oa6rkW37gwn+wqrTLMHi+oM6fVkmtvfRTqO6zQTCddsaOZcv2pt/lOm3HKYPvM73+P/twy1M1KzVy6ZON86MTvPtkkoc6qp/SeHI6rMKLhIo3133dxi4/eX+MLOF1Zzzr2yTWbXTjf/btSve7MD0NO5dvFTi3w3MbW3R3CW8eZmk+Mk35m3nfKLXnZRZ5tuuEN1x7q0axbi3rQRQu+eOTv1e5ySVFJivKGvL8I3OzA1xu43e0dDyt2o5MNJXp4Y2n06rAPTzecqq9npt/ZY474937TbXPU5Yu8veqfYHt+89ULv/7o7Xsu3cDzPg3Aza1rfIMbIOVEBzq1ge9lI/vf0NoGFQei7WCfwx+22Bct9/XPKorj4N4kmC3EWS55DRzeAQoAADs=');background-repeat:no-repeat;border:8px solid #fff;border-radius:5px;opacity:.5;width:274px;height:73px;text-align:center;color:#000;display:none}div.passbook-container .passbook-barcode:after{position:relative;top:18px;content:'No barcode';background:#fff;border:4px solid #fff;border-radius:4px;padding:5px}div.passbook-container .passbook-barcode.passbook-barcode-pdf417{background:#fff;width:274px;height:73px;left:23px;top:330px;opacity:1;display:block}div.passbook-container .passbook-barcode.passbook-barcode-pdf417:after{content:none}div.passbook-container .passbook-barcode.passbook-barcode-qrcode{background:#fff;width:139px;height:139px;left:90px;top:290px;opacity:1;display:block}div.passbook-container .passbook-barcode.passbook-barcode-qrcode:after{content:none}div.passbook-container.passbook-edit .passbook-barcode{display:block}div.passbook-container div.passbook-back{width:320px;min-width:320px;max-width:320px;height:450px;min-height:450px;max-height:450px;border-style:none;border-radius:6px;backface-visibility:hidden;-webkit-backface-visibility:hidden;position:absolute;top:0;left:0;transform:rotateY(180deg);-webkit-transform:rotateY(180deg);padding:10px 5px 5px 5px}div.passbook-container div.passbook-back div.passbook-done{text-align:right;margin:0 10px 10px 0;cursor:pointer;user-select:none;-webkit-user-select:none;opacity:.7}div.passbook-container div.passbook-back div.passbook-done:before{content:'\00f0e2';font-family:FontAwesome}div.passbook-container div.passbook-back div.passbook-done:after{content:'\0000a0Done'}div.passbook-container div.passbook-back div.passbook-back-fields{background-color:#fff;padding:0 10px;margin-top:10px;border-radius:4px;height:403px;overflow:scroll}div.passbook-container div.passbook-back div.passbook-back-fields table{border-collapse:collapse;border-style:none;width:100%}div.passbook-container div.passbook-back div.passbook-back-fields table th{border-top:1px solid #ccc;padding:10px 0 0 0;color:#aaa;font-size:12px}div.passbook-container div.passbook-back div.passbook-back-fields table td{border-bottom:1px solid #ccc;padding:0 0 10px 0;color:#aaa;font-size:14px;font-weight:200}div.passbook-container div.passbook-back div.passbook-back-fields table tr:first-child th,div.passbook-container div.passbook-back div.passbook-back-fields table tr:last-child th,div.passbook-container div.passbook-back div.passbook-back-fields table tr:first-child td,div.passbook-container div.passbook-back div.passbook-back-fields table tr:last-child td{border:none}div.passbook-container [contenteditable]:hover,div.passbook-container [contenteditable]:focus{color:#000 !important;outline:none}div.passbook-container [contenteditable]:empty:after{content:'\002026';opacity:.4}div.passbook-container [contenteditable]:hover:empty:after{opacity:1 !important}div.passbook-container [contenteditable]:focus:empty:after{content:none !important}div.passbook-container table.passbook-header [contenteditable].passbook-title:empty:after{content:'Toy Town'}div.passbook-container table.passbook-primary [contenteditable].passbook-primary-label-1:empty:after{content:'Member'}div.passbook-container table.passbook-primary [contenteditable].passbook-primary-value-1:empty:after{content:'Johnny Appleseed'}div.passbook-container.passbook-boarding-pass table.passbook-header [contenteditable].passbook-title:empty:after{content:'Skyport Airways'}div.passbook-container.passbook-boarding-pass table.passbook-primary [contenteditable].passbook-primary-label-1:empty:after{content:'SAN FRANCISCO'}div.passbook-container.passbook-boarding-pass table.passbook-primary [contenteditable].passbook-primary-value-1:empty:after{content:'SFO'}div.passbook-container.passbook-boarding-pass table.passbook-primary [contenteditable].passbook-primary-label-2:empty:after{content:'NEW YORK'}div.passbook-container.passbook-boarding-pass table.passbook-primary [contenteditable].passbook-primary-value-2:empty:after{content:'JFK'}div.passbook-container.passbook-coupon table.passbook-header [contenteditable].passbook-title:empty:after{content:'Paw Planet'}div.passbook-container.passbook-coupon table.passbook-primary [contenteditable].passbook-primary-label-1:empty:after{content:'Any premium dog food'}div.passbook-container.passbook-coupon table.passbook-primary [contenteditable].passbook-primary-value-1:empty:after{content:'20% off'}div.passbook-container.passbook-event table.passbook-header [contenteditable].passbook-title:empty:after{content:'Lollapalooza'}div.passbook-container.passbook-event table.passbook-primary [contenteditable].passbook-primary-label-1:empty:after{content:'EVENT'}div.passbook-container.passbook-event table.passbook-primary [contenteditable].passbook-primary-value-1:empty:after{content:'The Beat Goes On'}div.passbook-container.passbook-store-card table.passbook-header [contenteditable].passbook-title:empty:after{content:'Organic Produce'}div.passbook-container.passbook-store-card table.passbook-primary [contenteditable].passbook-primary-label-1:empty:after{content:'remaining balance'}div.passbook-container.passbook-store-card table.passbook-primary [contenteditable].passbook-primary-value-1:empty:after{content:'$21.75'}div.passbook-container .passbook-back [contenteditable]:hover,div.passbook-container .passbook-back [contenteditable]:focus{color:#666 !important}div.passbook-container.passbook-white .passbook-front [contenteditable]:hover,div.passbook-container.passbook-white .passbook-front [contenteditable]:focus{color:#fff !important}div.passbook-container div.passbook-picker{width:320px;min-width:320px;max-width:320px;height:450px;min-height:450px;max-height:450px;border-style:none;border-radius:6px;backface-visibility:hidden;-webkit-backface-visibility:hidden;position:absolute;left:0;top:0;width:100px !important;z-index:1000;display:none}div.passbook-container div.passbook-picker div.passbook-picker-contents{position:absolute;left:50px;top:100px;width:220px;border:1px solid rgba(0,0,0,0.2);background:#fff;border-radius:6px;opacity:1;padding:10px;text-align:center}div.passbook-container div.passbook-picker div.passbook-picker-contents input.passbook-slider{width:200px}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-r .slider-handle{z-index:999999 !important;background:#c00000}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-g .slider-handle{z-index:999999 !important;background:#00c000}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-b .slider-handle{z-index:999999 !important;background:#0000c0}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-k .slider-handle{z-index:999999 !important;background:#808080}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-r .slider-selection{background:rgba(255,0,0,0.5)}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-g .slider-selection{background:rgba(0,255,0,0.5)}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-b .slider-selection{background:rgba(0,0,255,0.5)}div.passbook-container div.passbook-picker div.passbook-picker-contents .slider-k .slider-selection{background:rgba(128,128,128,0.5)}div.passbook-container div.passbook-picker div.passbook-picker-contents button{width:40px}div.passbook-container div.passbook-picker div.passbook-picker-contents button[name='generic']{color:#fff;background-color:#428bca}div.passbook-container.passbook-boarding-pass div.passbook-picker button[name='generic']{color:#333 !important;background-color:transparent !important}div.passbook-container.passbook-boarding-pass div.passbook-picker button[name='boarding-pass']{color:#fff;background-color:#428bca}div.passbook-container.passbook-coupon div.passbook-picker button[name='generic']{color:#333 !important;background-color:transparent !important}div.passbook-container.passbook-coupon div.passbook-picker button[name='coupon']{color:#fff;background-color:#428bca}div.passbook-container.passbook-event div.passbook-picker button[name='generic']{color:#333 !important;background-color:transparent !important}div.passbook-container.passbook-event div.passbook-picker button[name='event']{color:#fff;background-color:#428bca}div.passbook-container.passbook-store-card div.passbook-picker button[name='generic']{color:#333 !important;background-color:transparent !important}div.passbook-container.passbook-store-card div.passbook-picker button[name='store-card']{color:#fff;background-color:#428bca}div.passbook-container div.passbook-clear{font-size:13px;font-family:FontAwesome;position:absolute;width:13px;height:13px;background:#fff;border-width:1px;border-style:solid;color:rgba(0,0,0,0.5);border-color:rgba(0,0,0,0.2);border-radius:2px;cursor:pointer;user-select:none;-webkit-user-select:none;display:none}div.passbook-container div.passbook-clear:before{content:'\00f00d';position:relative;top:-3px}div.passbook-container .passbook-logo div.passbook-clear{right:-5px;bottom:-5px}div.passbook-container .passbook-thumbnail div.passbook-clear{left:-5px;top:-5px}div.passbook-container.passbook-edit .passbook-has-image div.passbook-clear{display:block}div.passbook-container.passbook-edit .passbook-logo{display:table-cell}div.passbook-container div.passbook-add{font-size:13px;font-family:FontAwesome;position:absolute;width:16px;height:17px;background:#fff;border-width:1px;border-style:solid;color:rgba(0,0,0,0.5);border-color:rgba(0,0,0,0.2);border-radius:2px;cursor:pointer;user-select:none;-webkit-user-select:none;display:none}div.passbook-container div.passbook-add:before{content:'\00f060';position:relative;top:-1px;left:1px}div.passbook-container .passbook-front div.passbook-add{position:absolute;left:275px;top:10px}div.passbook-container .passbook-back div.passbook-add{position:absolute;left:290px;top:418px}div.passbook-container .passbook-back div.passbook-add:before{content:'\00f062'}div.passbook-container.passbook-edit div.passbook-add{display:block !important;z-index:100}div.passbook-container.passbook-edit .passbook-extra-fields{width:265px}div.passbook-container .passbook-flipper{position:relative;transition:.6s;transform-style:preserve-3d;-webkit-transition:.6s;-webkit-transform-style:preserve-3d}div.passbook-container.passbook-flipped .passbook-flipper{transform:rotateY(180deg);-webkit-transform:rotateY(180deg)} \ No newline at end of file diff --git a/passbook.min.js b/passbook.min.js deleted file mode 100644 index 470cd03..0000000 --- a/passbook.min.js +++ /dev/null @@ -1 +0,0 @@ -/* ========================================================================== */+function(e){"use strict";var t="boarding-pass",n="coupon",r="event",i="store-card",s="generic",o="air",u="boat",a="bus",f="train",l="generic",c="passbook-boarding-pass",h="passbook-coupon",p="passbook-event",d="passbook-store-card",v=[c,h,p,d].join(" "),m="passbook-transport-air",g="passbook-transport-boat",y="passbook-transport-bus",b="passbook-transport-train",w=[m,g,y,b].join(" "),E=function(e){e.data.flip(),e.preventDefault(),e.stopPropagation()},S=function(e){var t=e.data;t.$container.hasClass("passbook-edit")?t.save():t.edit(),e.preventDefault(),e.stopPropagation()},x=function(t){var n=e(t.target);n.text(n.text().trim()),t.preventDefault(),t.stopPropagation()},T=function(t){if(e(this).parent("tr").children("th,td").length<2)return!0;var n=e(this).parent("tr").children("th,td").index(this)+1,r=e(this).parents("table").find("th:nth-child("+n+")"),i=e(this).parents("table").find("td:nth-child("+n+")");if(r.text().length!=0)return;if(i.text().length!=0)return;r.remove(),i.remove()},N=function(t){var n=e(this).parents("table.passbook-extra-fields").find("tr");e(n[0]).append(e("
").append(e("").append(e("
").on("blur",x).on("blur",T)),e(n[1]).append(e("").on("blur",x).on("blur",T))},C=function(t){var n=e(this),r,i,s,o;n.prop("tagName")=="TH"?(r=n,s=n.parents("tr"),o=s.next("tr"),i=o.find("td")):n.prop("tagName")=="TD"&&(i=n,o=n.parents("tr"),s=o.prev("tr"),r=s.find("th"));if(r.text().length!=0)return;if(i.text().length!=0)return;s.remove(),o.remove()},k=function(t){e(this).parents(".passbook-back-fields").find("table").append(e("
").on("blur",x).on("blur",C))).append(e("
").on("blur",x).on("blur",C)))},L=function(t){var n=e(t).data("passbook");if(n!=null)return n;var r=e(t).parent()[0];while(n==null&&r!=null){var i=e(r);n=i.data("passbook"),r=i.parent()[0]}return n},A=function(){var t=L(this);return e(e('
').append(e('
').append(e(''))).append(e('
').append(e('
').append(e('').on("click",t,M)).append(e('').on("click",t,_))).append(e('
').append(e('').on("click",t,P)).append(e('').on("click",t,D)))))},O=function(e){var t=e.data,n=t.$container;n.find('input[name="barcode"]').val(t.barcode),t.barcodeType=="pdf417"?(n.find('button[name="pdf417"]').addClass("btn-primary").removeClass("btn-default"),n.find('button[name="qrcode"]').addClass("btn-default").removeClass("btn-primary")):t.barcodeType=="qrcode"?(n.find('button[name="qrcode"]').addClass("btn-primary").removeClass("btn-default"),n.find('button[name="pdf417"]').addClass("btn-default").removeClass("btn-primary")):(n.find('button[name="qrcode"]').addClass("btn-default").removeClass("btn-primary"),n.find('button[name="pdf417"]').addClass("btn-default").removeClass("btn-primary"))},M=function(e){var t=e.data,n=t.$container;n.find('button[name="pdf417"]').addClass("btn-primary").removeClass("btn-default btn-warning"),n.find('button[name="qrcode"]').addClass("btn-default").removeClass("btn-primary btn-warning")},_=function(e){var t=e.data,n=t.$container;n.find('button[name="pdf417"]').addClass("btn-default").removeClass("btn-primary btn-warning"),n.find('button[name="qrcode"]').addClass("btn-primary").removeClass("btn-default btn-warning")},D=function(e){var t=e.data,n=t.$container,r=n.find('input[name="barcode"]').val();if(r==null||r==""){t.barcode="",t.barcodeType="",n.find(".passbook-barcode").removeClass("passbook-barcode-qrcode passbook-barcode-pdf417").removeAttr("style"),n.find(".passbook-barcode").popover("hide").next(".popover").css("display","none");return}var i,s=n.find('button[name="pdf417"]'),o=n.find('button[name="qrcode"]');if(s.hasClass("btn-primary"))i="pdf417";else{if(!o.hasClass("btn-primary")){s.addClass("btn-warning"),o.addClass("btn-warning");return}i="qrcode"}t.barcode=r,t.barcodeType=i;var u=new Barcode(i,r,{version:6}),a=u.createImageData(3);n.find(".passbook-barcode").css("background-image","url("+a+")").css("background-size",u.cols*3+"px "+u.rows*3+"px").removeClass("passbook-barcode-qrcode passbook-barcode-pdf417").addClass("passbook-barcode-"+i),n.find(".passbook-barcode").popover("hide").next(".popover").css("display","none")},P=function(e){var t=e.data,n=t.$container;n.find(".passbook-barcode").popover("hide").next(".popover").css("display","none")},H=function(t){t.data.type=e(t.currentTarget).attr("name")},B=function(t){if(t.target!=t.currentTarget)return;var n=t.data,r=n.$container,i=e(r.find(".passbook-picker"));if(i.css("display")!="none"){i.removeAttr("style").off("click").empty();return}i.on("click",t.data,B);var s,o,u,a,f=function(e){var t=e.data,n=Math.round(s.getValue()),r=Math.round(o.getValue()),i=Math.round(u.getValue()),f=(a.getValue()-128)/128;t.color="rgb("+n+","+r+","+i+")",t.shading=(a.getValue()-128)/128},l=n.color.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/),c=Number(l[1]),h=Number(l[2]),p=Number(l[3]),d=n.shading+64,v=Math.floor(Math.random()*999999);i.css("display","block").append(e('
').append(e('
').append(e('')).append(e('')).append(e('')).append(e('')).append(e(''))).append(e('
')).append(e('
')).append(e('
')).append(e('
'))),i.find(".passbook-slider").slider(),i.find("button").tooltip({container:i}).on("click",n,H),s=i.find("div.slider-r input.passbook-slider").on("slide",t.data,f).data("slider"),o=i.find("div.slider-g input.passbook-slider").on("slide",t.data,f).data("slider"),u=i.find("div.slider-b input.passbook-slider").on("slide",t.data,f).data("slider"),a=i.find("div.slider-k input.passbook-slider").on("slide",t.data,f).data("slider")},j=function(e){var t=e.data,n=t.transport;n==o?t.transport=u:n==u?t.transport=a:n==a?t.transport=f:n==f?t.transport=l:n==l&&(t.transport=o)},F=function(t){var n=(t.clipboardData||t.originalEvent.clipboardData).items;if(!n||!n[0]){console.warn("No items to load");return}if(!n[0].type.match(/image\//)){console.warn("Cannot load type "+n[0].type);return}e(new FileReader).on("load",t.data,function(t){e(new Image).on("load",t.data,function(t){var n=this.width,r=this.height,i=this.src;if(t.data.size){if(n>t.data.size[0]||r>t.data.size[1]){var s=t.data.size[0]/n,o=t.data.size[1]/r;o").attr({width:n,height:r})[0],a=u.getContext("2d");a.drawImage(this,0,0,n,r),i=u.toDataURL()}t.data.handler&&t.data.handler({width:n,height:r,data:i})})[0].src=t.target.result})[0].readAsDataURL(n[0].getAsFile())},I=function(t){var n=t.data,r=function(e){var t=n.$container.find(".passbook-thumbnail"),r="url("+e.data+")";t.css({width:e.width,height:e.height,background:"url("+e.data+")"}).addClass("passbook-has-image").popover("hide").next(".popover").css("display","none")};e(document).on("paste",{passbook:n,size:[90,90],handler:r},F)},q=function(t){e(document).off("paste")},R=function(t){var n=t.data,r=function(e){var t=n.$container.find(".passbook-logo"),r="url("+e.data+")";t.css({width:e.width,height:e.height,background:"url("+e.data+")"}).addClass("passbook-has-image").popover("hide").next(".popover").css("display","none")};e(document).on("paste",{passbook:n,size:[160,50],handler:r},F)},U=function(t){e(document).off("paste")},z=function(t){var n=e(t.target).parent(".passbook-has-image");n.removeAttr("style").removeClass("passbook-has-image"),t.preventDefault(),t.stopPropagation()},W=function(t){this.$container=e(e('
')).append(e('
').append(e('
').append(e('
')).append(e('').append(e("").append(e('").append(e('
')).append(e(''))).append(e("
')))).append(e('
').append(e('
'))).append(e('
')).append(e('').append(e("").append(e("").append(e('").append(e("").append(e('') + .append($(' + ) // + .append($('') + .append($(' + ); + }; + + const _find_passbook = function (from) { + /* Easy way out? */ + let data = $(from).data('passbook'); + + if (data != null) return data; + + /* Look in the current element, and all its parents */ + let parent = $(from).parent()[0]; + while ((data == null) && (parent != null)) { + const $current = $(parent); + data = $current.data('passbook'); + parent = $current.parent()[0]; + } + + /* Return whatever we got */ + return data; + }; + + + /* ======================================================================== */ + /* BARCODE CONSTRUCTION */ + /* ======================================================================== */ + + const barcode_popover = function () { + const passbook = _find_passbook(this); + return $($('') + .append($('
') + .append($(''))) //
+ .append($('
') + .append($('
') + .append($('') + .on('click', passbook, barcode_pdf417)) + .append($('') + .on('click', passbook, barcode_qrcode))) //
+ .append($('
') + .append($('') + .on('click', passbook, barcode_dismiss)) + .append($('') + .on('click', passbook, barcode_confirm))), //
+ ), //
+ ); // + }; + + const barcode_shown = function (event) { + const passbook = event.data; + const $container = passbook.$container; + + $container.find('input[name="barcode"]').val(passbook.barcode); + if (passbook.barcodeType === 'pdf417') { + $container.find('button[name="pdf417"]').addClass('btn-primary').removeClass('btn-default'); + $container.find('button[name="qrcode"]').addClass('btn-default').removeClass('btn-primary'); + } else if (passbook.barcodeType === 'qrcode') { + $container.find('button[name="qrcode"]').addClass('btn-primary').removeClass('btn-default'); + $container.find('button[name="pdf417"]').addClass('btn-default').removeClass('btn-primary'); + } else { + $container.find('button[name="qrcode"]').addClass('btn-default').removeClass('btn-primary'); + $container.find('button[name="pdf417"]').addClass('btn-default').removeClass('btn-primary'); + } + }; + + const barcode_pdf417 = function (event) { + const passbook = event.data; + const $container = passbook.$container; + $container.find('button[name="pdf417"]').addClass('btn-primary').removeClass('btn-default btn-warning'); + $container.find('button[name="qrcode"]').addClass('btn-default').removeClass('btn-primary btn-warning'); + }; + + const barcode_qrcode = function (event) { + const passbook = event.data; + const $container = passbook.$container; + $container.find('button[name="pdf417"]').addClass('btn-default').removeClass('btn-primary btn-warning'); + $container.find('button[name="qrcode"]').addClass('btn-primary').removeClass('btn-default btn-warning'); + }; + + const barcode_confirm = function (event) { + const passbook = event.data; + const $container = passbook.$container; + + /* Barcode value */ + const barcode = $container.find('input[name="barcode"]').val(); + if ((barcode == null) || (!barcode)) { + passbook.barcode = ''; + passbook.barcodeType = ''; + $container.find('.passbook-barcode') + .removeClass('passbook-barcode-qrcode passbook-barcode-pdf417') + .removeAttr('style'); + $container.find('.passbook-barcode').popover('hide') + .next('.popover').css('display', 'none'); + return; + } + + /* Barcode type */ + let barcodeType; + const pdf417 = $container.find('button[name="pdf417"]'); + const qrcode = $container.find('button[name="qrcode"]'); + if (pdf417.hasClass('btn-primary')) { + barcodeType = 'pdf417'; + } else if (qrcode.hasClass('btn-primary')) { + barcodeType = 'qrcode'; + } else { + pdf417.addClass('btn-warning'); + qrcode.addClass('btn-warning'); + return; + } + + /* Save and dismiss */ + passbook.barcode = barcode; + passbook.barcodeType = barcodeType; + const code = new Barcode(barcodeType, barcode, {version: 6}); + const image = code.createImageData(3); + $container.find('.passbook-barcode') + .css('background-image', `url(${image})`) + .css('background-size', `${code.cols * 3}px ${code.rows * 3}px`) + .removeClass('passbook-barcode-qrcode passbook-barcode-pdf417') + .addClass(`passbook-barcode-${barcodeType}`); + $container.find('.passbook-barcode').popover('hide') + .next('.popover').css('display', 'none'); + }; + + const barcode_dismiss = function (event) { + const passbook = event.data; + const $container = passbook.$container; + $container.find('.passbook-barcode').popover('hide') + .next('.popover').css('display', 'none'); + }; + + /* ======================================================================== */ + /* COLOR PICKER */ + /* ======================================================================== */ + + const passbook_change_type = function (event) { + event.data.type = $(event.currentTarget).attr('name'); + }; + + const passbook_picker_toggle = function (event) { + if (event.target !== event.currentTarget) return; + + const passbook = event.data; + const $container = passbook.$container; + const $picker = $($container.find('.passbook-picker')); + + if ($picker.css('display') !== 'none') { + $picker.removeAttr('style') + .off('click') + .empty(); + return; + } + + $picker.on('click', event.data, passbook_picker_toggle); + let r, + g, + b, + k; + const _change_color = function (event) { + const passbook = event.data; + const rb = Math.round(r.getValue()); + const gb = Math.round(g.getValue()); + const bb = Math.round(b.getValue()); + const shading = (k.getValue() - 128) / 128; + passbook.color = `rgb(${rb},${gb},${bb})`; + passbook.shading = (k.getValue() - 128) / 128; + }; + + const components = passbook.color.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/); + const rc = Number(components[1]); + const gc = Number(components[2]); + const bc = Number(components[3]); + const kc = passbook.shading + 0.5 * 128; + + const id = Math.floor(Math.random() * 999999); + $picker.css('display', 'block') + .append($('
') + .append($('
') + .append($('')) + .append($('')) + .append($('')) + .append($('')) + .append($(''))) //
+ .append($(`
`)) + .append($(`
`)) + .append($(`
`)) + .append($(`
`))); //
+ + /* Enable sliders and tooltips */ + $picker.find('.passbook-slider').slider(); + $picker.find('button').tooltip({container: $picker}).on('click', passbook, passbook_change_type); + + r = $picker.find('div.slider-r input.passbook-slider').on('slide', event.data, _change_color).data('slider'); + g = $picker.find('div.slider-g input.passbook-slider').on('slide', event.data, _change_color).data('slider'); + b = $picker.find('div.slider-b input.passbook-slider').on('slide', event.data, _change_color).data('slider'); + k = $picker.find('div.slider-k input.passbook-slider').on('slide', event.data, _change_color).data('slider'); + }; + + const transport_toggle = function (event) { + const passbook = event.data; + const transport = passbook.transport; + + if (transport === TRANSPORT_AIR) { + passbook.transport = TRANSPORT_BOAT; + } else if (transport === TRANSPORT_BOAT) { + passbook.transport = TRANSPORT_BUS; + } else if (transport === TRANSPORT_BUS) { + passbook.transport = TRANSPORT_TRAIN; + } else if (transport === TRANSPORT_TRAIN) { + passbook.transport = TRANSPORT_GENERIC; + } else if (transport === TRANSPORT_GENERIC) { + passbook.transport = TRANSPORT_AIR; + } + }; + + /* ======================================================================== */ + /* THUMBNAIL AND IMAGE PASTING */ + /* ======================================================================== */ + + const read_image = function (event) { + + /* Check if we have something to load */ + const items = (event.clipboardData || event.originalEvent.clipboardData).items; + if ((!items) || (!items[0])) { + console.warn('No items to load'); + return; + } + + /* Check we have an image */ + if (!items[0].type.match(/image\//)) { + console.warn(`Cannot load type ${items[0].type}`); + return; + } + + /* Load the "file" as a data URL */ + $(new FileReader()).on('load', event.data, (event) => { + + /* Create an image from the contents */ + $(new Image()).on('load', event.data, function (event) { + let width = this.width; + let height = this.height; + let data = this.src; + + /* We might have to rescale the image */ + if (event.data.size) { + if ((width > event.data.size[0]) || (height > event.data.size[1])) { + let stretchX = event.data.size[0] / width; + let stretchY = event.data.size[1] / height; + if (stretchY < stretchX) stretchX = stretchY; + if (stretchX < stretchY) stretchY = stretchX; + width = Math.floor(width * stretchX); + height = Math.floor(height * stretchY); + console.log(`Rescaling to ${width}x${height}`); + } + + /* Use a canvas to resize the image */ + const canvas = $('').attr({width, height})[0]; + const context = canvas.getContext('2d'); + context.drawImage(this, 0, 0, width, height); + data = canvas.toDataURL(); + } + + /* Slap the thumbnail as a background source for the target */ + if (event.data.handler) event.data.handler({width, height, data}); + + /* Trigger loading of the image source */ + })[0].src = event.target.result; + + /* Trigger reading the pasted item */ + })[0].readAsDataURL(items[0].getAsFile()); + }; + + const thumbnail_shown = function (event) { + const passbook = event.data; + + /* A handler to slap the image in the thumbnail */ + const handler = function (image) { + const target = passbook.$container.find('.passbook-thumbnail'); + const background = `url(${image.data})`; + target.css({ + width: image.width, + height: image.height, + background: `url(${image.data})`, + }) + .addClass('passbook-has-image') + .popover('hide') + .next('.popover') + .css('display', 'none'); + }; + + /* Trigger our handler on paste */ + $(document).on('paste', {passbook, size: [90, 90], handler}, read_image); + }; + + const thumbnail_hidden = function (event) { + $(document).off('paste'); + }; + + const logo_shown = function (event) { + const passbook = event.data; + + /* A handler to slap the image in the thumbnail */ + const handler = function (image) { + const target = passbook.$container.find('.passbook-logo'); + const background = `url(${image.data})`; + target.css({ + width: image.width, + height: image.height, + background: `url(${image.data})`, + }) + .addClass('passbook-has-image') + .popover('hide') + .next('.popover') + .css('display', 'none'); + }; + + /* Trigger our handler on paste */ + $(document).on('paste', {passbook, size: [160, 50], handler}, read_image); + }; + + const logo_hidden = function (event) { + $(document).off('paste'); + }; + + const clear_image = function (event) { + const image = $(event.target).parent('.passbook-has-image'); + image.removeAttr('style').removeClass('passbook-has-image'); + event.preventDefault(); + event.stopPropagation(); + }; + + /* ======================================================================== */ + /* CONSTRUCTOR */ + /* ======================================================================== */ + + const Passbook = function (element) { + this.$container = $($('
')) + .append($('
') + .append($('
') + .append($('
')) + .append($('
')).append(e('')))).append(e("
')).append(e(''))))).append(e('').append(e('
').on("click",this,N)).append(e("
")).append(e(""))).append(e('
').append(e('
').on("click",this,N)).append(e("
")).append(e(""))).append(e('
')).append(e('
').on("click",this,E)).append(e('
').on("click",this,S))).append(e('
').append(e('
').on("click",this,E)).append(e('
').append(e("
")).append(e('
').on("click",this,k)))));var n=e(t);n.append(this.$container),this.type=n.data("passbook-type")||s,this.transport=n.data("passbook-transport")||l,this.barcode="",this.barcodeType=""};Object.defineProperty(W.prototype,"TYPE_BOARDING_PASS",{value:t}),Object.defineProperty(W.prototype,"TYPE_COUPON",{value:n}),Object.defineProperty(W.prototype,"TYPE_EVENT",{value:r}),Object.defineProperty(W.prototype,"TYPE_STORE_CARD",{value:i}),Object.defineProperty(W.prototype,"TYPE_GENERIC",{value:s}),Object.defineProperty(W.prototype,"TRANSPORT_AIR",{value:o}),Object.defineProperty(W.prototype,"TRANSPORT_BOAT",{value:u}),Object.defineProperty(W.prototype,"TRANSPORT_BUS",{value:a}),Object.defineProperty(W.prototype,"TRANSPORT_TRAIN",{value:f}),Object.defineProperty(W.prototype,"TRANSPORT_GENERIC",{value:l}),W.prototype.edit=function(){if(this.mode=="edit")return;this.$container.find("th,td").not(".passbook-logo").attr("contenteditable",!0).on("blur",this,x),this.$container.find(".passbook-extra-fields [contenteditable]").on("blur",this,T),this.$container.find(".passbook-back-fields [contenteditable]").on("blur",this,C),this.$container.find(".passbook-barcode").on("shown.bs.popover",this,O).popover({animation:!1,html:!0,placement:"top",trigger:"click",title:"Barcode contents",content:A}),this.$container.find(".passbook-thumbnail").on("shown.bs.popover",this,I).on("hidden.bs.popover",this,q).popover({animation:!1,html:!1,placement:"left",trigger:"click",content:"Paste a logo"}),this.$container.find(".passbook-logo").on("shown.bs.popover",this,R).on("hidden.bs.popover",this,U).popover({animation:!1,html:!1,placement:"right",trigger:"click",content:"Paste a thumbnail"}),this.$container.find(".passbook-front").on("click",this,B),this.$container.find(".passbook-transport").on("click",this,j),this.$container.find(".passbook-clear").on("click",this,z),this.$container.addClass("passbook-edit")},W.prototype.save=function(){if(this.mode!="edit")return;this.$container.find("[contenteditable]").removeAttr("contenteditable").off("blur"),this.$container.removeClass("passbook-edit"),this.$container.find(".passbook-barcode").off("shown.bs.popover").popover("destroy"),this.$container.find(".passbook-thumbnail").off("shown.bs.popover").popover("destroy"),this.$container.find(".passbook-logo").off("shown.bs.popover").popover("destroy"),this.$container.find(".passbook-front").off("click"),this.$container.find(".passbook-transport").off("click"),this.$container.find(".passbook-picker").removeAttr("style").empty()},W.prototype.flip=function(){this.$container.toggleClass("passbook-flipped")},Object.defineProperty(W.prototype,"type",{get:function(){return this.$container.hasClass(c)?t:this.$container.hasClass(h)?n:this.$container.hasClass(p)?r:this.$container.hasClass(d)?i:s},set:function(e){var o;if(e==t)o=c;else if(e==n)o=h;else if(e==r)o=p;else if(e==i)o=d;else{if(e!=s)throw'Unsupported passbook type "'+e+'"';o=null}this.$container.removeClass(v),o!=null&&this.$container.addClass(o)}}),Object.defineProperty(W.prototype,"transport",{get:function(){return this.$container.hasClass(c)?this.$container.hasClass(m)?this.TRANSPORT_AIR:this.$container.hasClass(g)?this.TRANSPORT_BOAT:this.$container.hasClass(y)?this.TRANSPORT_BUS:this.$container.hasClass(b)?this.TRANSPORT_TRAIN:l:null},set:function(e){var t;if(e==o)t=m;else if(e==u)t=g;else if(e==a)t=y;else if(e==f)t=b;else{if(e!=l)throw'Unsupported transport type "'+e+'"';t=null}this.$container.removeClass(w),t!=null&&this.$container.addClass(t)}}),Object.defineProperty(W.prototype,"color",{get:function(){return this.$container.find(".passbook-color").css("background-color")},set:function(t){t=e('
').css("color");if(t==null||t=="")return;this.$container.find(".passbook-color").css("background-color",t)}}),Object.defineProperty(W.prototype,"shading",{get:function(){var e=this.$container.find(".passbook-shading").css("opacity");return e=Math.round(Number(e)/2*3*100)/100,e<0?e=0:e>1&&(e=1),this.$container.hasClass("passbook-white")?e:-e},set:function(e){e<0?(e=-e,this.$container.removeClass("passbook-white"),this.$container.find(".passbook-color").css("color","rgba(0,0,0,"+e+")"),this.$container.find(".passbook-shading").css("opacity",e/3*2)):(this.$container.addClass("passbook-white"),this.$container.find(".passbook-color").css("color","rgba(255,255,255,"+e+")"),this.$container.find(".passbook-shading").css("opacity",e/3*2))}}),Object.defineProperty(W.prototype,"foreground",{get:function(){var e=this.color,t=/rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(e);if(t==null)throw"Invalid color "+e+" found???";var n=Number(t[1]),r=Number(t[2]),i=Number(t[3]),s=this.shading,o,u,a;return s<0?(s=-s,o=Math.round(0*s+n*(1-s)),u=Math.round(0*s+r*(1-s)),a=Math.round(0*s+i*(1-s))):(o=Math.round(255*s+rb*(1-s)),u=Math.round(255*s+gb*(1-s)),a=Math.round(255*s+bb*(1-s))),"rgb("+o+", "+u+", "+a+")"},set:function(){throw"Foreground is a read-only property"}}),Object.defineProperty(W.prototype,"mode",{get:function(){return this.$container.hasClass("passbook-edit")?"edit":"view"},set:function(){throw"Mode is a read-only property"}}),e.fn.passbook=function(t){var n=null,r=this.each(function(){var r=e(this),i=r.data("passbook");i||(i=r.data("passbook",i=new W(r))),t=="edit"&&i.edit(),t=="save"&&i.save(),t=="flip"&&i.flip(),t=="data"&&!n&&(n=i)});return n||r}}(jQuery); \ No newline at end of file diff --git a/src/css/custom.css b/src/css/custom.css new file mode 100644 index 0000000..140050c --- /dev/null +++ b/src/css/custom.css @@ -0,0 +1,38 @@ + +body { + padding: 50px 0px; +} +h4 { + margin-top: 20px; +} +table.api { + border-collapse: collapse; + width: 90%; +} +table.api th, +table.api td { + padding: 5px; + border: 2px solid white; +} +table.api th { + background-color: #ccc; +} +table.api td { + background-color: #eee; +} +table.api td.code { + font-family: Menlo,Monaco,Consolas,"Courier New",monospace; + white-space: nowrap; + font-size: 90%; +} +table.api thead, +table.api tbody { + border-top: 5px solid white; + border-bottom: 5px solid white; +} +table.api code { + background: none; +} +pre { + width: 90%; +} diff --git a/lib/slider/css/slider.css b/src/css/slider.css similarity index 100% rename from lib/slider/css/slider.css rename to src/css/slider.css diff --git a/src/index.ejs b/src/index.ejs new file mode 100644 index 0000000..5a5b6f1 --- /dev/null +++ b/src/index.ejs @@ -0,0 +1,183 @@ + + + + Passbook + + + + Fork me on GitHub + + + + +
+ +

A IOS Passbook editor for Bootstrap

+ +

+ A fully editable IOS Passbook + implementation which can be used to generate data in a visual way to be loaded into your iPhone. +

+ +

+ This is still in the early stages, but this editor allows to edit + in a fashion much similar to the native Passbook app all + sort of information related to passes. +

+ +

An example

+ +

+ The passbook below is created for you in edit mode. + Click around, fill in some text, play with barcodes, and at the end hit + the little save button + to preview the final pass. +

+ +

+ Images can be pasted directly from your clipboard, barcodes are generated + on-the-fly using our JavaScript + library, and clicking on the background of the card allows you to + select the pass type and colors. +

+ +

+ +

API and use

+ +

+ The API is still rudimentary... This implementation relies on a couple + of components: +

+ + + +

+ To create a Passbook editor, use the usual jQuery/Boostrap way by calling + $('myElement').passbook();. The element supports a + couple of data points, namely data-passbook-type and + data-passbook-transport: +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValueDescription
passbook-typeboarding-passUsed to edit a boarding pass
couponDisplay a coupon pass
eventDisplay a ticket or an event pass
store cardDisplay a store card pass
genericDisplay a generic pass
passbook-transpoetairIndicates a boarding pass for a plane
boatIndicates a boarding pass for a boat
busIndicates a boarding pass for a bus
trainIndicates a boarding pass for a train
genericIndicates a generic boarding pass
+ +

Interaction with passes

+ +

+ The $('myElement').passbook(…); function + can also be used to interact (minimally) with the pass: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
editForce the pass to be in "edit mode".
saveWhen in edit mode, save the changes and return in view mode.
flipFlip the pass around.
dataReturn the internal structure of the pass (the internal API - not for the fainthearted).
+ +

Future enhancements

+ +

+ Hoping we can get some much needed finishing touches: +

+ +
    +
  • import/export: it shouldn't be difficult to implement, + quickly loading JSON on creation, and saving the results out.
  • +
  • events: again, should be trivial to implement, but hopefully + we will have events for flipped (when the pass is + flipped), saved (after hitting the save button) and + editing (when entering in edit mode).
  • +
  • read-only mode: meh, self-explanatory.
  • +
  • varcode pasting: allow barcodes to be pasted like + images, parsed (possibly by a backend) and re-rendered on the pass.
  • +
+ + + + diff --git a/src/js/bootstrap-slider.js b/src/js/bootstrap-slider.js new file mode 100644 index 0000000..ff64523 --- /dev/null +++ b/src/js/bootstrap-slider.js @@ -0,0 +1,387 @@ +/* ========================================================= + * bootstrap-slider.js v2.0.0 + * http://www.eyecon.ro/bootstrap-slider + * ========================================================= + * Copyright 2012 Stefan Petre + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ +const jQuery = require('jquery'); + +function slider($) { + + const Slider = function (element, options) { + this.element = $(element); + this.picker = $('
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
') + .insertBefore(this.element) + .append(this.element); + this.id = this.element.data('slider-id') || options.id; + if (this.id) { + this.picker[0].id = this.id; + } + + if (typeof Modernizr !== 'undefined' && Modernizr.touch) { + this.touchCapable = true; + } + + const tooltip = this.element.data('slider-tooltip') || options.tooltip; + + this.tooltip = this.picker.find('.tooltip'); + this.tooltipInner = this.tooltip.find('div.tooltip-inner'); + + this.orientation = this.element.data('slider-orientation') || options.orientation; + switch (this.orientation) { + case 'vertical': + this.picker.addClass('slider-vertical'); + this.stylePos = 'top'; + this.mousePos = 'pageY'; + this.sizePos = 'offsetHeight'; + this.tooltip.addClass('right')[0].style.left = '100%'; + break; + default: + this.picker + .addClass('slider-horizontal') + .css('width', this.element.outerWidth()); + this.orientation = 'horizontal'; + this.stylePos = 'left'; + this.mousePos = 'pageX'; + this.sizePos = 'offsetWidth'; + this.tooltip.addClass('top')[0].style.top = `${-this.tooltip.outerHeight() - 14}px`; + break; + } + + this.min = this.element.data('slider-min') || options.min; + this.max = this.element.data('slider-max') || options.max; + this.step = this.element.data('slider-step') || options.step; + this.value = this.element.data('slider-value') || options.value; + if (this.value[1]) { + this.range = true; + } + + this.selection = this.element.data('slider-selection') || options.selection; + this.selectionEl = this.picker.find('.slider-selection'); + if (this.selection === 'none') { + this.selectionEl.addClass('hide'); + } + this.selectionElStyle = this.selectionEl[0].style; + + + this.handle1 = this.picker.find('.slider-handle:first'); + this.handle1Stype = this.handle1[0].style; + this.handle2 = this.picker.find('.slider-handle:last'); + this.handle2Stype = this.handle2[0].style; + + const handle = this.element.data('slider-handle') || options.handle; + switch (handle) { + case 'round': + this.handle1.addClass('round'); + this.handle2.addClass('round'); + break; + case 'triangle': + this.handle1.addClass('triangle'); + this.handle2.addClass('triangle'); + break; + } + + if (this.range) { + this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); + this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); + } else { + this.value = [Math.max(this.min, Math.min(this.max, this.value))]; + this.handle2.addClass('hide'); + if (this.selection === 'after') { + this.value[1] = this.max; + } else { + this.value[1] = this.min; + } + } + this.diff = this.max - this.min; + this.percentage = [ + (this.value[0] - this.min) * 100 / this.diff, + (this.value[1] - this.min) * 100 / this.diff, + this.step * 100 / this.diff, + ]; + + this.offset = this.picker.offset(); + this.size = this.picker[0][this.sizePos]; + + this.formater = options.formater; + + this.layout(); + + if (this.touchCapable) { + // Touch: Bind touch events: + this.picker.on({ + touchstart: $.proxy(this.mousedown, this), + }); + } else { + this.picker.on({ + mousedown: $.proxy(this.mousedown, this), + }); + } + + if (tooltip === 'show') { + this.picker.on({ + mouseenter: $.proxy(this.showTooltip, this), + mouseleave: $.proxy(this.hideTooltip, this), + }); + } else { + this.tooltip.addClass('hide'); + } + }; + + Slider.prototype = { + constructor: Slider, + + over: false, + inDrag: false, + + showTooltip() { + this.tooltip.addClass('in'); + // var left = Math.round(this.percent*this.width); + // this.tooltip.css('left', left - this.tooltip.outerWidth()/2); + this.over = true; + }, + + hideTooltip() { + if (this.inDrag === false) { + this.tooltip.removeClass('in'); + } + this.over = false; + }, + + layout() { + this.handle1Stype[this.stylePos] = `${this.percentage[0]}%`; + this.handle2Stype[this.stylePos] = `${this.percentage[1]}%`; + if (this.orientation === 'vertical') { + this.selectionElStyle.top = `${Math.min(this.percentage[0], this.percentage[1])}%`; + this.selectionElStyle.height = `${Math.abs(this.percentage[0] - this.percentage[1])}%`; + } else { + this.selectionElStyle.left = `${Math.min(this.percentage[0], this.percentage[1])}%`; + this.selectionElStyle.width = `${Math.abs(this.percentage[0] - this.percentage[1])}%`; + } + if (this.range) { + this.tooltipInner.text(`${this.formater(this.value[0]) + } : ${ + this.formater(this.value[1])}`); + this.tooltip[0].style[this.stylePos] = `${this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0]) / 2) / 100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight() / 2 : this.tooltip.outerWidth() / 2)}px`; + } else { + this.tooltipInner.text(this.formater(this.value[0])); + this.tooltip[0].style[this.stylePos] = `${this.size * this.percentage[0] / 100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight() / 2 : this.tooltip.outerWidth() / 2)}px`; + } + }, + + mousedown(ev) { + + // Touch: Get the original event: + if (this.touchCapable && ev.type === 'touchstart') { + ev = ev.originalEvent; + } + + this.offset = this.picker.offset(); + this.size = this.picker[0][this.sizePos]; + + const percentage = this.getPercentage(ev); + + if (this.range) { + const diff1 = Math.abs(this.percentage[0] - percentage); + const diff2 = Math.abs(this.percentage[1] - percentage); + this.dragged = (diff1 < diff2) ? 0 : 1; + } else { + this.dragged = 0; + } + + this.percentage[this.dragged] = percentage; + this.layout(); + + if (this.touchCapable) { + // Touch: Bind touch events: + $(document).on({ + touchmove: $.proxy(this.mousemove, this), + touchend: $.proxy(this.mouseup, this), + }); + } else { + $(document).on({ + mousemove: $.proxy(this.mousemove, this), + mouseup: $.proxy(this.mouseup, this), + }); + } + + this.inDrag = true; + const val = this.calculateValue(); + this.element.trigger({ + type: 'slideStart', + value: val, + }).trigger({ + type: 'slide', + value: val, + }); + return false; + }, + + mousemove(ev) { + + // Touch: Get the original event: + if (this.touchCapable && ev.type === 'touchmove') { + ev = ev.originalEvent; + } + + const percentage = this.getPercentage(ev); + if (this.range) { + if (this.dragged === 0 && this.percentage[1] < percentage) { + this.percentage[0] = this.percentage[1]; + this.dragged = 1; + } else if (this.dragged === 1 && this.percentage[0] > percentage) { + this.percentage[1] = this.percentage[0]; + this.dragged = 0; + } + } + this.percentage[this.dragged] = percentage; + this.layout(); + const val = this.calculateValue(); + this.element + .trigger({ + type: 'slide', + value: val, + }) + .data('value', val) + .prop('value', val); + return false; + }, + + mouseup(ev) { + if (this.touchCapable) { + // Touch: Bind touch events: + $(document).off({ + touchmove: this.mousemove, + touchend: this.mouseup, + }); + } else { + $(document).off({ + mousemove: this.mousemove, + mouseup: this.mouseup, + }); + } + + this.inDrag = false; + if (!this.over) { + this.hideTooltip(); + } + // this.element; + const val = this.calculateValue(); + this.element + .trigger({ + type: 'slideStop', + value: val, + }) + .data('value', val) + .prop('value', val); + return false; + }, + + calculateValue() { + let val; + if (this.range) { + val = [ + (this.min + Math.round((this.diff * this.percentage[0] / 100) / this.step) * this.step), + (this.min + Math.round((this.diff * this.percentage[1] / 100) / this.step) * this.step), + ]; + this.value = val; + } else { + val = (this.min + Math.round((this.diff * this.percentage[0] / 100) / this.step) * this.step); + this.value = [val, this.value[1]]; + } + return val; + }, + + getPercentage(ev) { + if (this.touchCapable) { + ev = ev.touches[0]; + } + let percentage = (ev[this.mousePos] - this.offset[this.stylePos]) * 100 / this.size; + percentage = Math.round(percentage / this.percentage[2]) * this.percentage[2]; + return Math.max(0, Math.min(100, percentage)); + }, + + getValue() { + if (this.range) { + return this.value; + } + return this.value[0]; + }, + + setValue(val) { + this.value = val; + + if (this.range) { + this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); + this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); + } else { + this.value = [Math.max(this.min, Math.min(this.max, this.value))]; + this.handle2.addClass('hide'); + if (this.selection === 'after') { + this.value[1] = this.max; + } else { + this.value[1] = this.min; + } + } + this.diff = this.max - this.min; + this.percentage = [ + (this.value[0] - this.min) * 100 / this.diff, + (this.value[1] - this.min) * 100 / this.diff, + this.step * 100 / this.diff, + ]; + this.layout(); + }, + }; + + $.fn.slider = function (option, val) { + return this.each(function () { + let $this = $(this), + data = $this.data('slider'), + options = typeof option === 'object' && option; + if (!data) { + $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults, options)))); + } + if (typeof option === 'string') { + data[option](val); + } + }); + }; + + $.fn.slider.defaults = { + min: 0, + max: 10, + step: 1, + orientation: 'horizontal', + value: 5, + selection: 'before', + tooltip: 'show', + handle: 'round', + formater(value) { + return value; + }, + }; + + $.fn.slider.Constructor = Slider; + +} + +slider(jQuery); diff --git a/src/js/index.js b/src/js/index.js new file mode 100644 index 0000000..5805322 --- /dev/null +++ b/src/js/index.js @@ -0,0 +1,19 @@ +import 'bootstrap/dist/css/bootstrap.css'; +import 'font-awesome/css/font-awesome.css'; +import '../css/custom.css'; +import '../css/slider.css'; +// import '../less/slider.less'; +import '../less/passbook.less'; + +const $ = require('jquery'); + +window.$ = $; +window.jQuery = $; +require('bootstrap'); +require('./passbook.js'); +require('./bootstrap-slider.js'); + +$(document).ready(() => { + const passbook = $('#passbook').passbook(); + passbook.passbook('edit'); +}); diff --git a/src/js/javascript-barcodes.js b/src/js/javascript-barcodes.js new file mode 100644 index 0000000..f2c15de --- /dev/null +++ b/src/js/javascript-barcodes.js @@ -0,0 +1,4054 @@ +const BarcodeExport = (function () { + + /* ======================================================================= */ + /* Our "Barcode" object */ + /* ======================================================================= */ + + const Barcode = function (type, code, parameters) { + const _function = __formats[type]; + + if (_function == null) { + throw new Error(`Unsupported barcode type "${type}"`); + } + + const _barcode = _function(code, parameters); + this.parameters = _barcode.parameters || parameters || {}; + this.format = type; + this.rows = _barcode.rows; + this.cols = _barcode.cols; + this.data = _barcode.data; + this.contents = code; + }; + + Barcode.prototype.createCanvas = function (scaleX, scaleY) { + const scale = normalizeScale(scaleX, scaleY); + + /* Create our Canvas element */ + canvas = document.createElement('canvas'); + canvas.width = scale.x * this.cols; + canvas.height = scale.y * this.rows; + + /* Paint! */ + const ctx = canvas.getContext('2d'); + for (let r = 0, y = 0; r < this.rows; r++, y += scale.y) { + for (let c = 0, x = 0; c < this.cols; c++, x += scale.x) { + if (this.data[r][c]) { + ctx.fillRect(x, y, scale.x, scale.y); + } + } + } + return canvas; + }; + + Barcode.prototype.createImageData = function (scaleX, scaleY) { + const scale = normalizeScale(scaleX, scaleY); + + const _data = this.data; + const _rows = this.rows; + const _cols = this.cols; + return __create_image_data(_cols * scale.x, _rows * scale.y, (x, y) => { + const c = Math.floor(x / scale.x); + const r = Math.floor(y / scale.y); + if ((r >= 0) && (r < _rows) && (c >= 0) && (c < _cols)) { + return _data[r][c] ? 0 : 1; + } + return 1; + + }); + }; + + /* ======================================================================= */ + /* Constants */ + /* ======================================================================= */ + Object.defineProperty(Barcode, 'PDF417', { enumerable: true, value: 'pdf417' }); + Object.defineProperty(Barcode, 'QRCODE', { enumerable: true, value: 'qrcode' }); + + /* ======================================================================= */ + /* Little helper functions */ + /* ======================================================================= */ + var normalizeScale = function (scaleX, scaleY) { + /* No parameter? Scale 1 */ + if (scaleX == null) scaleX = scaleY = 1; + + /* One parameter? Scale both! */ + if ((scaleX != null) && (scaleY == null)) { + scaleY = scaleX; + } + + /* Convert to numbers (keep barcodes pixel perfect) */ + scaleX = Math.round(Number(scaleX) || 2); + scaleY = Math.round(Number(scaleY) || 2); + + /* Return them */ + return { x: scaleX, y: scaleY }; + }; + + /* ======================================================================= */ + /* Imported libraries */ + /* ======================================================================= */ + + /* Formats creation functions */ + var __formats = {}; + let __create_image_data; + + +(function () { + /* BCMath library statically included */ + /** + * BC Math Library for Javascript + * Ported from the PHP5 bcmath extension source code, + * which uses the libbcmath package... + * Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + * Copyright (C) 2000 Philip A. Nelson + * The Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111-1307 USA. + * e-mail: philnelson@acm.org + * us-mail: Philip A. Nelson + * Computer Science Department, 9062 + * Western Washington University + * Bellingham, WA 98226-9062 + * + * bcmath-js homepage: + * + * This code is covered under the LGPL licence, and can be used however you want :) + * Be kind and share any decent code changes. + */ + + var libbcmath = { + PLUS: '+', + MINUS: '-', + BASE: 10, // must be 10 (for now) + scale: 0, // default scale + + /** + * Basic number structure + */ + bc_num() { + this.n_sign = null; // sign + this.n_len = null; /* (int) The number of digits before the decimal point. */ + this.n_scale = null; /* (int) The number of digits after the decimal point. */ + // this.n_refs = null; /* (int) The number of pointers to this number. */ + // this.n_text = null; /* ?? Linked list for available list. */ + this.n_value = null; /* array as value, where 1.23 = [1,2,3] */ + this.toString = function () { + let r, + tmp; + tmp = this.n_value.join(''); + + // add minus sign (if applicable) then add the integer part + r = ((this.n_sign == libbcmath.PLUS) ? '' : this.n_sign) + tmp.substr(0, this.n_len); + + // if decimal places, add a . and the decimal part + if (this.n_scale > 0) { + r += `.${tmp.substr(this.n_len, this.n_scale)}`; + } + return r; + }; + + this.setScale = function (newScale) { + while (this.n_scale < newScale) { + this.n_value.push(0); + this.n_scale++; + } + while (this.n_scale > newScale) { + this.n_value.pop(); + this.n_scale--; + } + return this; + }; + + }, + + /** + * @param int length + * @param int scale + * @return bc_num + */ + bc_new_num(length, scale) { + let temp; // bc_num + temp = new libbcmath.bc_num(); + temp.n_sign = libbcmath.PLUS; + temp.n_len = length; + temp.n_scale = scale; + temp.n_value = libbcmath.safe_emalloc(1, length + scale, 0); + libbcmath.memset(temp.n_value, 0, 0, length + scale); + return temp; + }, + + safe_emalloc(size, len, extra) { + return Array((size * len) + extra); + }, + + /** + * Create a new number + */ + bc_init_num() { + return new libbcmath.bc_new_num(1, 0); + + }, + + _bc_rm_leading_zeros(num) { + /* We can move n_value to point to the first non zero digit! */ + while ((num.n_value[0] === 0) && (num.n_len > 1)) { + num.n_value.shift(); + num.n_len--; + } + }, + + /** + * Convert to bc_num detecting scale + */ + php_str2num(str) { + let p; + p = str.indexOf('.'); + if (p == -1) { + return libbcmath.bc_str2num(str, 0); + } + return libbcmath.bc_str2num(str, (str.length - p)); + + + }, + + CH_VAL(c) { + return c - '0'; // ?? + }, + + BCD_CHAR(d) { + return `${d}0`; // ?? + }, + + isdigit(c) { + return (!isNaN(parseInt(c, 10))); + }, + + bc_str2num(str_in, scale) { + let str, + num, + ptr, + digits, + strscale, + zero_int, + nptr; + // remove any non-expected characters + /* Check for valid number and count digits. */ + + str = str_in.split(''); // convert to array + ptr = 0; // str + digits = 0; + strscale = 0; + zero_int = false; + if ((str[ptr] === '+') || (str[ptr] === '-')) { + ptr++; /* Sign */ + } + while (str[ptr] === '0') { + ptr++; /* Skip leading zeros. */ + } + // while (libbcmath.isdigit(str[ptr])) { + while ((str[ptr]) % 1 === 0) { // libbcmath.isdigit(str[ptr])) { + ptr++; + digits++; /* digits */ + } + + if (str[ptr] === '.') { + ptr++; /* decimal point */ + } + // while (libbcmath.isdigit(str[ptr])) { + while ((str[ptr]) % 1 === 0) { // libbcmath.isdigit(str[ptr])) { + ptr++; + strscale++; /* digits */ + } + + if ((str[ptr]) || (digits + strscale === 0)) { + // invalid number, return 0 + return libbcmath.bc_init_num(); + //* num = bc_copy_num (BCG(_zero_)); + } + + /* Adjust numbers and allocate storage and initialize fields. */ + strscale = libbcmath.MIN(strscale, scale); + if (digits === 0) { + zero_int = true; + digits = 1; + } + + num = libbcmath.bc_new_num(digits, strscale); + + /* Build the whole number. */ + ptr = 0; // str + if (str[ptr] === '-') { + num.n_sign = libbcmath.MINUS; + // (*num)->n_sign = MINUS; + ptr++; + } else { + num.n_sign = libbcmath.PLUS; + // (*num)->n_sign = PLUS; + if (str[ptr] === '+') { + ptr++; + } + } + while (str[ptr] === '0') { + ptr++; /* Skip leading zeros. */ + } + + nptr = 0; // (*num)->n_value; + if (zero_int) { + num.n_value[nptr++] = 0; + digits = 0; + } + for (;digits > 0; digits--) { + num.n_value[nptr++] = libbcmath.CH_VAL(str[ptr++]); + //* nptr++ = CH_VAL(*ptr++); + } + + /* Build the fractional part. */ + if (strscale > 0) { + ptr++; /* skip the decimal point! */ + for (;strscale > 0; strscale--) { + num.n_value[nptr++] = libbcmath.CH_VAL(str[ptr++]); + } + } + + return num; + }, + + cint(v) { + if (typeof (v) === 'undefined') { + v = 0; + } + let x = parseInt(v, 10); + if (isNaN(x)) { + x = 0; + } + return x; + }, + + /** + * Basic min function + * @param int + * @param int + */ + MIN(a, b) { + return ((a > b) ? b : a); + }, + + /** + * Basic max function + * @param int + * @param int + */ + MAX(a, b) { + return ((a > b) ? a : b); + }, + + /** + * Basic odd function + * @param int + * @param int + */ + ODD(a) { + return (a & 1); + }, + + /** + * replicate c function + * @param array return (by reference) + * @param string char to fill + * @param int length to fill + */ + memset(r, ptr, chr, len) { + let i; + for (i = 0; i < len; i++) { + r[ptr + i] = chr; + } + }, + + /** + * Replacement c function + * Obviously can't work like c does, so we've added an "offset" param so you could do memcpy(dest+1, src, len) as memcpy(dest, 1, src, len) + * Also only works on arrays + */ + memcpy(dest, ptr, src, srcptr, len) { + let i; + for (i = 0; i < len; i++) { + dest[ptr + i] = src[srcptr + i]; + } + return true; + }, + + + /** + * Determine if the number specified is zero or not + * @param bc_num num number to check + * @return boolean true when zero, false when not zero. + */ + bc_is_zero(num) { + let count; // int + let nptr; // int + + /* Quick check. */ + // if (num == BCG(_zero_)) return TRUE; + + /* Initialize */ + count = num.n_len + num.n_scale; + nptr = 0; // num->n_value; + + /* The check */ + while ((count > 0) && (num.n_value[nptr++] === 0)) { + count--; + } + + if (count !== 0) { + return false; + } + return true; + + }, + + bc_out_of_memory() { + throw new Error('(BC) Out of memory'); + }, + }; + + /** + * Base add function + * + // Here is the full add routine that takes care of negative numbers. + // N1 is added to N2 and the result placed into RESULT. SCALE_MIN + // is the minimum scale for the result. + * + * @param bc_num n1 + * @param bc_num n2 + * @pram int scale_min + * @return bc_num + */ + libbcmath.bc_add = function (n1, n2, scale_min) { + let sum, + cmp_res, + res_scale; + + if (n1.n_sign === n2.n_sign) { + sum = libbcmath._bc_do_add(n1, n2, scale_min); + sum.n_sign = n1.n_sign; + } else { + /* subtraction must be done. */ + cmp_res = libbcmath._bc_do_compare(n1, n2, false, false); /* Compare magnitudes. */ + switch (cmp_res) { + case -1: + /* n1 is less than n2, subtract n1 from n2. */ + sum = libbcmath._bc_do_sub(n2, n1, scale_min); + sum.n_sign = n2.n_sign; + break; + + case 0: + /* They are equal! return zero with the correct scale! */ + res_scale = libbcmath.MAX(scale_min, libbcmath.MAX(n1.n_scale, n2.n_scale)); + sum = libbcmath.bc_new_num(1, res_scale); + libbcmath.memset(sum.n_value, 0, 0, res_scale + 1); + break; + + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + sum = libbcmath._bc_do_sub(n1, n2, scale_min); + sum.n_sign = n1.n_sign; + } + } + return sum; + }; + /* Some utility routines for the divide: First a one digit multiply. + NUM (with SIZE digits) is multiplied by DIGIT and the result is + placed into RESULT. It is written so that NUM and RESULT can be + the same pointers. */ + /** + * + * @param array num (pass by ref) + * @param int size + * @param int digit + * @param array result (pass by ref) + */ + libbcmath._one_mult = function (num, n_ptr, size, digit, result, r_ptr) { + let carry, + value; // int + let nptr, + rptr; // int pointers + + if (digit === 0) { + libbcmath.memset(result, 0, 0, size); // memset (result, 0, size); + } else if (digit == 1) { + libbcmath.memcpy(result, r_ptr, num, n_ptr, size); // memcpy (result, num, size); + } else { + /* Initialize */ + nptr = n_ptr + size - 1; // nptr = (unsigned char *) (num+size-1); + rptr = r_ptr + size - 1; // rptr = (unsigned char *) (result+size-1); + carry = 0; + + while (size-- > 0) { + value = num[nptr--] * digit + carry; // value = *nptr-- * digit + carry; + // result[rptr--] = libbcmath.cint(value % libbcmath.BASE); // @CHECK cint //*rptr-- = value % BASE; + result[rptr--] = value % libbcmath.BASE; // @CHECK cint //*rptr-- = value % BASE; + // carry = libbcmath.cint(value / libbcmath.BASE); // @CHECK cint //carry = value / BASE; + carry = Math.floor(value / libbcmath.BASE); // @CHECK cint //carry = value / BASE; + } + + if (carry != 0) { + result[rptr] = carry; + } + } + }; + + + /* The full division routine. This computes N1 / N2. It returns + 0 if the division is ok and the result is in QUOT. The number of + digits after the decimal point is SCALE. It returns -1 if division + by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ + + libbcmath.bc_divide = function (n1, n2, scale) { + let quot; // bc_num return + let qval; // bc_num + let num1, + num2; // string + let ptr1, + ptr2, + n2ptr, + qptr; // int pointers + let scale1, + val; // int + let len1, + len2, + scale2, + qdigits, + extra, + count; // int + let qdig, + qguess, + borrow, + carry; // int + let mval; // string + let zero; // char + let norm; // int + let ptrs; // return object from one_mul + + /* Test for divide by zero. (return failure) */ + if (libbcmath.bc_is_zero(n2)) { + return -1; + } + + /* Test for zero divide by anything (return zero) */ + if (libbcmath.bc_is_zero(n1)) { + return libbcmath.bc_new_num(1, scale); + } + + /* Test for n1 equals n2 (return 1 as n1 nor n2 are zero) + if (libbcmath.bc_compare(n1, n2, libbcmath.MAX(n1.n_scale, n2.n_scale)) === 0) { + quot=libbcmath.bc_new_num(1, scale); + quot.n_value[0] = 1; + return quot; + } + */ + + /* Test for divide by 1. If it is we must truncate. */ + // todo: check where scale > 0 too.. can't see why not (ie bc_is_zero - add bc_is_one function) + if (n2.n_scale === 0) { + if (n2.n_len === 1 && n2.n_value[0] === 1) { + qval = libbcmath.bc_new_num(n1.n_len, scale); // qval = bc_new_num (n1->n_len, scale); + qval.n_sign = (n1.n_sign == n2.n_sign ? libbcmath.PLUS : libbcmath.MINUS); + libbcmath.memset(qval.n_value, n1.n_len, 0, scale); // memset (&qval->n_value[n1->n_len],0,scale); + libbcmath.memcpy(qval.n_value, 0, n1.n_value, 0, n1.n_len + libbcmath.MIN(n1.n_scale, scale)); // memcpy (qval->n_value, n1->n_value, n1->n_len + MIN(n1->n_scale,scale)); + // can we return here? not in c src, but can't see why-not. + // return qval; + } + } + + /* Set up the divide. Move the decimal point on n1 by n2's scale. + Remember, zeros on the end of num2 are wasted effort for dividing. */ + scale2 = n2.n_scale; // scale2 = n2->n_scale; + n2ptr = n2.n_len + scale2 - 1; // n2ptr = (unsigned char *) n2.n_value+n2.n_len+scale2-1; + while ((scale2 > 0) && (n2.n_value[n2ptr--] === 0)) { + scale2--; + } + + len1 = n1.n_len + scale2; + scale1 = n1.n_scale - scale2; + if (scale1 < scale) { + extra = scale - scale1; + } else { + extra = 0; + } + + num1 = libbcmath.safe_emalloc(1, n1.n_len + n1.n_scale, extra + 2); // num1 = (unsigned char *) safe_emalloc (1, n1.n_len+n1.n_scale, extra+2); + if (num1 === null) { + libbcmath.bc_out_of_memory(); + } + libbcmath.memset(num1, 0, 0, n1.n_len + n1.n_scale + extra + 2); // memset (num1, 0, n1->n_len+n1->n_scale+extra+2); + libbcmath.memcpy(num1, 1, n1.n_value, 0, n1.n_len + n1.n_scale); // memcpy (num1+1, n1.n_value, n1.n_len+n1.n_scale); + + len2 = n2.n_len + scale2; // len2 = n2->n_len + scale2; + num2 = libbcmath.safe_emalloc(1, len2, 1);// num2 = (unsigned char *) safe_emalloc (1, len2, 1); + if (num2 === null) { + libbcmath.bc_out_of_memory(); + } + libbcmath.memcpy(num2, 0, n2.n_value, 0, len2); // memcpy (num2, n2.n_value, len2); + num2[len2] = 0; // *(num2+len2) = 0; + n2ptr = 0; // n2ptr = num2; + + while (num2[n2ptr] === 0) { // while (*n2ptr == 0) + n2ptr++; + len2--; + } + + /* Calculate the number of quotient digits. */ + if (len2 > len1 + scale) { + qdigits = scale + 1; + zero = true; + } else { + zero = false; + if (len2 > len1) { + qdigits = scale + 1; /* One for the zero integer part. */ + } else { + qdigits = len1 - len2 + scale + 1; + } + } + + /* Allocate and zero the storage for the quotient. */ + qval = libbcmath.bc_new_num(qdigits - scale, scale); // qval = bc_new_num (qdigits-scale,scale); + libbcmath.memset(qval.n_value, 0, 0, qdigits); // memset (qval->n_value, 0, qdigits); + + /* Allocate storage for the temporary storage mval. */ + mval = libbcmath.safe_emalloc(1, len2, 1); // mval = (unsigned char *) safe_emalloc (1, len2, 1); + if (mval === null) { + libbcmath.bc_out_of_memory(); + } + + /* Now for the full divide algorithm. */ + if (!zero) { + /* Normalize */ + // norm = libbcmath.cint(10 / (libbcmath.cint(n2.n_value[n2ptr]) + 1)); //norm = 10 / ((int)*n2ptr + 1); + norm = Math.floor(10 / (n2.n_value[n2ptr] + 1)); // norm = 10 / ((int)*n2ptr + 1); + if (norm != 1) { + libbcmath._one_mult(num1, 0, len1 + scale1 + extra + 1, norm, num1, 0); // libbcmath._one_mult(num1, len1+scale1+extra+1, norm, num1); + libbcmath._one_mult(n2.n_value, n2ptr, len2, norm, n2.n_value, n2ptr); // libbcmath._one_mult(n2ptr, len2, norm, n2ptr); + + // @CHECK Is the pointer affected by the call? if so, maybe need to adjust points on return? + + } + + /* Initialize divide loop. */ + qdig = 0; + if (len2 > len1) { + qptr = len2 - len1; // qptr = (unsigned char *) qval.n_value+len2-len1; + } else { + qptr = 0; // qptr = (unsigned char *) qval.n_value; + } + + /* Loop */ + while (qdig <= len1 + scale - len2) { + /* Calculate the quotient digit guess. */ + if (n2.n_value[n2ptr] == num1[qdig]) { + qguess = 9; + } else { + qguess = Math.floor((num1[qdig] * 10 + num1[qdig + 1]) / n2.n_value[n2ptr]); + } + /* Test qguess. */ + + if (n2.n_value[n2ptr + 1] * qguess > (num1[qdig] * 10 + num1[qdig + 1] - n2.n_value[n2ptr] * qguess) * 10 + num1[qdig + 2]) { // if (n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]) { + qguess--; + /* And again. */ + if (n2.n_value[n2ptr + 1] * qguess > (num1[qdig] * 10 + num1[qdig + 1] - n2.n_value[n2ptr] * qguess) * 10 + num1[qdig + 2]) { // if (n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]) + qguess--; + } + } + + /* Multiply and subtract. */ + borrow = 0; + if (qguess !== 0) { + mval[0] = 0; //* mval = 0; // @CHECK is this to fix ptr2 < 0? + libbcmath._one_mult(n2.n_value, n2ptr, len2, qguess, mval, 1); // _one_mult (n2ptr, len2, qguess, mval+1); // @CHECK + + ptr1 = qdig + len2; // (unsigned char *) num1+qdig+len2; + ptr2 = len2; // (unsigned char *) mval+len2; + + // @CHECK: Does a negative pointer return null? + // ptr2 can be < 0 here as ptr1 = len2, thus count < len2+1 will always fail ? + for (count = 0; count < len2 + 1; count++) { + if (ptr2 < 0) { + // val = libbcmath.cint(num1[ptr1]) - 0 - borrow; //val = (int) *ptr1 - (int) *ptr2-- - borrow; + val = num1[ptr1] - 0 - borrow; // val = (int) *ptr1 - (int) *ptr2-- - borrow; + } else { + // val = libbcmath.cint(num1[ptr1]) - libbcmath.cint(mval[ptr2--]) - borrow; //val = (int) *ptr1 - (int) *ptr2-- - borrow; + val = num1[ptr1] - mval[ptr2--] - borrow; // val = (int) *ptr1 - (int) *ptr2-- - borrow; + } + if (val < 0) { + val += 10; + borrow = 1; + } else { + borrow = 0; + } + num1[ptr1--] = val; + } + } + + /* Test for negative result. */ + if (borrow == 1) { + qguess--; + ptr1 = qdig + len2; // (unsigned char *) num1+qdig+len2; + ptr2 = len2 - 1; // (unsigned char *) n2ptr+len2-1; + carry = 0; + for (count = 0; count < len2; count++) { + if (ptr2 < 0) { + // val = libbcmath.cint(num1[ptr1]) + 0 + carry; //val = (int) *ptr1 + (int) *ptr2-- + carry; + val = num1[ptr1] + 0 + carry; // val = (int) *ptr1 + (int) *ptr2-- + carry; + } else { + // val = libbcmath.cint(num1[ptr1]) + libbcmath.cint(n2.n_value[ptr2--]) + carry; //val = (int) *ptr1 + (int) *ptr2-- + carry; + val = num1[ptr1] + n2.n_value[ptr2--] + carry; // val = (int) *ptr1 + (int) *ptr2-- + carry; + } + if (val > 9) { + val -= 10; + carry = 1; + } else { + carry = 0; + } + num1[ptr1--] = val; //* ptr1-- = val; + } + if (carry == 1) { + // num1[ptr1] = libbcmath.cint((num1[ptr1] + 1) % 10); // *ptr1 = (*ptr1 + 1) % 10; // @CHECK + num1[ptr1] = (num1[ptr1] + 1) % 10; // *ptr1 = (*ptr1 + 1) % 10; // @CHECK + } + } + + /* We now know the quotient digit. */ + qval.n_value[qptr++] = qguess; //* qptr++ = qguess; + qdig++; + } + } + + /* Clean up and return the number. */ + qval.n_sign = (n1.n_sign == n2.n_sign ? libbcmath.PLUS : libbcmath.MINUS); + if (libbcmath.bc_is_zero(qval)) { + qval.n_sign = libbcmath.PLUS; + } + libbcmath._bc_rm_leading_zeros(qval); + + return qval; + + // return 0; /* Everything is OK. */ + }; + + + /** + * Perform an "add" + * + // Perform addition: N1 is added to N2 and the value is + // returned. The signs of N1 and N2 are ignored. + // SCALE_MIN is to set the minimum scale of the result. + * + * Basic school maths says to add 2 numbers.. + * 1. make them the same length, the decimal places, and the integer part + * 2. start from the right and add the two numbers together + * 3. if the sum of the 2 numbers > 9, carry 1 to the next set and subtract 10 (ie 18 > carry 1 becomes 8). thus 0.9 + 0.9 = 1.8 + * + * @param bc_num n1 + * @param bc_num n2 + * @param int scale_min + * @return bc_num + */ + libbcmath._bc_do_add = function (n1, n2, scale_min) { + let sum; // bc_num + let sum_scale, + sum_digits; // int + let n1ptr, + n2ptr, + sumptr; // int + let carry, + n1bytes, + n2bytes; // int + let tmp; // int + + + // Prepare sum. + sum_scale = libbcmath.MAX(n1.n_scale, n2.n_scale); + sum_digits = libbcmath.MAX(n1.n_len, n2.n_len) + 1; + sum = libbcmath.bc_new_num(sum_digits, libbcmath.MAX(sum_scale, scale_min)); + + + /* Not needed? + if (scale_min > sum_scale) { + sumptr = (char *) (sum->n_value + sum_scale + sum_digits); + for (count = scale_min - sum_scale; count > 0; count--) { + *sumptr++ = 0; + } + } + */ + + // Start with the fraction part. Initialize the pointers. + n1bytes = n1.n_scale; + n2bytes = n2.n_scale; + n1ptr = (n1.n_len + n1bytes - 1); + n2ptr = (n2.n_len + n2bytes - 1); + sumptr = (sum_scale + sum_digits - 1); + + // Add the fraction part. First copy the longer fraction (ie when adding 1.2345 to 1 we know .2345 is correct already) . + if (n1bytes != n2bytes) { + if (n1bytes > n2bytes) { + // n1 has more dp then n2 + while (n1bytes > n2bytes) { + sum.n_value[sumptr--] = n1.n_value[n1ptr--]; + // *sumptr-- = *n1ptr--; + n1bytes--; + } + } else { + // n2 has more dp then n1 + while (n2bytes > n1bytes) { + sum.n_value[sumptr--] = n2.n_value[n2ptr--]; + // *sumptr-- = *n2ptr--; + n2bytes--; + } + } + } + + // Now add the remaining fraction part and equal size integer parts. + n1bytes += n1.n_len; + n2bytes += n2.n_len; + carry = 0; + while ((n1bytes > 0) && (n2bytes > 0)) { + + // add the two numbers together + tmp = n1.n_value[n1ptr--] + n2.n_value[n2ptr--] + carry; + // *sumptr = *n1ptr-- + *n2ptr-- + carry; + + // check if they are >= 10 (impossible to be more then 18) + if (tmp >= libbcmath.BASE) { + carry = 1; + tmp -= libbcmath.BASE; // yep, subtract 10, add a carry + } else { + carry = 0; + } + sum.n_value[sumptr] = tmp; + sumptr--; + n1bytes--; + n2bytes--; + } + + // Now add carry the [rest of the] longer integer part. + if (n1bytes === 0) { + // n2 is a bigger number then n1 + while (n2bytes-- > 0) { + tmp = n2.n_value[n2ptr--] + carry; + // *sumptr = *n2ptr-- + carry; + + if (tmp >= libbcmath.BASE) { + carry = 1; + tmp -= libbcmath.BASE; + } else { + carry = 0; + } + sum.n_value[sumptr--] = tmp; + } + } else { + // n1 is bigger then n2.. + while (n1bytes-- > 0) { + tmp = n1.n_value[n1ptr--] + carry; + // *sumptr = *n1ptr-- + carry; + + if (tmp >= libbcmath.BASE) { + carry = 1; + tmp -= libbcmath.BASE; + } else { + carry = 0; + } + sum.n_value[sumptr--] = tmp; + } + } + + // Set final carry. + if (carry == 1) { + sum.n_value[sumptr] += 1; + // *sumptr += 1; + } + + // Adjust sum and return. + libbcmath._bc_rm_leading_zeros(sum); + return sum; + }; + + /** + * Perform a subtraction + * + // Perform subtraction: N2 is subtracted from N1 and the value is + // returned. The signs of N1 and N2 are ignored. Also, N1 is + // assumed to be larger than N2. SCALE_MIN is the minimum scale + // of the result. + * + * Basic school maths says to subtract 2 numbers.. + * 1. make them the same length, the decimal places, and the integer part + * 2. start from the right and subtract the two numbers from each other + * 3. if the sum of the 2 numbers < 0, carry -1 to the next set and add 10 (ie 18 > carry 1 becomes 8). thus 0.9 + 0.9 = 1.8 + * + * @param bc_num n1 + * @param bc_num n2 + * @param int scale_min + * @return bc_num + */ + libbcmath._bc_do_sub = function (n1, n2, scale_min) { + let diff; // bc_num + let diff_scale, + diff_len; // int + let min_scale, + min_len; // int + let n1ptr, + n2ptr, + diffptr; // int + let borrow, + count, + val; // int + + // Allocate temporary storage. + diff_len = libbcmath.MAX(n1.n_len, n2.n_len); + diff_scale = libbcmath.MAX(n1.n_scale, n2.n_scale); + min_len = libbcmath.MIN(n1.n_len, n2.n_len); + min_scale = libbcmath.MIN(n1.n_scale, n2.n_scale); + diff = libbcmath.bc_new_num(diff_len, libbcmath.MAX(diff_scale, scale_min)); + + /* Not needed? + // Zero extra digits made by scale_min. + if (scale_min > diff_scale) { + diffptr = (char *) (diff->n_value + diff_len + diff_scale); + for (count = scale_min - diff_scale; count > 0; count--) { + *diffptr++ = 0; + } + } + */ + + // Initialize the subtract. + n1ptr = (n1.n_len + n1.n_scale - 1); + n2ptr = (n2.n_len + n2.n_scale - 1); + diffptr = (diff_len + diff_scale - 1); + + // Subtract the numbers. + borrow = 0; + + // Take care of the longer scaled number. + if (n1.n_scale != min_scale) { + // n1 has the longer scale + for (count = n1.n_scale - min_scale; count > 0; count--) { + diff.n_value[diffptr--] = n1.n_value[n1ptr--]; + // *diffptr-- = *n1ptr--; + } + } else { + // n2 has the longer scale + for (count = n2.n_scale - min_scale; count > 0; count--) { + val = 0 - n2.n_value[n2ptr--] - borrow; + // val = - *n2ptr-- - borrow; + if (val < 0) { + val += libbcmath.BASE; + borrow = 1; + } else { + borrow = 0; + diff.n_value[diffptr--] = val; + //* diffptr-- = val; + } + } + } + + // Now do the equal length scale and integer parts. + for (count = 0; count < min_len + min_scale; count++) { + val = n1.n_value[n1ptr--] - n2.n_value[n2ptr--] - borrow; + // val = *n1ptr-- - *n2ptr-- - borrow; + if (val < 0) { + val += libbcmath.BASE; + borrow = 1; + } else { + borrow = 0; + } + diff.n_value[diffptr--] = val; + //* diffptr-- = val; + } + + // If n1 has more digits then n2, we now do that subtract. + if (diff_len != min_len) { + for (count = diff_len - min_len; count > 0; count--) { + val = n1.n_value[n1ptr--] - borrow; + // val = *n1ptr-- - borrow; + if (val < 0) { + val += libbcmath.BASE; + borrow = 1; + } else { + borrow = 0; + } + diff.n_value[diffptr--] = val; + } + } + + // Clean up and return. + libbcmath._bc_rm_leading_zeros(diff); + return diff; + }; + + libbcmath.MUL_BASE_DIGITS = 80; + libbcmath.MUL_SMALL_DIGITS = (libbcmath.MUL_BASE_DIGITS / 4); // #define MUL_SMALL_DIGITS mul_base_digits/4 + + + /* The multiply routine. N2 times N1 is put int PROD with the scale of + the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)). + */ + /** + * @param n1 bc_num + * @param n2 bc_num + * @param scale [int] optional + */ + libbcmath.bc_multiply = function (n1, n2, scale) { + let pval; // bc_num + let len1, + len2; // int + let full_scale, + prod_scale; // int + + // Initialize things. + len1 = n1.n_len + n1.n_scale; + len2 = n2.n_len + n2.n_scale; + full_scale = n1.n_scale + n2.n_scale; + prod_scale = libbcmath.MIN(full_scale, libbcmath.MAX(scale, libbcmath.MAX(n1.n_scale, n2.n_scale))); + + // pval = libbcmath.bc_init_num(); // allow pass by ref + // Do the multiply + pval = libbcmath._bc_rec_mul(n1, len1, n2, len2, full_scale); + + // Assign to prod and clean up the number. + pval.n_sign = (n1.n_sign == n2.n_sign ? libbcmath.PLUS : libbcmath.MINUS); + // pval.n_value = pval.n_ptr; // @FIX + pval.n_len = len2 + len1 + 1 - full_scale; + pval.n_scale = prod_scale; + libbcmath._bc_rm_leading_zeros(pval); + if (libbcmath.bc_is_zero(pval)) { + pval.n_sign = libbcmath.PLUS; + } + // bc_free_num (prod); + return pval; + }; + + libbcmath.new_sub_num = function (length, scale, value) { + const temp = new libbcmath.bc_num(); + temp.n_sign = libbcmath.PLUS; + temp.n_len = length; + temp.n_scale = scale; + temp.n_value = value; + return temp; + }; + + libbcmath._bc_simp_mul = function (n1, n1len, n2, n2len, full_scale) { + let prod; // bc_num + let n1ptr, + n2ptr, + pvptr; // char *n1ptr, *n2ptr, *pvptr; + let n1end, + n2end; // char *n1end, *n2end; /* To the end of n1 and n2. */ + let indx, + sum, + prodlen; // int indx, sum, prodlen; + + prodlen = n1len + n2len + 1; + + prod = libbcmath.bc_new_num(prodlen, 0); + + n1end = n1len - 1; // (char *) (n1->n_value + n1len - 1); + n2end = n2len - 1; // (char *) (n2->n_value + n2len - 1); + pvptr = prodlen - 1; // (char *) ((*prod)->n_value + prodlen - 1); + sum = 0; + + // Here is the loop... + for (indx = 0; indx < prodlen - 1; indx++) { + n1ptr = n1end - libbcmath.MAX(0, indx - n2len + 1); // (char *) (n1end - MAX(0, indx-n2len+1)); + n2ptr = n2end - libbcmath.MIN(indx, n2len - 1); // (char *) (n2end - MIN(indx, n2len-1)); + while ((n1ptr >= 0) && (n2ptr <= n2end)) { + sum += n1.n_value[n1ptr--] * n2.n_value[n2ptr++]; // sum += *n1ptr-- * *n2ptr++; + } + prod.n_value[pvptr--] = Math.floor(sum % libbcmath.BASE); //* pvptr-- = sum % BASE; + sum = Math.floor(sum / libbcmath.BASE); // sum = sum / BASE; + } + prod.n_value[pvptr] = sum; //* pvptr = sum; + return prod; + }; + + + /* A special adder/subtractor for the recursive divide and conquer + multiply algorithm. Note: if sub is called, accum must + be larger that what is being subtracted. Also, accum and val + must have n_scale = 0. (e.g. they must look like integers. *) */ + libbcmath._bc_shift_addsub = function (accum, val, shift, sub) { + let accp, + valp; // signed char *accp, *valp; + let count, + carry; // int count, carry; + + count = val.n_len; + if (val.n_value[0] === 0) { + count--; + } + + // assert (accum->n_len+accum->n_scale >= shift+count); + if (!(accum.n_len + accum.n_scale >= shift + count)) { + throw new Error('len + scale < shift + count'); // ?? I think thats what assert does :) + } + + + // Set up pointers and others + accp = accum.n_len + accum.n_scale - shift - 1; // (signed char *)(accum->n_value + accum->n_len + accum->n_scale - shift - 1); + valp = val.n_len = 1; // (signed char *)(val->n_value + val->n_len - 1); + carry = 0; + if (sub) { + // Subtraction, carry is really borrow. + while (count--) { + accum.n_value[accp] -= val.n_value[valp--] + carry; //* accp -= *valp-- + carry; + if (accum.n_value[accp] < 0) { // if (*accp < 0) + carry = 1; + accum.n_value[accp--] += libbcmath.BASE; //* accp-- += BASE; + } else { + carry = 0; + accp--; + } + } + while (carry) { + accum.n_value[accp] -= carry; //* accp -= carry; + if (accum.n_value[accp] < 0) { // if (*accp < 0) + accum.n_value[accp--] += libbcmath.BASE; // *accp-- += BASE; + } else { + carry = 0; + } + } + } else { + // Addition + while (count--) { + accum.n_value[accp] += val.n_value[valp--] + carry; //* accp += *valp-- + carry; + if (accum.n_value[accp] > (libbcmath.BASE - 1)) { // if (*accp > (BASE-1)) + carry = 1; + accum.n_value[accp--] -= libbcmath.BASE; //* accp-- -= BASE; + } else { + carry = 0; + accp--; + } + } + while (carry) { + accum.n_value[accp] += carry; //* accp += carry; + if (accum.n_value[accp] > (libbcmath.BASE - 1)) { // if (*accp > (BASE-1)) + accum.n_value[accp--] -= libbcmath.BASE; //* accp-- -= BASE; + } else { + carry = 0; + } + } + } + return true; // accum is the pass-by-reference return + }; + + /* Recursive divide and conquer multiply algorithm. + Based on + Let u = u0 + u1*(b^n) + Let v = v0 + v1*(b^n) + Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0 + + B is the base of storage, number of digits in u1,u0 close to equal. + */ + libbcmath._bc_rec_mul = function (u, ulen, v, vlen, full_scale) { + let prod; // @return + let u0, + u1, + v0, + v1; // bc_num + let u0len, + v0len; // int + let m1, + m2, + m3, + d1, + d2; // bc_num + let n, + prodlen, + m1zero; // int + let d1len, + d2len; // int + + // Base case? + if ((ulen + vlen) < libbcmath.MUL_BASE_DIGITS || ulen < libbcmath.MUL_SMALL_DIGITS || vlen < libbcmath.MUL_SMALL_DIGITS) { + return libbcmath._bc_simp_mul(u, ulen, v, vlen, full_scale); + } + + // Calculate n -- the u and v split point in digits. + n = Math.floor((libbcmath.MAX(ulen, vlen) + 1) / 2); + + // Split u and v. + if (ulen < n) { + u1 = libbcmath.bc_init_num(); // u1 = bc_copy_num (BCG(_zero_)); + u0 = libbcmath.new_sub_num(ulen, 0, u.n_value); + } else { + u1 = libbcmath.new_sub_num(ulen - n, 0, u.n_value); + u0 = libbcmath.new_sub_num(n, 0, u.n_value + ulen - n); + } + if (vlen < n) { + v1 = libbcmath.bc_init_num(); // bc_copy_num (BCG(_zero_)); + v0 = libbcmath.new_sub_num(vlen, 0, v.n_value); + } else { + v1 = libbcmath.new_sub_num(vlen - n, 0, v.n_value); + v0 = libbcmath.new_sub_num(n, 0, v.n_value + vlen - n); + } + libbcmath._bc_rm_leading_zeros(u1); + libbcmath._bc_rm_leading_zeros(u0); + u0len = u0.n_len; + libbcmath._bc_rm_leading_zeros(v1); + libbcmath._bc_rm_leading_zeros(v0); + v0len = v0.n_len; + + m1zero = libbcmath.bc_is_zero(u1) || libbcmath.bc_is_zero(v1); + + // Calculate sub results ... + + d1 = libbcmath.bc_init_num(); // needed? + d2 = libbcmath.bc_init_num(); // needed? + d1 = libbcmath.bc_sub(u1, u0, 0); + d1len = d1.n_len; + + d2 = libbcmath.bc_sub(v0, v1, 0); + d2len = d2.n_len; + + // Do recursive multiplies and shifted adds. + if (m1zero) { + m1 = libbcmath.bc_init_num(); // bc_copy_num (BCG(_zero_)); + } else { + // m1 = libbcmath.bc_init_num(); //allow pass-by-ref + m1 = libbcmath._bc_rec_mul(u1, u1.n_len, v1, v1.n_len, 0); + } + if (libbcmath.bc_is_zero(d1) || libbcmath.bc_is_zero(d2)) { + m2 = libbcmath.bc_init_num(); // bc_copy_num (BCG(_zero_)); + } else { + // m2 = libbcmath.bc_init_num(); //allow pass-by-ref + m2 = libbcmath._bc_rec_mul(d1, d1len, d2, d2len, 0); + } + + if (libbcmath.bc_is_zero(u0) || libbcmath.bc_is_zero(v0)) { + m3 = libbcmath.bc_init_num(); // bc_copy_num (BCG(_zero_)); + } else { + // m3 = libbcmath.bc_init_num(); //allow pass-by-ref + m3 = libbcmath._bc_rec_mul(u0, u0.n_len, v0, v0.n_len, 0); + } + + // Initialize product + prodlen = ulen + vlen + 1; + prod = libbcmath.bc_new_num(prodlen, 0); + + if (!m1zero) { + libbcmath._bc_shift_addsub(prod, m1, 2 * n, 0); + libbcmath._bc_shift_addsub(prod, m1, n, 0); + } + libbcmath._bc_shift_addsub(prod, m3, n, 0); + libbcmath._bc_shift_addsub(prod, m3, 0, 0); + libbcmath._bc_shift_addsub(prod, m2, n, d1.n_sign != d2.n_sign); + + return prod; + // Now clean up! + // bc_free_num (&u1); + // bc_free_num (&u0); + // bc_free_num (&v1); + // bc_free_num (&m1); + // bc_free_num (&v0); + // bc_free_num (&m2); + // bc_free_num (&m3); + // bc_free_num (&d1); + // bc_free_num (&d2); + }; + /** + * PHP Implementation of the libbcmath functions + * + * Designed to replicate the PHP functions exactly. + * Also includes new function: bcround + */ + + + /** + * bcadd - Add two arbitrary precision numbers + * Sums left_operand and right_operand. + * + * @param string left_operand The left operand, as a string + * @param string right_operand The right operand, as a string. + * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() + * @return string + */ + function bcadd(left_operand, right_operand, scale) { + let first, + second, + result; + + if (typeof (scale) === 'undefined') { + scale = libbcmath.scale; + } + scale = ((scale < 0) ? 0 : scale); + + // create objects + first = libbcmath.bc_init_num(); + second = libbcmath.bc_init_num(); + result = libbcmath.bc_init_num(); + + first = libbcmath.php_str2num(left_operand.toString()); + second = libbcmath.php_str2num(right_operand.toString()); + + // normalize arguments to same scale. + if (first.n_scale > second.n_scale) second.setScale(first.n_scale); + if (second.n_scale > first.n_scale) first.setScale(second.n_scale); + + result = libbcmath.bc_add(first, second, scale); + + if (result.n_scale > scale) { + result.n_scale = scale; + } + + return result.toString(); + } + + /** + * bcsub - Subtract one arbitrary precision number from another + * Returns difference between the left operand and the right operand. + * + * @param string left_operand The left operand, as a string + * @param string right_operand The right operand, as a string. + * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() + * @return string + */ + function bcsub(left_operand, right_operand, scale) { + let first, + second, + result; + + if (typeof (scale) === 'undefined') { + scale = libbcmath.scale; + } + scale = ((scale < 0) ? 0 : scale); + + // create objects + first = libbcmath.bc_init_num(); + second = libbcmath.bc_init_num(); + result = libbcmath.bc_init_num(); + + first = libbcmath.php_str2num(left_operand.toString()); + second = libbcmath.php_str2num(right_operand.toString()); + + // normalize arguments to same scale. + if (first.n_scale > second.n_scale) second.setScale(first.n_scale); + if (second.n_scale > first.n_scale) first.setScale(second.n_scale); + + result = libbcmath.bc_sub(first, second, scale); + + if (result.n_scale > scale) { + result.n_scale = scale; + } + + return result.toString(); + + } + + /** + * bccomp - Compare two arbitrary precision numers + * + * @param string left_operand The left operand, as a string + * @param string right_operand The right operand, as a string. + * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() + * @return int 0: Left/Right are equal, 1 if left > right, -1 otherwise + */ + function bccomp(left_operand, right_operand, scale) { + let first, + second; // bc_num + + if (typeof (scale) === 'undefined') { + scale = libbcmath.scale; + } + scale = ((scale < 0) ? 0 : scale); + + first = libbcmath.bc_init_num(); + second = libbcmath.bc_init_num(); + + first = libbcmath.bc_str2num(left_operand.toString(), scale); // note bc_ not php_str2num + second = libbcmath.bc_str2num(right_operand.toString(), scale); // note bc_ not php_str2num + + return libbcmath.bc_compare(first, second, scale); + } + + /** + * bcscale - Set default scale parameter for all bc math functions + * @param int scale The scale factor (0 to infinate) + * @return bool + */ + function bcscale(scale) { + scale = parseInt(scale, 10); + if (isNaN(scale)) { + return false; + } + if (scale < 0) { + return false; + } + libbcmath.scale = scale; + return true; + } + + + /** + * bcdiv - Divide two arbitrary precision numbers + * + * @param string left_operand The left operand, as a string + * @param string right_operand The right operand, as a string. + * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() + * @return string The result as a string + */ + function bcdiv(left_operand, right_operand, scale) { + let first, + second, + result; + + if (typeof (scale) === 'undefined') { + scale = libbcmath.scale; + } + scale = ((scale < 0) ? 0 : scale); + + // create objects + first = libbcmath.bc_init_num(); + second = libbcmath.bc_init_num(); + result = libbcmath.bc_init_num(); + + first = libbcmath.php_str2num(left_operand.toString()); + second = libbcmath.php_str2num(right_operand.toString()); + + // normalize arguments to same scale. + if (first.n_scale > second.n_scale) second.setScale(first.n_scale); + if (second.n_scale > first.n_scale) first.setScale(second.n_scale); + + + result = libbcmath.bc_divide(first, second, scale); + if (result === -1) { + // error + throw new Error(11, '(BC) Division by zero'); + } + if (result.n_scale > scale) { + result.n_scale = scale; + } + return result.toString(); + } + + /** + * bcdiv - Multiply two arbitrary precision number + * + * @param string left_operand The left operand, as a string + * @param string right_operand The right operand, as a string. + * @param int [scale] The optional parameter is used to set the number of digits after the decimal place in the result. You can also set the global scale for all functions by using bcscale() + * @return string The result as a string + */ + function bcmul(left_operand, right_operand, scale) { + let first, + second, + result; + + if (typeof (scale) === 'undefined') { + scale = libbcmath.scale; + } + scale = ((scale < 0) ? 0 : scale); + + // create objects + first = libbcmath.bc_init_num(); + second = libbcmath.bc_init_num(); + result = libbcmath.bc_init_num(); + + first = libbcmath.php_str2num(left_operand.toString()); + second = libbcmath.php_str2num(right_operand.toString()); + + // normalize arguments to same scale. + if (first.n_scale > second.n_scale) second.setScale(first.n_scale); + if (second.n_scale > first.n_scale) first.setScale(second.n_scale); + + + result = libbcmath.bc_multiply(first, second, scale); + + if (result.n_scale > scale) { + result.n_scale = scale; + } + return result.toString(); + } + + + /** + * bcround - Returns the rounded value of [val] to the specified [precision] (number of digits after the decimal point). + * [precision] can also be a negative or zero (default) + * Note: uses "round up and away from zero" method (ie -1.5 > -2, 1.5 > 2 where .5 always goes to 1 (or 0.5 to -1) etc + * + * @param string val The value to round (accept in virtually any format) + * @param int precision The optional number of digits to round-to + * @return string In exact decimal places of precision (ie bcround('1.2222', 2) == '1.22' or bcround('1', 4) == '1.0000' ) + */ + function bcround(val, precision) { + let x, + r; + x = `0.${Array(precision + 1).join('0')}5`; + if (val.toString().substring(0, 1) == '-') { + x = `-${x}`; + } + + r = bcadd(val, x, precision); + + return r; + } + /* + var temp, result, digit; + var right_operand; + + // create number + temp = libbcmath.bc_init_num(); + temp = libbcmath.php_str2num(val.toString()); + + // check if any rounding needs + if (precision >= temp.n_scale) { + // nothing to round, just add the zeros. + while (temp.n_scale < precision) { + temp.n_value[temp.n_len+temp.n_scale]=0; + temp.n_scale++; + } + return temp.toString(); + } + + // get the digit we are checking (1 after the precision) + // loop through digits after the precision marker + digit = temp.n_value[temp.n_len + precision]; + + right_operand = libbcmath.bc_init_num(); + right_operand = libbcmath.bc_new_num(1, precision); + + if (digit >= 5) { + //round away from zero by adding 1 (or -1) at the "precision".. ie 1.44999 @ 3dp = (1.44999 + 0.001).toString().substr(0,5) + right_operand.n_value[right_operand.n_len+right_operand.n_scale-1] = 1; + if (temp.n_sign == libbcmath.MINUS) { + // round down + right_operand.n_sign = libbcmath.MINUS; + } + result = libbcmath.bc_add(temp, right_operand, precision); + } else { + // leave-as-is.. just truncate it. + result = temp; + } + + if (result.n_scale > precision) { + result.n_scale = precision; + } + return result.toString(); + } */ + + /* Import the PDF417 library */ + /*= =================================================================================================================================================* + | PDF417 BARCODE CONSTANTS | + *================================================================================================================================================== */ + + const ROWHEIGHT = 1; + + const START_PATTERN = '11111111010101000'; + const STOP_PATTERN = '111111101000101001'; + + /** Array of text Compaction Sub-Modes (values 0xFB - 0xFF are used for submode changers). */ + const TEXT_SUBMODES = [[ // ALPHA -------------------------------------------------------------------------------- + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x20, 0xFD, 0xFE, 0xFF], + [ // LOWER -------------------------------------------------------------------------------- + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x20, 0xFD, 0xFE, 0xFF], + [ // MIXED -------------------------------------------------------------------------------- + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x26, 0x0d, 0x09, 0x2c, 0x3a, + 0x23, 0x2d, 0x2e, 0x24, 0x2f, 0x2b, 0x25, 0x2a, 0x3d, 0x5e, 0xFB, 0x20, 0xFD, 0xFE, 0xFF], + [ // PUNCTUATION -------------------------------------------------------------------------- + 0x3b, 0x3c, 0x3e, 0x40, 0x5b, 0x5c, 0x5d, 0x5f, 0x60, 0x7e, 0x21, 0x0d, 0x09, 0x2c, 0x3a, + 0x0a, 0x2d, 0x2e, 0x24, 0x2f, 0x22, 0x7c, 0x2a, 0x28, 0x29, 0x3f, 0x7b, 0x7d, 0x27, 0xFF]]; + + /** Array of switching codes for Text Compaction Sub-Modes. */ + const TEXT_LATCH = { + '01': [27], + '02': [28], + '03': [28, 25], + 10: [28, 28], + 12: [28], + 13: [28, 25], + 20: [28], + 21: [27], + 23: [25], + 30: [29], + 31: [29, 27], + 32: [29, 28], + }; + + /** + * Clusters of codewords (0, 3, 6)
+ * Values are hex equivalents of binary representation of bars (1 = bar, 0 = space).
+ * The codewords numbered from 900 to 928 have special meaning, some enable to switch between modes in order to optimise the code: + *
    + *
  • 900 : Switch to "Text" mode
  • + *
  • 901 : Switch to "Byte" mode
  • + *
  • 902 : Switch to "Numeric" mode
  • + *
  • 903 - 912 : Reserved
  • + *
  • 913 : Switch to "Octet" only for the next codeword
  • + *
  • 914 - 920 : Reserved
  • + *
  • 921 : Initialization
  • + *
  • 922 : Terminator codeword for Macro PDF control block
  • + *
  • 923 : Sequence tag to identify the beginning of optional fields in the Macro PDF control block
  • + *
  • 924 : Switch to "Byte" mode (If the total number of byte is multiple of 6)
  • + *
  • 925 : Identifier for a user defined Extended Channel Interpretation (ECI)
  • + *
  • 926 : Identifier for a general purpose ECI format
  • + *
  • 927 : Identifier for an ECI of a character set or code page
  • + *
  • 928 : Macro marker codeword to indicate the beginning of a Macro PDF Control Block
  • + *
+ */ + const CLUSTERS = [[ // cluster 0 -------------------------------------------------------------------------- + 0x1d5c0, 0x1eaf0, 0x1f57c, 0x1d4e0, 0x1ea78, 0x1f53e, 0x1a8c0, 0x1d470, 0x1a860, 0x15040, // 10 + 0x1a830, 0x15020, 0x1adc0, 0x1d6f0, 0x1eb7c, 0x1ace0, 0x1d678, 0x1eb3e, 0x158c0, 0x1ac70, // 20 + 0x15860, 0x15dc0, 0x1aef0, 0x1d77c, 0x15ce0, 0x1ae78, 0x1d73e, 0x15c70, 0x1ae3c, 0x15ef0, // 30 + 0x1af7c, 0x15e78, 0x1af3e, 0x15f7c, 0x1f5fa, 0x1d2e0, 0x1e978, 0x1f4be, 0x1a4c0, 0x1d270, // 40 + 0x1e93c, 0x1a460, 0x1d238, 0x14840, 0x1a430, 0x1d21c, 0x14820, 0x1a418, 0x14810, 0x1a6e0, // 50 + 0x1d378, 0x1e9be, 0x14cc0, 0x1a670, 0x1d33c, 0x14c60, 0x1a638, 0x1d31e, 0x14c30, 0x1a61c, // 60 + 0x14ee0, 0x1a778, 0x1d3be, 0x14e70, 0x1a73c, 0x14e38, 0x1a71e, 0x14f78, 0x1a7be, 0x14f3c, // 70 + 0x14f1e, 0x1a2c0, 0x1d170, 0x1e8bc, 0x1a260, 0x1d138, 0x1e89e, 0x14440, 0x1a230, 0x1d11c, // 80 + 0x14420, 0x1a218, 0x14410, 0x14408, 0x146c0, 0x1a370, 0x1d1bc, 0x14660, 0x1a338, 0x1d19e, // 90 + 0x14630, 0x1a31c, 0x14618, 0x1460c, 0x14770, 0x1a3bc, 0x14738, 0x1a39e, 0x1471c, 0x147bc, // 100 + 0x1a160, 0x1d0b8, 0x1e85e, 0x14240, 0x1a130, 0x1d09c, 0x14220, 0x1a118, 0x1d08e, 0x14210, // 110 + 0x1a10c, 0x14208, 0x1a106, 0x14360, 0x1a1b8, 0x1d0de, 0x14330, 0x1a19c, 0x14318, 0x1a18e, // 120 + 0x1430c, 0x14306, 0x1a1de, 0x1438e, 0x14140, 0x1a0b0, 0x1d05c, 0x14120, 0x1a098, 0x1d04e, // 130 + 0x14110, 0x1a08c, 0x14108, 0x1a086, 0x14104, 0x141b0, 0x14198, 0x1418c, 0x140a0, 0x1d02e, // 140 + 0x1a04c, 0x1a046, 0x14082, 0x1cae0, 0x1e578, 0x1f2be, 0x194c0, 0x1ca70, 0x1e53c, 0x19460, // 150 + 0x1ca38, 0x1e51e, 0x12840, 0x19430, 0x12820, 0x196e0, 0x1cb78, 0x1e5be, 0x12cc0, 0x19670, // 160 + 0x1cb3c, 0x12c60, 0x19638, 0x12c30, 0x12c18, 0x12ee0, 0x19778, 0x1cbbe, 0x12e70, 0x1973c, // 170 + 0x12e38, 0x12e1c, 0x12f78, 0x197be, 0x12f3c, 0x12fbe, 0x1dac0, 0x1ed70, 0x1f6bc, 0x1da60, // 180 + 0x1ed38, 0x1f69e, 0x1b440, 0x1da30, 0x1ed1c, 0x1b420, 0x1da18, 0x1ed0e, 0x1b410, 0x1da0c, // 190 + 0x192c0, 0x1c970, 0x1e4bc, 0x1b6c0, 0x19260, 0x1c938, 0x1e49e, 0x1b660, 0x1db38, 0x1ed9e, // 200 + 0x16c40, 0x12420, 0x19218, 0x1c90e, 0x16c20, 0x1b618, 0x16c10, 0x126c0, 0x19370, 0x1c9bc, // 210 + 0x16ec0, 0x12660, 0x19338, 0x1c99e, 0x16e60, 0x1b738, 0x1db9e, 0x16e30, 0x12618, 0x16e18, // 220 + 0x12770, 0x193bc, 0x16f70, 0x12738, 0x1939e, 0x16f38, 0x1b79e, 0x16f1c, 0x127bc, 0x16fbc, // 230 + 0x1279e, 0x16f9e, 0x1d960, 0x1ecb8, 0x1f65e, 0x1b240, 0x1d930, 0x1ec9c, 0x1b220, 0x1d918, // 240 + 0x1ec8e, 0x1b210, 0x1d90c, 0x1b208, 0x1b204, 0x19160, 0x1c8b8, 0x1e45e, 0x1b360, 0x19130, // 250 + 0x1c89c, 0x16640, 0x12220, 0x1d99c, 0x1c88e, 0x16620, 0x12210, 0x1910c, 0x16610, 0x1b30c, // 260 + 0x19106, 0x12204, 0x12360, 0x191b8, 0x1c8de, 0x16760, 0x12330, 0x1919c, 0x16730, 0x1b39c, // 270 + 0x1918e, 0x16718, 0x1230c, 0x12306, 0x123b8, 0x191de, 0x167b8, 0x1239c, 0x1679c, 0x1238e, // 280 + 0x1678e, 0x167de, 0x1b140, 0x1d8b0, 0x1ec5c, 0x1b120, 0x1d898, 0x1ec4e, 0x1b110, 0x1d88c, // 290 + 0x1b108, 0x1d886, 0x1b104, 0x1b102, 0x12140, 0x190b0, 0x1c85c, 0x16340, 0x12120, 0x19098, // 300 + 0x1c84e, 0x16320, 0x1b198, 0x1d8ce, 0x16310, 0x12108, 0x19086, 0x16308, 0x1b186, 0x16304, // 310 + 0x121b0, 0x190dc, 0x163b0, 0x12198, 0x190ce, 0x16398, 0x1b1ce, 0x1638c, 0x12186, 0x16386, // 320 + 0x163dc, 0x163ce, 0x1b0a0, 0x1d858, 0x1ec2e, 0x1b090, 0x1d84c, 0x1b088, 0x1d846, 0x1b084, // 330 + 0x1b082, 0x120a0, 0x19058, 0x1c82e, 0x161a0, 0x12090, 0x1904c, 0x16190, 0x1b0cc, 0x19046, // 340 + 0x16188, 0x12084, 0x16184, 0x12082, 0x120d8, 0x161d8, 0x161cc, 0x161c6, 0x1d82c, 0x1d826, // 350 + 0x1b042, 0x1902c, 0x12048, 0x160c8, 0x160c4, 0x160c2, 0x18ac0, 0x1c570, 0x1e2bc, 0x18a60, // 360 + 0x1c538, 0x11440, 0x18a30, 0x1c51c, 0x11420, 0x18a18, 0x11410, 0x11408, 0x116c0, 0x18b70, // 370 + 0x1c5bc, 0x11660, 0x18b38, 0x1c59e, 0x11630, 0x18b1c, 0x11618, 0x1160c, 0x11770, 0x18bbc, // 380 + 0x11738, 0x18b9e, 0x1171c, 0x117bc, 0x1179e, 0x1cd60, 0x1e6b8, 0x1f35e, 0x19a40, 0x1cd30, // 390 + 0x1e69c, 0x19a20, 0x1cd18, 0x1e68e, 0x19a10, 0x1cd0c, 0x19a08, 0x1cd06, 0x18960, 0x1c4b8, // 400 + 0x1e25e, 0x19b60, 0x18930, 0x1c49c, 0x13640, 0x11220, 0x1cd9c, 0x1c48e, 0x13620, 0x19b18, // 410 + 0x1890c, 0x13610, 0x11208, 0x13608, 0x11360, 0x189b8, 0x1c4de, 0x13760, 0x11330, 0x1cdde, // 420 + 0x13730, 0x19b9c, 0x1898e, 0x13718, 0x1130c, 0x1370c, 0x113b8, 0x189de, 0x137b8, 0x1139c, // 430 + 0x1379c, 0x1138e, 0x113de, 0x137de, 0x1dd40, 0x1eeb0, 0x1f75c, 0x1dd20, 0x1ee98, 0x1f74e, // 440 + 0x1dd10, 0x1ee8c, 0x1dd08, 0x1ee86, 0x1dd04, 0x19940, 0x1ccb0, 0x1e65c, 0x1bb40, 0x19920, // 450 + 0x1eedc, 0x1e64e, 0x1bb20, 0x1dd98, 0x1eece, 0x1bb10, 0x19908, 0x1cc86, 0x1bb08, 0x1dd86, // 460 + 0x19902, 0x11140, 0x188b0, 0x1c45c, 0x13340, 0x11120, 0x18898, 0x1c44e, 0x17740, 0x13320, // 470 + 0x19998, 0x1ccce, 0x17720, 0x1bb98, 0x1ddce, 0x18886, 0x17710, 0x13308, 0x19986, 0x17708, // 480 + 0x11102, 0x111b0, 0x188dc, 0x133b0, 0x11198, 0x188ce, 0x177b0, 0x13398, 0x199ce, 0x17798, // 490 + 0x1bbce, 0x11186, 0x13386, 0x111dc, 0x133dc, 0x111ce, 0x177dc, 0x133ce, 0x1dca0, 0x1ee58, // 500 + 0x1f72e, 0x1dc90, 0x1ee4c, 0x1dc88, 0x1ee46, 0x1dc84, 0x1dc82, 0x198a0, 0x1cc58, 0x1e62e, // 510 + 0x1b9a0, 0x19890, 0x1ee6e, 0x1b990, 0x1dccc, 0x1cc46, 0x1b988, 0x19884, 0x1b984, 0x19882, // 520 + 0x1b982, 0x110a0, 0x18858, 0x1c42e, 0x131a0, 0x11090, 0x1884c, 0x173a0, 0x13190, 0x198cc, // 530 + 0x18846, 0x17390, 0x1b9cc, 0x11084, 0x17388, 0x13184, 0x11082, 0x13182, 0x110d8, 0x1886e, // 540 + 0x131d8, 0x110cc, 0x173d8, 0x131cc, 0x110c6, 0x173cc, 0x131c6, 0x110ee, 0x173ee, 0x1dc50, // 550 + 0x1ee2c, 0x1dc48, 0x1ee26, 0x1dc44, 0x1dc42, 0x19850, 0x1cc2c, 0x1b8d0, 0x19848, 0x1cc26, // 560 + 0x1b8c8, 0x1dc66, 0x1b8c4, 0x19842, 0x1b8c2, 0x11050, 0x1882c, 0x130d0, 0x11048, 0x18826, // 570 + 0x171d0, 0x130c8, 0x19866, 0x171c8, 0x1b8e6, 0x11042, 0x171c4, 0x130c2, 0x171c2, 0x130ec, // 580 + 0x171ec, 0x171e6, 0x1ee16, 0x1dc22, 0x1cc16, 0x19824, 0x19822, 0x11028, 0x13068, 0x170e8, // 590 + 0x11022, 0x13062, 0x18560, 0x10a40, 0x18530, 0x10a20, 0x18518, 0x1c28e, 0x10a10, 0x1850c, // 600 + 0x10a08, 0x18506, 0x10b60, 0x185b8, 0x1c2de, 0x10b30, 0x1859c, 0x10b18, 0x1858e, 0x10b0c, // 610 + 0x10b06, 0x10bb8, 0x185de, 0x10b9c, 0x10b8e, 0x10bde, 0x18d40, 0x1c6b0, 0x1e35c, 0x18d20, // 620 + 0x1c698, 0x18d10, 0x1c68c, 0x18d08, 0x1c686, 0x18d04, 0x10940, 0x184b0, 0x1c25c, 0x11b40, // 630 + 0x10920, 0x1c6dc, 0x1c24e, 0x11b20, 0x18d98, 0x1c6ce, 0x11b10, 0x10908, 0x18486, 0x11b08, // 640 + 0x18d86, 0x10902, 0x109b0, 0x184dc, 0x11bb0, 0x10998, 0x184ce, 0x11b98, 0x18dce, 0x11b8c, // 650 + 0x10986, 0x109dc, 0x11bdc, 0x109ce, 0x11bce, 0x1cea0, 0x1e758, 0x1f3ae, 0x1ce90, 0x1e74c, // 660 + 0x1ce88, 0x1e746, 0x1ce84, 0x1ce82, 0x18ca0, 0x1c658, 0x19da0, 0x18c90, 0x1c64c, 0x19d90, // 670 + 0x1cecc, 0x1c646, 0x19d88, 0x18c84, 0x19d84, 0x18c82, 0x19d82, 0x108a0, 0x18458, 0x119a0, // 680 + 0x10890, 0x1c66e, 0x13ba0, 0x11990, 0x18ccc, 0x18446, 0x13b90, 0x19dcc, 0x10884, 0x13b88, // 690 + 0x11984, 0x10882, 0x11982, 0x108d8, 0x1846e, 0x119d8, 0x108cc, 0x13bd8, 0x119cc, 0x108c6, // 700 + 0x13bcc, 0x119c6, 0x108ee, 0x119ee, 0x13bee, 0x1ef50, 0x1f7ac, 0x1ef48, 0x1f7a6, 0x1ef44, // 710 + 0x1ef42, 0x1ce50, 0x1e72c, 0x1ded0, 0x1ef6c, 0x1e726, 0x1dec8, 0x1ef66, 0x1dec4, 0x1ce42, // 720 + 0x1dec2, 0x18c50, 0x1c62c, 0x19cd0, 0x18c48, 0x1c626, 0x1bdd0, 0x19cc8, 0x1ce66, 0x1bdc8, // 730 + 0x1dee6, 0x18c42, 0x1bdc4, 0x19cc2, 0x1bdc2, 0x10850, 0x1842c, 0x118d0, 0x10848, 0x18426, // 740 + 0x139d0, 0x118c8, 0x18c66, 0x17bd0, 0x139c8, 0x19ce6, 0x10842, 0x17bc8, 0x1bde6, 0x118c2, // 750 + 0x17bc4, 0x1086c, 0x118ec, 0x10866, 0x139ec, 0x118e6, 0x17bec, 0x139e6, 0x17be6, 0x1ef28, // 760 + 0x1f796, 0x1ef24, 0x1ef22, 0x1ce28, 0x1e716, 0x1de68, 0x1ef36, 0x1de64, 0x1ce22, 0x1de62, // 770 + 0x18c28, 0x1c616, 0x19c68, 0x18c24, 0x1bce8, 0x19c64, 0x18c22, 0x1bce4, 0x19c62, 0x1bce2, // 780 + 0x10828, 0x18416, 0x11868, 0x18c36, 0x138e8, 0x11864, 0x10822, 0x179e8, 0x138e4, 0x11862, // 790 + 0x179e4, 0x138e2, 0x179e2, 0x11876, 0x179f6, 0x1ef12, 0x1de34, 0x1de32, 0x19c34, 0x1bc74, // 800 + 0x1bc72, 0x11834, 0x13874, 0x178f4, 0x178f2, 0x10540, 0x10520, 0x18298, 0x10510, 0x10508, // 810 + 0x10504, 0x105b0, 0x10598, 0x1058c, 0x10586, 0x105dc, 0x105ce, 0x186a0, 0x18690, 0x1c34c, // 820 + 0x18688, 0x1c346, 0x18684, 0x18682, 0x104a0, 0x18258, 0x10da0, 0x186d8, 0x1824c, 0x10d90, // 830 + 0x186cc, 0x10d88, 0x186c6, 0x10d84, 0x10482, 0x10d82, 0x104d8, 0x1826e, 0x10dd8, 0x186ee, // 840 + 0x10dcc, 0x104c6, 0x10dc6, 0x104ee, 0x10dee, 0x1c750, 0x1c748, 0x1c744, 0x1c742, 0x18650, // 850 + 0x18ed0, 0x1c76c, 0x1c326, 0x18ec8, 0x1c766, 0x18ec4, 0x18642, 0x18ec2, 0x10450, 0x10cd0, // 860 + 0x10448, 0x18226, 0x11dd0, 0x10cc8, 0x10444, 0x11dc8, 0x10cc4, 0x10442, 0x11dc4, 0x10cc2, // 870 + 0x1046c, 0x10cec, 0x10466, 0x11dec, 0x10ce6, 0x11de6, 0x1e7a8, 0x1e7a4, 0x1e7a2, 0x1c728, // 880 + 0x1cf68, 0x1e7b6, 0x1cf64, 0x1c722, 0x1cf62, 0x18628, 0x1c316, 0x18e68, 0x1c736, 0x19ee8, // 890 + 0x18e64, 0x18622, 0x19ee4, 0x18e62, 0x19ee2, 0x10428, 0x18216, 0x10c68, 0x18636, 0x11ce8, // 900 + 0x10c64, 0x10422, 0x13de8, 0x11ce4, 0x10c62, 0x13de4, 0x11ce2, 0x10436, 0x10c76, 0x11cf6, // 910 + 0x13df6, 0x1f7d4, 0x1f7d2, 0x1e794, 0x1efb4, 0x1e792, 0x1efb2, 0x1c714, 0x1cf34, 0x1c712, // 920 + 0x1df74, 0x1cf32, 0x1df72, 0x18614, 0x18e34, 0x18612, 0x19e74, 0x18e32, 0x1bef4], // 929 + [ // cluster 3 -------------------------------------------------------------------------- + 0x1f560, 0x1fab8, 0x1ea40, 0x1f530, 0x1fa9c, 0x1ea20, 0x1f518, 0x1fa8e, 0x1ea10, 0x1f50c, // 10 + 0x1ea08, 0x1f506, 0x1ea04, 0x1eb60, 0x1f5b8, 0x1fade, 0x1d640, 0x1eb30, 0x1f59c, 0x1d620, // 20 + 0x1eb18, 0x1f58e, 0x1d610, 0x1eb0c, 0x1d608, 0x1eb06, 0x1d604, 0x1d760, 0x1ebb8, 0x1f5de, // 30 + 0x1ae40, 0x1d730, 0x1eb9c, 0x1ae20, 0x1d718, 0x1eb8e, 0x1ae10, 0x1d70c, 0x1ae08, 0x1d706, // 40 + 0x1ae04, 0x1af60, 0x1d7b8, 0x1ebde, 0x15e40, 0x1af30, 0x1d79c, 0x15e20, 0x1af18, 0x1d78e, // 50 + 0x15e10, 0x1af0c, 0x15e08, 0x1af06, 0x15f60, 0x1afb8, 0x1d7de, 0x15f30, 0x1af9c, 0x15f18, // 60 + 0x1af8e, 0x15f0c, 0x15fb8, 0x1afde, 0x15f9c, 0x15f8e, 0x1e940, 0x1f4b0, 0x1fa5c, 0x1e920, // 70 + 0x1f498, 0x1fa4e, 0x1e910, 0x1f48c, 0x1e908, 0x1f486, 0x1e904, 0x1e902, 0x1d340, 0x1e9b0, // 80 + 0x1f4dc, 0x1d320, 0x1e998, 0x1f4ce, 0x1d310, 0x1e98c, 0x1d308, 0x1e986, 0x1d304, 0x1d302, // 90 + 0x1a740, 0x1d3b0, 0x1e9dc, 0x1a720, 0x1d398, 0x1e9ce, 0x1a710, 0x1d38c, 0x1a708, 0x1d386, // 100 + 0x1a704, 0x1a702, 0x14f40, 0x1a7b0, 0x1d3dc, 0x14f20, 0x1a798, 0x1d3ce, 0x14f10, 0x1a78c, // 110 + 0x14f08, 0x1a786, 0x14f04, 0x14fb0, 0x1a7dc, 0x14f98, 0x1a7ce, 0x14f8c, 0x14f86, 0x14fdc, // 120 + 0x14fce, 0x1e8a0, 0x1f458, 0x1fa2e, 0x1e890, 0x1f44c, 0x1e888, 0x1f446, 0x1e884, 0x1e882, // 130 + 0x1d1a0, 0x1e8d8, 0x1f46e, 0x1d190, 0x1e8cc, 0x1d188, 0x1e8c6, 0x1d184, 0x1d182, 0x1a3a0, // 140 + 0x1d1d8, 0x1e8ee, 0x1a390, 0x1d1cc, 0x1a388, 0x1d1c6, 0x1a384, 0x1a382, 0x147a0, 0x1a3d8, // 150 + 0x1d1ee, 0x14790, 0x1a3cc, 0x14788, 0x1a3c6, 0x14784, 0x14782, 0x147d8, 0x1a3ee, 0x147cc, // 160 + 0x147c6, 0x147ee, 0x1e850, 0x1f42c, 0x1e848, 0x1f426, 0x1e844, 0x1e842, 0x1d0d0, 0x1e86c, // 170 + 0x1d0c8, 0x1e866, 0x1d0c4, 0x1d0c2, 0x1a1d0, 0x1d0ec, 0x1a1c8, 0x1d0e6, 0x1a1c4, 0x1a1c2, // 180 + 0x143d0, 0x1a1ec, 0x143c8, 0x1a1e6, 0x143c4, 0x143c2, 0x143ec, 0x143e6, 0x1e828, 0x1f416, // 190 + 0x1e824, 0x1e822, 0x1d068, 0x1e836, 0x1d064, 0x1d062, 0x1a0e8, 0x1d076, 0x1a0e4, 0x1a0e2, // 200 + 0x141e8, 0x1a0f6, 0x141e4, 0x141e2, 0x1e814, 0x1e812, 0x1d034, 0x1d032, 0x1a074, 0x1a072, // 210 + 0x1e540, 0x1f2b0, 0x1f95c, 0x1e520, 0x1f298, 0x1f94e, 0x1e510, 0x1f28c, 0x1e508, 0x1f286, // 220 + 0x1e504, 0x1e502, 0x1cb40, 0x1e5b0, 0x1f2dc, 0x1cb20, 0x1e598, 0x1f2ce, 0x1cb10, 0x1e58c, // 230 + 0x1cb08, 0x1e586, 0x1cb04, 0x1cb02, 0x19740, 0x1cbb0, 0x1e5dc, 0x19720, 0x1cb98, 0x1e5ce, // 240 + 0x19710, 0x1cb8c, 0x19708, 0x1cb86, 0x19704, 0x19702, 0x12f40, 0x197b0, 0x1cbdc, 0x12f20, // 250 + 0x19798, 0x1cbce, 0x12f10, 0x1978c, 0x12f08, 0x19786, 0x12f04, 0x12fb0, 0x197dc, 0x12f98, // 260 + 0x197ce, 0x12f8c, 0x12f86, 0x12fdc, 0x12fce, 0x1f6a0, 0x1fb58, 0x16bf0, 0x1f690, 0x1fb4c, // 270 + 0x169f8, 0x1f688, 0x1fb46, 0x168fc, 0x1f684, 0x1f682, 0x1e4a0, 0x1f258, 0x1f92e, 0x1eda0, // 280 + 0x1e490, 0x1fb6e, 0x1ed90, 0x1f6cc, 0x1f246, 0x1ed88, 0x1e484, 0x1ed84, 0x1e482, 0x1ed82, // 290 + 0x1c9a0, 0x1e4d8, 0x1f26e, 0x1dba0, 0x1c990, 0x1e4cc, 0x1db90, 0x1edcc, 0x1e4c6, 0x1db88, // 300 + 0x1c984, 0x1db84, 0x1c982, 0x1db82, 0x193a0, 0x1c9d8, 0x1e4ee, 0x1b7a0, 0x19390, 0x1c9cc, // 310 + 0x1b790, 0x1dbcc, 0x1c9c6, 0x1b788, 0x19384, 0x1b784, 0x19382, 0x1b782, 0x127a0, 0x193d8, // 320 + 0x1c9ee, 0x16fa0, 0x12790, 0x193cc, 0x16f90, 0x1b7cc, 0x193c6, 0x16f88, 0x12784, 0x16f84, // 330 + 0x12782, 0x127d8, 0x193ee, 0x16fd8, 0x127cc, 0x16fcc, 0x127c6, 0x16fc6, 0x127ee, 0x1f650, // 340 + 0x1fb2c, 0x165f8, 0x1f648, 0x1fb26, 0x164fc, 0x1f644, 0x1647e, 0x1f642, 0x1e450, 0x1f22c, // 350 + 0x1ecd0, 0x1e448, 0x1f226, 0x1ecc8, 0x1f666, 0x1ecc4, 0x1e442, 0x1ecc2, 0x1c8d0, 0x1e46c, // 360 + 0x1d9d0, 0x1c8c8, 0x1e466, 0x1d9c8, 0x1ece6, 0x1d9c4, 0x1c8c2, 0x1d9c2, 0x191d0, 0x1c8ec, // 370 + 0x1b3d0, 0x191c8, 0x1c8e6, 0x1b3c8, 0x1d9e6, 0x1b3c4, 0x191c2, 0x1b3c2, 0x123d0, 0x191ec, // 380 + 0x167d0, 0x123c8, 0x191e6, 0x167c8, 0x1b3e6, 0x167c4, 0x123c2, 0x167c2, 0x123ec, 0x167ec, // 390 + 0x123e6, 0x167e6, 0x1f628, 0x1fb16, 0x162fc, 0x1f624, 0x1627e, 0x1f622, 0x1e428, 0x1f216, // 400 + 0x1ec68, 0x1f636, 0x1ec64, 0x1e422, 0x1ec62, 0x1c868, 0x1e436, 0x1d8e8, 0x1c864, 0x1d8e4, // 410 + 0x1c862, 0x1d8e2, 0x190e8, 0x1c876, 0x1b1e8, 0x1d8f6, 0x1b1e4, 0x190e2, 0x1b1e2, 0x121e8, // 420 + 0x190f6, 0x163e8, 0x121e4, 0x163e4, 0x121e2, 0x163e2, 0x121f6, 0x163f6, 0x1f614, 0x1617e, // 430 + 0x1f612, 0x1e414, 0x1ec34, 0x1e412, 0x1ec32, 0x1c834, 0x1d874, 0x1c832, 0x1d872, 0x19074, // 440 + 0x1b0f4, 0x19072, 0x1b0f2, 0x120f4, 0x161f4, 0x120f2, 0x161f2, 0x1f60a, 0x1e40a, 0x1ec1a, // 450 + 0x1c81a, 0x1d83a, 0x1903a, 0x1b07a, 0x1e2a0, 0x1f158, 0x1f8ae, 0x1e290, 0x1f14c, 0x1e288, // 460 + 0x1f146, 0x1e284, 0x1e282, 0x1c5a0, 0x1e2d8, 0x1f16e, 0x1c590, 0x1e2cc, 0x1c588, 0x1e2c6, // 470 + 0x1c584, 0x1c582, 0x18ba0, 0x1c5d8, 0x1e2ee, 0x18b90, 0x1c5cc, 0x18b88, 0x1c5c6, 0x18b84, // 480 + 0x18b82, 0x117a0, 0x18bd8, 0x1c5ee, 0x11790, 0x18bcc, 0x11788, 0x18bc6, 0x11784, 0x11782, // 490 + 0x117d8, 0x18bee, 0x117cc, 0x117c6, 0x117ee, 0x1f350, 0x1f9ac, 0x135f8, 0x1f348, 0x1f9a6, // 500 + 0x134fc, 0x1f344, 0x1347e, 0x1f342, 0x1e250, 0x1f12c, 0x1e6d0, 0x1e248, 0x1f126, 0x1e6c8, // 510 + 0x1f366, 0x1e6c4, 0x1e242, 0x1e6c2, 0x1c4d0, 0x1e26c, 0x1cdd0, 0x1c4c8, 0x1e266, 0x1cdc8, // 520 + 0x1e6e6, 0x1cdc4, 0x1c4c2, 0x1cdc2, 0x189d0, 0x1c4ec, 0x19bd0, 0x189c8, 0x1c4e6, 0x19bc8, // 530 + 0x1cde6, 0x19bc4, 0x189c2, 0x19bc2, 0x113d0, 0x189ec, 0x137d0, 0x113c8, 0x189e6, 0x137c8, // 540 + 0x19be6, 0x137c4, 0x113c2, 0x137c2, 0x113ec, 0x137ec, 0x113e6, 0x137e6, 0x1fba8, 0x175f0, // 550 + 0x1bafc, 0x1fba4, 0x174f8, 0x1ba7e, 0x1fba2, 0x1747c, 0x1743e, 0x1f328, 0x1f996, 0x132fc, // 560 + 0x1f768, 0x1fbb6, 0x176fc, 0x1327e, 0x1f764, 0x1f322, 0x1767e, 0x1f762, 0x1e228, 0x1f116, // 570 + 0x1e668, 0x1e224, 0x1eee8, 0x1f776, 0x1e222, 0x1eee4, 0x1e662, 0x1eee2, 0x1c468, 0x1e236, // 580 + 0x1cce8, 0x1c464, 0x1dde8, 0x1cce4, 0x1c462, 0x1dde4, 0x1cce2, 0x1dde2, 0x188e8, 0x1c476, // 590 + 0x199e8, 0x188e4, 0x1bbe8, 0x199e4, 0x188e2, 0x1bbe4, 0x199e2, 0x1bbe2, 0x111e8, 0x188f6, // 600 + 0x133e8, 0x111e4, 0x177e8, 0x133e4, 0x111e2, 0x177e4, 0x133e2, 0x177e2, 0x111f6, 0x133f6, // 610 + 0x1fb94, 0x172f8, 0x1b97e, 0x1fb92, 0x1727c, 0x1723e, 0x1f314, 0x1317e, 0x1f734, 0x1f312, // 620 + 0x1737e, 0x1f732, 0x1e214, 0x1e634, 0x1e212, 0x1ee74, 0x1e632, 0x1ee72, 0x1c434, 0x1cc74, // 630 + 0x1c432, 0x1dcf4, 0x1cc72, 0x1dcf2, 0x18874, 0x198f4, 0x18872, 0x1b9f4, 0x198f2, 0x1b9f2, // 640 + 0x110f4, 0x131f4, 0x110f2, 0x173f4, 0x131f2, 0x173f2, 0x1fb8a, 0x1717c, 0x1713e, 0x1f30a, // 650 + 0x1f71a, 0x1e20a, 0x1e61a, 0x1ee3a, 0x1c41a, 0x1cc3a, 0x1dc7a, 0x1883a, 0x1987a, 0x1b8fa, // 660 + 0x1107a, 0x130fa, 0x171fa, 0x170be, 0x1e150, 0x1f0ac, 0x1e148, 0x1f0a6, 0x1e144, 0x1e142, // 670 + 0x1c2d0, 0x1e16c, 0x1c2c8, 0x1e166, 0x1c2c4, 0x1c2c2, 0x185d0, 0x1c2ec, 0x185c8, 0x1c2e6, // 680 + 0x185c4, 0x185c2, 0x10bd0, 0x185ec, 0x10bc8, 0x185e6, 0x10bc4, 0x10bc2, 0x10bec, 0x10be6, // 690 + 0x1f1a8, 0x1f8d6, 0x11afc, 0x1f1a4, 0x11a7e, 0x1f1a2, 0x1e128, 0x1f096, 0x1e368, 0x1e124, // 700 + 0x1e364, 0x1e122, 0x1e362, 0x1c268, 0x1e136, 0x1c6e8, 0x1c264, 0x1c6e4, 0x1c262, 0x1c6e2, // 710 + 0x184e8, 0x1c276, 0x18de8, 0x184e4, 0x18de4, 0x184e2, 0x18de2, 0x109e8, 0x184f6, 0x11be8, // 720 + 0x109e4, 0x11be4, 0x109e2, 0x11be2, 0x109f6, 0x11bf6, 0x1f9d4, 0x13af8, 0x19d7e, 0x1f9d2, // 730 + 0x13a7c, 0x13a3e, 0x1f194, 0x1197e, 0x1f3b4, 0x1f192, 0x13b7e, 0x1f3b2, 0x1e114, 0x1e334, // 740 + 0x1e112, 0x1e774, 0x1e332, 0x1e772, 0x1c234, 0x1c674, 0x1c232, 0x1cef4, 0x1c672, 0x1cef2, // 750 + 0x18474, 0x18cf4, 0x18472, 0x19df4, 0x18cf2, 0x19df2, 0x108f4, 0x119f4, 0x108f2, 0x13bf4, // 760 + 0x119f2, 0x13bf2, 0x17af0, 0x1bd7c, 0x17a78, 0x1bd3e, 0x17a3c, 0x17a1e, 0x1f9ca, 0x1397c, // 770 + 0x1fbda, 0x17b7c, 0x1393e, 0x17b3e, 0x1f18a, 0x1f39a, 0x1f7ba, 0x1e10a, 0x1e31a, 0x1e73a, // 780 + 0x1ef7a, 0x1c21a, 0x1c63a, 0x1ce7a, 0x1defa, 0x1843a, 0x18c7a, 0x19cfa, 0x1bdfa, 0x1087a, // 790 + 0x118fa, 0x139fa, 0x17978, 0x1bcbe, 0x1793c, 0x1791e, 0x138be, 0x179be, 0x178bc, 0x1789e, // 800 + 0x1785e, 0x1e0a8, 0x1e0a4, 0x1e0a2, 0x1c168, 0x1e0b6, 0x1c164, 0x1c162, 0x182e8, 0x1c176, // 810 + 0x182e4, 0x182e2, 0x105e8, 0x182f6, 0x105e4, 0x105e2, 0x105f6, 0x1f0d4, 0x10d7e, 0x1f0d2, // 820 + 0x1e094, 0x1e1b4, 0x1e092, 0x1e1b2, 0x1c134, 0x1c374, 0x1c132, 0x1c372, 0x18274, 0x186f4, // 830 + 0x18272, 0x186f2, 0x104f4, 0x10df4, 0x104f2, 0x10df2, 0x1f8ea, 0x11d7c, 0x11d3e, 0x1f0ca, // 840 + 0x1f1da, 0x1e08a, 0x1e19a, 0x1e3ba, 0x1c11a, 0x1c33a, 0x1c77a, 0x1823a, 0x1867a, 0x18efa, // 850 + 0x1047a, 0x10cfa, 0x11dfa, 0x13d78, 0x19ebe, 0x13d3c, 0x13d1e, 0x11cbe, 0x13dbe, 0x17d70, // 860 + 0x1bebc, 0x17d38, 0x1be9e, 0x17d1c, 0x17d0e, 0x13cbc, 0x17dbc, 0x13c9e, 0x17d9e, 0x17cb8, // 870 + 0x1be5e, 0x17c9c, 0x17c8e, 0x13c5e, 0x17cde, 0x17c5c, 0x17c4e, 0x17c2e, 0x1c0b4, 0x1c0b2, // 880 + 0x18174, 0x18172, 0x102f4, 0x102f2, 0x1e0da, 0x1c09a, 0x1c1ba, 0x1813a, 0x1837a, 0x1027a, // 890 + 0x106fa, 0x10ebe, 0x11ebc, 0x11e9e, 0x13eb8, 0x19f5e, 0x13e9c, 0x13e8e, 0x11e5e, 0x13ede, // 900 + 0x17eb0, 0x1bf5c, 0x17e98, 0x1bf4e, 0x17e8c, 0x17e86, 0x13e5c, 0x17edc, 0x13e4e, 0x17ece, // 910 + 0x17e58, 0x1bf2e, 0x17e4c, 0x17e46, 0x13e2e, 0x17e6e, 0x17e2c, 0x17e26, 0x10f5e, 0x11f5c, // 920 + 0x11f4e, 0x13f58, 0x19fae, 0x13f4c, 0x13f46, 0x11f2e, 0x13f6e, 0x13f2c, 0x13f26], // 929 + [ // cluster 6 -------------------------------------------------------------------------- + 0x1abe0, 0x1d5f8, 0x153c0, 0x1a9f0, 0x1d4fc, 0x151e0, 0x1a8f8, 0x1d47e, 0x150f0, 0x1a87c, // 10 + 0x15078, 0x1fad0, 0x15be0, 0x1adf8, 0x1fac8, 0x159f0, 0x1acfc, 0x1fac4, 0x158f8, 0x1ac7e, // 20 + 0x1fac2, 0x1587c, 0x1f5d0, 0x1faec, 0x15df8, 0x1f5c8, 0x1fae6, 0x15cfc, 0x1f5c4, 0x15c7e, // 30 + 0x1f5c2, 0x1ebd0, 0x1f5ec, 0x1ebc8, 0x1f5e6, 0x1ebc4, 0x1ebc2, 0x1d7d0, 0x1ebec, 0x1d7c8, // 40 + 0x1ebe6, 0x1d7c4, 0x1d7c2, 0x1afd0, 0x1d7ec, 0x1afc8, 0x1d7e6, 0x1afc4, 0x14bc0, 0x1a5f0, // 50 + 0x1d2fc, 0x149e0, 0x1a4f8, 0x1d27e, 0x148f0, 0x1a47c, 0x14878, 0x1a43e, 0x1483c, 0x1fa68, // 60 + 0x14df0, 0x1a6fc, 0x1fa64, 0x14cf8, 0x1a67e, 0x1fa62, 0x14c7c, 0x14c3e, 0x1f4e8, 0x1fa76, // 70 + 0x14efc, 0x1f4e4, 0x14e7e, 0x1f4e2, 0x1e9e8, 0x1f4f6, 0x1e9e4, 0x1e9e2, 0x1d3e8, 0x1e9f6, // 80 + 0x1d3e4, 0x1d3e2, 0x1a7e8, 0x1d3f6, 0x1a7e4, 0x1a7e2, 0x145e0, 0x1a2f8, 0x1d17e, 0x144f0, // 90 + 0x1a27c, 0x14478, 0x1a23e, 0x1443c, 0x1441e, 0x1fa34, 0x146f8, 0x1a37e, 0x1fa32, 0x1467c, // 100 + 0x1463e, 0x1f474, 0x1477e, 0x1f472, 0x1e8f4, 0x1e8f2, 0x1d1f4, 0x1d1f2, 0x1a3f4, 0x1a3f2, // 110 + 0x142f0, 0x1a17c, 0x14278, 0x1a13e, 0x1423c, 0x1421e, 0x1fa1a, 0x1437c, 0x1433e, 0x1f43a, // 120 + 0x1e87a, 0x1d0fa, 0x14178, 0x1a0be, 0x1413c, 0x1411e, 0x141be, 0x140bc, 0x1409e, 0x12bc0, // 130 + 0x195f0, 0x1cafc, 0x129e0, 0x194f8, 0x1ca7e, 0x128f0, 0x1947c, 0x12878, 0x1943e, 0x1283c, // 140 + 0x1f968, 0x12df0, 0x196fc, 0x1f964, 0x12cf8, 0x1967e, 0x1f962, 0x12c7c, 0x12c3e, 0x1f2e8, // 150 + 0x1f976, 0x12efc, 0x1f2e4, 0x12e7e, 0x1f2e2, 0x1e5e8, 0x1f2f6, 0x1e5e4, 0x1e5e2, 0x1cbe8, // 160 + 0x1e5f6, 0x1cbe4, 0x1cbe2, 0x197e8, 0x1cbf6, 0x197e4, 0x197e2, 0x1b5e0, 0x1daf8, 0x1ed7e, // 170 + 0x169c0, 0x1b4f0, 0x1da7c, 0x168e0, 0x1b478, 0x1da3e, 0x16870, 0x1b43c, 0x16838, 0x1b41e, // 180 + 0x1681c, 0x125e0, 0x192f8, 0x1c97e, 0x16de0, 0x124f0, 0x1927c, 0x16cf0, 0x1b67c, 0x1923e, // 190 + 0x16c78, 0x1243c, 0x16c3c, 0x1241e, 0x16c1e, 0x1f934, 0x126f8, 0x1937e, 0x1fb74, 0x1f932, // 200 + 0x16ef8, 0x1267c, 0x1fb72, 0x16e7c, 0x1263e, 0x16e3e, 0x1f274, 0x1277e, 0x1f6f4, 0x1f272, // 210 + 0x16f7e, 0x1f6f2, 0x1e4f4, 0x1edf4, 0x1e4f2, 0x1edf2, 0x1c9f4, 0x1dbf4, 0x1c9f2, 0x1dbf2, // 220 + 0x193f4, 0x193f2, 0x165c0, 0x1b2f0, 0x1d97c, 0x164e0, 0x1b278, 0x1d93e, 0x16470, 0x1b23c, // 230 + 0x16438, 0x1b21e, 0x1641c, 0x1640e, 0x122f0, 0x1917c, 0x166f0, 0x12278, 0x1913e, 0x16678, // 240 + 0x1b33e, 0x1663c, 0x1221e, 0x1661e, 0x1f91a, 0x1237c, 0x1fb3a, 0x1677c, 0x1233e, 0x1673e, // 250 + 0x1f23a, 0x1f67a, 0x1e47a, 0x1ecfa, 0x1c8fa, 0x1d9fa, 0x191fa, 0x162e0, 0x1b178, 0x1d8be, // 260 + 0x16270, 0x1b13c, 0x16238, 0x1b11e, 0x1621c, 0x1620e, 0x12178, 0x190be, 0x16378, 0x1213c, // 270 + 0x1633c, 0x1211e, 0x1631e, 0x121be, 0x163be, 0x16170, 0x1b0bc, 0x16138, 0x1b09e, 0x1611c, // 280 + 0x1610e, 0x120bc, 0x161bc, 0x1209e, 0x1619e, 0x160b8, 0x1b05e, 0x1609c, 0x1608e, 0x1205e, // 290 + 0x160de, 0x1605c, 0x1604e, 0x115e0, 0x18af8, 0x1c57e, 0x114f0, 0x18a7c, 0x11478, 0x18a3e, // 300 + 0x1143c, 0x1141e, 0x1f8b4, 0x116f8, 0x18b7e, 0x1f8b2, 0x1167c, 0x1163e, 0x1f174, 0x1177e, // 310 + 0x1f172, 0x1e2f4, 0x1e2f2, 0x1c5f4, 0x1c5f2, 0x18bf4, 0x18bf2, 0x135c0, 0x19af0, 0x1cd7c, // 320 + 0x134e0, 0x19a78, 0x1cd3e, 0x13470, 0x19a3c, 0x13438, 0x19a1e, 0x1341c, 0x1340e, 0x112f0, // 330 + 0x1897c, 0x136f0, 0x11278, 0x1893e, 0x13678, 0x19b3e, 0x1363c, 0x1121e, 0x1361e, 0x1f89a, // 340 + 0x1137c, 0x1f9ba, 0x1377c, 0x1133e, 0x1373e, 0x1f13a, 0x1f37a, 0x1e27a, 0x1e6fa, 0x1c4fa, // 350 + 0x1cdfa, 0x189fa, 0x1bae0, 0x1dd78, 0x1eebe, 0x174c0, 0x1ba70, 0x1dd3c, 0x17460, 0x1ba38, // 360 + 0x1dd1e, 0x17430, 0x1ba1c, 0x17418, 0x1ba0e, 0x1740c, 0x132e0, 0x19978, 0x1ccbe, 0x176e0, // 370 + 0x13270, 0x1993c, 0x17670, 0x1bb3c, 0x1991e, 0x17638, 0x1321c, 0x1761c, 0x1320e, 0x1760e, // 380 + 0x11178, 0x188be, 0x13378, 0x1113c, 0x17778, 0x1333c, 0x1111e, 0x1773c, 0x1331e, 0x1771e, // 390 + 0x111be, 0x133be, 0x177be, 0x172c0, 0x1b970, 0x1dcbc, 0x17260, 0x1b938, 0x1dc9e, 0x17230, // 400 + 0x1b91c, 0x17218, 0x1b90e, 0x1720c, 0x17206, 0x13170, 0x198bc, 0x17370, 0x13138, 0x1989e, // 410 + 0x17338, 0x1b99e, 0x1731c, 0x1310e, 0x1730e, 0x110bc, 0x131bc, 0x1109e, 0x173bc, 0x1319e, // 420 + 0x1739e, 0x17160, 0x1b8b8, 0x1dc5e, 0x17130, 0x1b89c, 0x17118, 0x1b88e, 0x1710c, 0x17106, // 430 + 0x130b8, 0x1985e, 0x171b8, 0x1309c, 0x1719c, 0x1308e, 0x1718e, 0x1105e, 0x130de, 0x171de, // 440 + 0x170b0, 0x1b85c, 0x17098, 0x1b84e, 0x1708c, 0x17086, 0x1305c, 0x170dc, 0x1304e, 0x170ce, // 450 + 0x17058, 0x1b82e, 0x1704c, 0x17046, 0x1302e, 0x1706e, 0x1702c, 0x17026, 0x10af0, 0x1857c, // 460 + 0x10a78, 0x1853e, 0x10a3c, 0x10a1e, 0x10b7c, 0x10b3e, 0x1f0ba, 0x1e17a, 0x1c2fa, 0x185fa, // 470 + 0x11ae0, 0x18d78, 0x1c6be, 0x11a70, 0x18d3c, 0x11a38, 0x18d1e, 0x11a1c, 0x11a0e, 0x10978, // 480 + 0x184be, 0x11b78, 0x1093c, 0x11b3c, 0x1091e, 0x11b1e, 0x109be, 0x11bbe, 0x13ac0, 0x19d70, // 490 + 0x1cebc, 0x13a60, 0x19d38, 0x1ce9e, 0x13a30, 0x19d1c, 0x13a18, 0x19d0e, 0x13a0c, 0x13a06, // 500 + 0x11970, 0x18cbc, 0x13b70, 0x11938, 0x18c9e, 0x13b38, 0x1191c, 0x13b1c, 0x1190e, 0x13b0e, // 510 + 0x108bc, 0x119bc, 0x1089e, 0x13bbc, 0x1199e, 0x13b9e, 0x1bd60, 0x1deb8, 0x1ef5e, 0x17a40, // 520 + 0x1bd30, 0x1de9c, 0x17a20, 0x1bd18, 0x1de8e, 0x17a10, 0x1bd0c, 0x17a08, 0x1bd06, 0x17a04, // 530 + 0x13960, 0x19cb8, 0x1ce5e, 0x17b60, 0x13930, 0x19c9c, 0x17b30, 0x1bd9c, 0x19c8e, 0x17b18, // 540 + 0x1390c, 0x17b0c, 0x13906, 0x17b06, 0x118b8, 0x18c5e, 0x139b8, 0x1189c, 0x17bb8, 0x1399c, // 550 + 0x1188e, 0x17b9c, 0x1398e, 0x17b8e, 0x1085e, 0x118de, 0x139de, 0x17bde, 0x17940, 0x1bcb0, // 560 + 0x1de5c, 0x17920, 0x1bc98, 0x1de4e, 0x17910, 0x1bc8c, 0x17908, 0x1bc86, 0x17904, 0x17902, // 570 + 0x138b0, 0x19c5c, 0x179b0, 0x13898, 0x19c4e, 0x17998, 0x1bcce, 0x1798c, 0x13886, 0x17986, // 580 + 0x1185c, 0x138dc, 0x1184e, 0x179dc, 0x138ce, 0x179ce, 0x178a0, 0x1bc58, 0x1de2e, 0x17890, // 590 + 0x1bc4c, 0x17888, 0x1bc46, 0x17884, 0x17882, 0x13858, 0x19c2e, 0x178d8, 0x1384c, 0x178cc, // 600 + 0x13846, 0x178c6, 0x1182e, 0x1386e, 0x178ee, 0x17850, 0x1bc2c, 0x17848, 0x1bc26, 0x17844, // 610 + 0x17842, 0x1382c, 0x1786c, 0x13826, 0x17866, 0x17828, 0x1bc16, 0x17824, 0x17822, 0x13816, // 620 + 0x17836, 0x10578, 0x182be, 0x1053c, 0x1051e, 0x105be, 0x10d70, 0x186bc, 0x10d38, 0x1869e, // 630 + 0x10d1c, 0x10d0e, 0x104bc, 0x10dbc, 0x1049e, 0x10d9e, 0x11d60, 0x18eb8, 0x1c75e, 0x11d30, // 640 + 0x18e9c, 0x11d18, 0x18e8e, 0x11d0c, 0x11d06, 0x10cb8, 0x1865e, 0x11db8, 0x10c9c, 0x11d9c, // 650 + 0x10c8e, 0x11d8e, 0x1045e, 0x10cde, 0x11dde, 0x13d40, 0x19eb0, 0x1cf5c, 0x13d20, 0x19e98, // 660 + 0x1cf4e, 0x13d10, 0x19e8c, 0x13d08, 0x19e86, 0x13d04, 0x13d02, 0x11cb0, 0x18e5c, 0x13db0, // 670 + 0x11c98, 0x18e4e, 0x13d98, 0x19ece, 0x13d8c, 0x11c86, 0x13d86, 0x10c5c, 0x11cdc, 0x10c4e, // 680 + 0x13ddc, 0x11cce, 0x13dce, 0x1bea0, 0x1df58, 0x1efae, 0x1be90, 0x1df4c, 0x1be88, 0x1df46, // 690 + 0x1be84, 0x1be82, 0x13ca0, 0x19e58, 0x1cf2e, 0x17da0, 0x13c90, 0x19e4c, 0x17d90, 0x1becc, // 700 + 0x19e46, 0x17d88, 0x13c84, 0x17d84, 0x13c82, 0x17d82, 0x11c58, 0x18e2e, 0x13cd8, 0x11c4c, // 710 + 0x17dd8, 0x13ccc, 0x11c46, 0x17dcc, 0x13cc6, 0x17dc6, 0x10c2e, 0x11c6e, 0x13cee, 0x17dee, // 720 + 0x1be50, 0x1df2c, 0x1be48, 0x1df26, 0x1be44, 0x1be42, 0x13c50, 0x19e2c, 0x17cd0, 0x13c48, // 730 + 0x19e26, 0x17cc8, 0x1be66, 0x17cc4, 0x13c42, 0x17cc2, 0x11c2c, 0x13c6c, 0x11c26, 0x17cec, // 740 + 0x13c66, 0x17ce6, 0x1be28, 0x1df16, 0x1be24, 0x1be22, 0x13c28, 0x19e16, 0x17c68, 0x13c24, // 750 + 0x17c64, 0x13c22, 0x17c62, 0x11c16, 0x13c36, 0x17c76, 0x1be14, 0x1be12, 0x13c14, 0x17c34, // 760 + 0x13c12, 0x17c32, 0x102bc, 0x1029e, 0x106b8, 0x1835e, 0x1069c, 0x1068e, 0x1025e, 0x106de, // 770 + 0x10eb0, 0x1875c, 0x10e98, 0x1874e, 0x10e8c, 0x10e86, 0x1065c, 0x10edc, 0x1064e, 0x10ece, // 780 + 0x11ea0, 0x18f58, 0x1c7ae, 0x11e90, 0x18f4c, 0x11e88, 0x18f46, 0x11e84, 0x11e82, 0x10e58, // 790 + 0x1872e, 0x11ed8, 0x18f6e, 0x11ecc, 0x10e46, 0x11ec6, 0x1062e, 0x10e6e, 0x11eee, 0x19f50, // 800 + 0x1cfac, 0x19f48, 0x1cfa6, 0x19f44, 0x19f42, 0x11e50, 0x18f2c, 0x13ed0, 0x19f6c, 0x18f26, // 810 + 0x13ec8, 0x11e44, 0x13ec4, 0x11e42, 0x13ec2, 0x10e2c, 0x11e6c, 0x10e26, 0x13eec, 0x11e66, // 820 + 0x13ee6, 0x1dfa8, 0x1efd6, 0x1dfa4, 0x1dfa2, 0x19f28, 0x1cf96, 0x1bf68, 0x19f24, 0x1bf64, // 830 + 0x19f22, 0x1bf62, 0x11e28, 0x18f16, 0x13e68, 0x11e24, 0x17ee8, 0x13e64, 0x11e22, 0x17ee4, // 840 + 0x13e62, 0x17ee2, 0x10e16, 0x11e36, 0x13e76, 0x17ef6, 0x1df94, 0x1df92, 0x19f14, 0x1bf34, // 850 + 0x19f12, 0x1bf32, 0x11e14, 0x13e34, 0x11e12, 0x17e74, 0x13e32, 0x17e72, 0x1df8a, 0x19f0a, // 860 + 0x1bf1a, 0x11e0a, 0x13e1a, 0x17e3a, 0x1035c, 0x1034e, 0x10758, 0x183ae, 0x1074c, 0x10746, // 870 + 0x1032e, 0x1076e, 0x10f50, 0x187ac, 0x10f48, 0x187a6, 0x10f44, 0x10f42, 0x1072c, 0x10f6c, // 880 + 0x10726, 0x10f66, 0x18fa8, 0x1c7d6, 0x18fa4, 0x18fa2, 0x10f28, 0x18796, 0x11f68, 0x18fb6, // 890 + 0x11f64, 0x10f22, 0x11f62, 0x10716, 0x10f36, 0x11f76, 0x1cfd4, 0x1cfd2, 0x18f94, 0x19fb4, // 900 + 0x18f92, 0x19fb2, 0x10f14, 0x11f34, 0x10f12, 0x13f74, 0x11f32, 0x13f72, 0x1cfca, 0x18f8a, // 910 + 0x19f9a, 0x10f0a, 0x11f1a, 0x13f3a, 0x103ac, 0x103a6, 0x107a8, 0x183d6, 0x107a4, 0x107a2, // 920 + 0x10396, 0x107b6, 0x187d4, 0x187d2, 0x10794, 0x10fb4, 0x10792, 0x10fb2, 0x1c7ea]]; // 929 + + /** + * Array of factors of the Reed-Solomon polynomial equations used for error correction; + * one sub array for each correction level (0-8). + */ + const RSFACTORS = [[ // ECL 0 (2 factors) ------------------------------------------------------------------------------------ + 0x01b, 0x395], // 2 + [ // ECL 1 (4 factors) ------------------------------------------------------------------------------------ + 0x20a, 0x238, 0x2d3, 0x329], // 4 + [ // ECL 2 (8 factors) ------------------------------------------------------------------------------------ + 0x0ed, 0x134, 0x1b4, 0x11c, 0x286, 0x28d, 0x1ac, 0x17b], // 8 + [ // ECL 3 (16 factors) ----------------------------------------------------------------------------------- + 0x112, 0x232, 0x0e8, 0x2f3, 0x257, 0x20c, 0x321, 0x084, 0x127, 0x074, 0x1ba, 0x1ac, 0x127, 0x02a, 0x0b0, 0x041], // 16 + [ // ECL 4 (32 factors) ----------------------------------------------------------------------------------- + 0x169, 0x23f, 0x39a, 0x20d, 0x0b0, 0x24a, 0x280, 0x141, 0x218, 0x2e6, 0x2a5, 0x2e6, 0x2af, 0x11c, 0x0c1, 0x205, // 16 + 0x111, 0x1ee, 0x107, 0x093, 0x251, 0x320, 0x23b, 0x140, 0x323, 0x085, 0x0e7, 0x186, 0x2ad, 0x14a, 0x03f, 0x19a], // 32 + [ // ECL 5 (64 factors) ----------------------------------------------------------------------------------- + 0x21b, 0x1a6, 0x006, 0x05d, 0x35e, 0x303, 0x1c5, 0x06a, 0x262, 0x11f, 0x06b, 0x1f9, 0x2dd, 0x36d, 0x17d, 0x264, // 16 + 0x2d3, 0x1dc, 0x1ce, 0x0ac, 0x1ae, 0x261, 0x35a, 0x336, 0x21f, 0x178, 0x1ff, 0x190, 0x2a0, 0x2fa, 0x11b, 0x0b8, // 32 + 0x1b8, 0x023, 0x207, 0x01f, 0x1cc, 0x252, 0x0e1, 0x217, 0x205, 0x160, 0x25d, 0x09e, 0x28b, 0x0c9, 0x1e8, 0x1f6, // 48 + 0x288, 0x2dd, 0x2cd, 0x053, 0x194, 0x061, 0x118, 0x303, 0x348, 0x275, 0x004, 0x17d, 0x34b, 0x26f, 0x108, 0x21f], // 64 + [ // ECL 6 (128 factors) ---------------------------------------------------------------------------------- + 0x209, 0x136, 0x360, 0x223, 0x35a, 0x244, 0x128, 0x17b, 0x035, 0x30b, 0x381, 0x1bc, 0x190, 0x39d, 0x2ed, 0x19f, // 16 + 0x336, 0x05d, 0x0d9, 0x0d0, 0x3a0, 0x0f4, 0x247, 0x26c, 0x0f6, 0x094, 0x1bf, 0x277, 0x124, 0x38c, 0x1ea, 0x2c0, // 32 + 0x204, 0x102, 0x1c9, 0x38b, 0x252, 0x2d3, 0x2a2, 0x124, 0x110, 0x060, 0x2ac, 0x1b0, 0x2ae, 0x25e, 0x35c, 0x239, // 48 + 0x0c1, 0x0db, 0x081, 0x0ba, 0x0ec, 0x11f, 0x0c0, 0x307, 0x116, 0x0ad, 0x028, 0x17b, 0x2c8, 0x1cf, 0x286, 0x308, // 64 + 0x0ab, 0x1eb, 0x129, 0x2fb, 0x09c, 0x2dc, 0x05f, 0x10e, 0x1bf, 0x05a, 0x1fb, 0x030, 0x0e4, 0x335, 0x328, 0x382, // 80 + 0x310, 0x297, 0x273, 0x17a, 0x17e, 0x106, 0x17c, 0x25a, 0x2f2, 0x150, 0x059, 0x266, 0x057, 0x1b0, 0x29e, 0x268, // 96 + 0x09d, 0x176, 0x0f2, 0x2d6, 0x258, 0x10d, 0x177, 0x382, 0x34d, 0x1c6, 0x162, 0x082, 0x32e, 0x24b, 0x324, 0x022, // 112 + 0x0d3, 0x14a, 0x21b, 0x129, 0x33b, 0x361, 0x025, 0x205, 0x342, 0x13b, 0x226, 0x056, 0x321, 0x004, 0x06c, 0x21b], // 128 + [ // ECL 7 (256 factors) ---------------------------------------------------------------------------------- + 0x20c, 0x37e, 0x04b, 0x2fe, 0x372, 0x359, 0x04a, 0x0cc, 0x052, 0x24a, 0x2c4, 0x0fa, 0x389, 0x312, 0x08a, 0x2d0, // 16 + 0x35a, 0x0c2, 0x137, 0x391, 0x113, 0x0be, 0x177, 0x352, 0x1b6, 0x2dd, 0x0c2, 0x118, 0x0c9, 0x118, 0x33c, 0x2f5, // 32 + 0x2c6, 0x32e, 0x397, 0x059, 0x044, 0x239, 0x00b, 0x0cc, 0x31c, 0x25d, 0x21c, 0x391, 0x321, 0x2bc, 0x31f, 0x089, // 48 + 0x1b7, 0x1a2, 0x250, 0x29c, 0x161, 0x35b, 0x172, 0x2b6, 0x145, 0x0f0, 0x0d8, 0x101, 0x11c, 0x225, 0x0d1, 0x374, // 64 + 0x13b, 0x046, 0x149, 0x319, 0x1ea, 0x112, 0x36d, 0x0a2, 0x2ed, 0x32c, 0x2ac, 0x1cd, 0x14e, 0x178, 0x351, 0x209, // 80 + 0x133, 0x123, 0x323, 0x2c8, 0x013, 0x166, 0x18f, 0x38c, 0x067, 0x1ff, 0x033, 0x008, 0x205, 0x0e1, 0x121, 0x1d6, // 96 + 0x27d, 0x2db, 0x042, 0x0ff, 0x395, 0x10d, 0x1cf, 0x33e, 0x2da, 0x1b1, 0x350, 0x249, 0x088, 0x21a, 0x38a, 0x05a, // 112 + 0x002, 0x122, 0x2e7, 0x0c7, 0x28f, 0x387, 0x149, 0x031, 0x322, 0x244, 0x163, 0x24c, 0x0bc, 0x1ce, 0x00a, 0x086, // 128 + 0x274, 0x140, 0x1df, 0x082, 0x2e3, 0x047, 0x107, 0x13e, 0x176, 0x259, 0x0c0, 0x25d, 0x08e, 0x2a1, 0x2af, 0x0ea, // 144 + 0x2d2, 0x180, 0x0b1, 0x2f0, 0x25f, 0x280, 0x1c7, 0x0c1, 0x2b1, 0x2c3, 0x325, 0x281, 0x030, 0x03c, 0x2dc, 0x26d, // 160 + 0x37f, 0x220, 0x105, 0x354, 0x28f, 0x135, 0x2b9, 0x2f3, 0x2f4, 0x03c, 0x0e7, 0x305, 0x1b2, 0x1a5, 0x2d6, 0x210, // 176 + 0x1f7, 0x076, 0x031, 0x31b, 0x020, 0x090, 0x1f4, 0x0ee, 0x344, 0x18a, 0x118, 0x236, 0x13f, 0x009, 0x287, 0x226, // 192 + 0x049, 0x392, 0x156, 0x07e, 0x020, 0x2a9, 0x14b, 0x318, 0x26c, 0x03c, 0x261, 0x1b9, 0x0b4, 0x317, 0x37d, 0x2f2, // 208 + 0x25d, 0x17f, 0x0e4, 0x2ed, 0x2f8, 0x0d5, 0x036, 0x129, 0x086, 0x036, 0x342, 0x12b, 0x39a, 0x0bf, 0x38e, 0x214, // 224 + 0x261, 0x33d, 0x0bd, 0x014, 0x0a7, 0x01d, 0x368, 0x1c1, 0x053, 0x192, 0x029, 0x290, 0x1f9, 0x243, 0x1e1, 0x0ad, // 240 + 0x194, 0x0fb, 0x2b0, 0x05f, 0x1f1, 0x22b, 0x282, 0x21f, 0x133, 0x09f, 0x39c, 0x22e, 0x288, 0x037, 0x1f1, 0x00a], // 256 + [ // ECL 8 (512 factors) ---------------------------------------------------------------------------------- + 0x160, 0x04d, 0x175, 0x1f8, 0x023, 0x257, 0x1ac, 0x0cf, 0x199, 0x23e, 0x076, 0x1f2, 0x11d, 0x17c, 0x15e, 0x1ec, // 16 + 0x0c5, 0x109, 0x398, 0x09b, 0x392, 0x12b, 0x0e5, 0x283, 0x126, 0x367, 0x132, 0x058, 0x057, 0x0c1, 0x160, 0x30d, // 32 + 0x34e, 0x04b, 0x147, 0x208, 0x1b3, 0x21f, 0x0cb, 0x29a, 0x0f9, 0x15a, 0x30d, 0x26d, 0x280, 0x10c, 0x31a, 0x216, // 48 + 0x21b, 0x30d, 0x198, 0x186, 0x284, 0x066, 0x1dc, 0x1f3, 0x122, 0x278, 0x221, 0x025, 0x35a, 0x394, 0x228, 0x029, // 64 + 0x21e, 0x121, 0x07a, 0x110, 0x17f, 0x320, 0x1e5, 0x062, 0x2f0, 0x1d8, 0x2f9, 0x06b, 0x310, 0x35c, 0x292, 0x2e5, // 80 + 0x122, 0x0cc, 0x2a9, 0x197, 0x357, 0x055, 0x063, 0x03e, 0x1e2, 0x0b4, 0x014, 0x129, 0x1c3, 0x251, 0x391, 0x08e, // 96 + 0x328, 0x2ac, 0x11f, 0x218, 0x231, 0x04c, 0x28d, 0x383, 0x2d9, 0x237, 0x2e8, 0x186, 0x201, 0x0c0, 0x204, 0x102, // 112 + 0x0f0, 0x206, 0x31a, 0x18b, 0x300, 0x350, 0x033, 0x262, 0x180, 0x0a8, 0x0be, 0x33a, 0x148, 0x254, 0x312, 0x12f, // 128 + 0x23a, 0x17d, 0x19f, 0x281, 0x09c, 0x0ed, 0x097, 0x1ad, 0x213, 0x0cf, 0x2a4, 0x2c6, 0x059, 0x0a8, 0x130, 0x192, // 144 + 0x028, 0x2c4, 0x23f, 0x0a2, 0x360, 0x0e5, 0x041, 0x35d, 0x349, 0x200, 0x0a4, 0x1dd, 0x0dd, 0x05c, 0x166, 0x311, // 160 + 0x120, 0x165, 0x352, 0x344, 0x33b, 0x2e0, 0x2c3, 0x05e, 0x008, 0x1ee, 0x072, 0x209, 0x002, 0x1f3, 0x353, 0x21f, // 176 + 0x098, 0x2d9, 0x303, 0x05f, 0x0f8, 0x169, 0x242, 0x143, 0x358, 0x31d, 0x121, 0x033, 0x2ac, 0x1d2, 0x215, 0x334, // 192 + 0x29d, 0x02d, 0x386, 0x1c4, 0x0a7, 0x156, 0x0f4, 0x0ad, 0x023, 0x1cf, 0x28b, 0x033, 0x2bb, 0x24f, 0x1c4, 0x242, // 208 + 0x025, 0x07c, 0x12a, 0x14c, 0x228, 0x02b, 0x1ab, 0x077, 0x296, 0x309, 0x1db, 0x352, 0x2fc, 0x16c, 0x242, 0x38f, // 224 + 0x11b, 0x2c7, 0x1d8, 0x1a4, 0x0f5, 0x120, 0x252, 0x18a, 0x1ff, 0x147, 0x24d, 0x309, 0x2bb, 0x2b0, 0x02b, 0x198, // 240 + 0x34a, 0x17f, 0x2d1, 0x209, 0x230, 0x284, 0x2ca, 0x22f, 0x03e, 0x091, 0x369, 0x297, 0x2c9, 0x09f, 0x2a0, 0x2d9, // 256 + 0x270, 0x03b, 0x0c1, 0x1a1, 0x09e, 0x0d1, 0x233, 0x234, 0x157, 0x2b5, 0x06d, 0x260, 0x233, 0x16d, 0x0b5, 0x304, // 272 + 0x2a5, 0x136, 0x0f8, 0x161, 0x2c4, 0x19a, 0x243, 0x366, 0x269, 0x349, 0x278, 0x35c, 0x121, 0x218, 0x023, 0x309, // 288 + 0x26a, 0x24a, 0x1a8, 0x341, 0x04d, 0x255, 0x15a, 0x10d, 0x2f5, 0x278, 0x2b7, 0x2ef, 0x14b, 0x0f7, 0x0b8, 0x02d, // 304 + 0x313, 0x2a8, 0x012, 0x042, 0x197, 0x171, 0x036, 0x1ec, 0x0e4, 0x265, 0x33e, 0x39a, 0x1b5, 0x207, 0x284, 0x389, // 320 + 0x315, 0x1a4, 0x131, 0x1b9, 0x0cf, 0x12c, 0x37c, 0x33b, 0x08d, 0x219, 0x17d, 0x296, 0x201, 0x038, 0x0fc, 0x155, // 336 + 0x0f2, 0x31d, 0x346, 0x345, 0x2d0, 0x0e0, 0x133, 0x277, 0x03d, 0x057, 0x230, 0x136, 0x2f4, 0x299, 0x18d, 0x328, // 352 + 0x353, 0x135, 0x1d9, 0x31b, 0x17a, 0x01f, 0x287, 0x393, 0x1cb, 0x326, 0x24e, 0x2db, 0x1a9, 0x0d8, 0x224, 0x0f9, // 368 + 0x141, 0x371, 0x2bb, 0x217, 0x2a1, 0x30e, 0x0d2, 0x32f, 0x389, 0x12f, 0x34b, 0x39a, 0x119, 0x049, 0x1d5, 0x317, // 384 + 0x294, 0x0a2, 0x1f2, 0x134, 0x09b, 0x1a6, 0x38b, 0x331, 0x0bb, 0x03e, 0x010, 0x1a9, 0x217, 0x150, 0x11e, 0x1b5, // 400 + 0x177, 0x111, 0x262, 0x128, 0x0b7, 0x39b, 0x074, 0x29b, 0x2ef, 0x161, 0x03e, 0x16e, 0x2b3, 0x17b, 0x2af, 0x34a, // 416 + 0x025, 0x165, 0x2d0, 0x2e6, 0x14a, 0x005, 0x027, 0x39b, 0x137, 0x1a8, 0x0f2, 0x2ed, 0x141, 0x036, 0x29d, 0x13c, // 432 + 0x156, 0x12b, 0x216, 0x069, 0x29b, 0x1e8, 0x280, 0x2a0, 0x240, 0x21c, 0x13c, 0x1e6, 0x2d1, 0x262, 0x02e, 0x290, // 448 + 0x1bf, 0x0ab, 0x268, 0x1d0, 0x0be, 0x213, 0x129, 0x141, 0x2fa, 0x2f0, 0x215, 0x0af, 0x086, 0x00e, 0x17d, 0x1b1, // 464 + 0x2cd, 0x02d, 0x06f, 0x014, 0x254, 0x11c, 0x2e0, 0x08a, 0x286, 0x19b, 0x36d, 0x29d, 0x08d, 0x397, 0x02d, 0x30c, // 480 + 0x197, 0x0a4, 0x14c, 0x383, 0x0a5, 0x2d6, 0x258, 0x145, 0x1f2, 0x28f, 0x165, 0x2f0, 0x300, 0x0df, 0x351, 0x287, // 496 + 0x03f, 0x136, 0x35f, 0x0fb, 0x16e, 0x130, 0x11a, 0x2e2, 0x2a3, 0x19a, 0x185, 0x0f4, 0x01f, 0x079, 0x12f, 0x107]]; // 512 + /*= =================================================================================================================================================* + | PDF417 BARCODE HELPER FUNCTIONS | + *================================================================================================================================================== */ + const _get_input_sequences = function (code) { + const sequence_array = []; // array to be returned + let numseq = []; + // get numeric sequences + numseq = code.match(/([0-9]{13,44})/g); + if (numseq == null) { + numseq = []; + } else { + // add offset to each matched line + for (var n = 0; n < numseq.length; n++) { + var offset = code.indexOf(numseq[n]); + numseq[n] = [numseq[n], offset]; + } + } + numseq.push(['', code.length]); + var offset = 0; + for (let i = 0; i < numseq.length; i++) { + const seq = numseq[i]; + const seqlen = seq[0].length; + if (seq[1] > 0) { + // extract text sequence before the number sequence + const prevseq = code.substr(offset, (seq[1] - offset)); + let textseq = []; + // get text sequences + textseq = prevseq.match(/([\x09\x0a\x0d\x20-\x7e]{5,})/g); + if (textseq == null) { + textseq = []; + } else { + // add offset to each matched line + for (var n = 0; n < textseq.length; n++) { + var offset = prevseq.indexOf(textseq[n]); + textseq[n] = [textseq[n], offset]; + } + } + textseq.push(['', prevseq.length]); + let txtoffset = 0; + for (let j = 0; j < textseq.length; j++) { + const txtseq = textseq[j]; + const txtseqlen = txtseq[0].length; + if (txtseq[1] > 0) { + // extract byte sequence before the text sequence + const prevtxtseq = prevseq.substr(txtoffset, (txtseq[1] - txtoffset)); + if (prevtxtseq.length > 0) { + // add BYTE sequence + if ((prevtxtseq.length == 1) && (sequence_array.length > 0) && (sequence_array[sequence_array.length - 1][0] == 900)) { + sequence_array.push([913, prevtxtseq]); + } else if ((prevtxtseq.length % 6) == 0) { + sequence_array.push([924, prevtxtseq]); + } else { + sequence_array.push([901, prevtxtseq]); + } + } + } + if (txtseqlen > 0) { + // add numeric sequence + sequence_array.push([900, txtseq[0]]); + } + txtoffset = txtseq[1] + txtseqlen; + } + } + if (seqlen > 0) { + // add numeric sequence + sequence_array.push([902, seq[0]]); + } + offset = seq[1] + seqlen; + } + return sequence_array; + }; + + /*= ============================================================================================================================================= */ + + const _get_compaction = function (mode, code, addmode) { + addmode = addmode || true; + const cw = []; // array of codewords to return + switch (mode) { + case 900: { // Text Compaction mode latch + let submode = 0; // default Alpha sub-mode + let txtarr = []; // array of characters and sub-mode switching characters + var codelen = code.length; + for (var i = 0; i < codelen; ++i) { + const chval = _ord(code.charAt(i)); + var k; + if ((k = _array_search(chval, TEXT_SUBMODES[submode])) !== false) { + // we are on the same sub-mode + txtarr.push(k); + } else { + // the sub-mode is changed + for (let s = 0; s < 4; ++s) { + // search new sub-mode + if ((s != submode) && ((k = _array_search(chval, TEXT_SUBMODES[s])) !== false)) { + // s is the new submode + if ((((i + 1) == codelen) || (((i + 1) < codelen) && (_array_search(_ord(code.charAt(i + 1)), TEXT_SUBMODES[submode]) !== false))) && ((s == 3) || ((s == 0) && (submode == 1)))) { + // shift (temporary change only for this char) + if (s == 3) { + // shift to puntuaction + txtarr.push(29); + } else { + // shift from lower to alpha + txtarr.push(27); + } + } else { + // latch + txtarr = txtarr.concat(TEXT_LATCH[`${submode}${s}`]); + // set new submode + submode = s; + } + // add characted code to array + txtarr.push(k); + break; + } + } + } + } + let txtarrlen = txtarr.length; + if ((txtarrlen % 2) != 0) { + // add padding + txtarr.push(29); + ++txtarrlen; + } + // calculate codewords + for (var i = 0; i < txtarrlen; i += 2) { + cw.push((30 * parseInt(txtarr[i])) + parseInt(txtarr[(i + 1)])); + } + break; + } + case 901: + case 924: { // Byte Compaction mode latch + var rest; + let sublen; + var codelen; + while ((codelen = code.length) > 0) { + if (codelen > 6) { + rest = code.substring(6); + code = code.substring(0, 6); + sublen = 6; + } else { + rest = ''; + sublen = code.length; + } + if (sublen == 6) { + var t = bcmul(`${_ord(code.charAt(0))}`, '1099511627776'); + t = bcadd(t, bcmul(`${_ord(code.charAt(1))}`, '4294967296')); + t = bcadd(t, bcmul(`${_ord(code.charAt(2))}`, '16777216')); + t = bcadd(t, bcmul(`${_ord(code.charAt(3))}`, '65536')); + t = bcadd(t, bcmul(`${_ord(code.charAt(4))}`, '256')); + t = bcadd(t, `${_ord(code.charAt(5))}`); + do { + var d = _my_bcmod(t, '900'); + t = bcdiv(t, '900'); + cw.unshift(d); + } while (t != '0'); + } else { + for (var i = 0; i < sublen; ++i) { + cw.push(_ord(code.charAt(i))); + } + } + code = rest; + } + break; + } + case 902: { // Numeric Compaction mode latch + var rest; + var codelen; + while ((codelen = code.length) > 0) { + if (codelen > 44) { + rest = code.substring(44); + code = code.substring(0, 44); + } else { + rest = ''; + } + var t = `1${code}`; + do { + var d = _my_bcmod(t, '900'); + t = bcdiv(t, '900'); + cw.unshift(d); + } while (t != '0'); + code = rest; + } + break; + } + case 913: { // Byte Compaction mode shift + cw.push(_ord(code)); + break; + } + } + if (addmode) { + // add the compaction mode codeword at the beginning + cw.unshift(mode); + } + return cw; + }; + + /*= ============================================================================================================================================= */ + + var _ord = function (string) { + return string.charCodeAt(0); + }; + + /*= ============================================================================================================================================= */ + + const _get_error_correction_level = function (ecl, numcw) { + // get maximum correction level + let maxecl = 8; // starting error level + const maxerrsize = (928 - numcw); // available codewords for error + while (maxecl > 0) { + const errsize = (2 << ecl); + if (maxerrsize >= errsize) { + break; + } + --maxecl; + } + // check for automatic levels + if ((ecl < 0) || (ecl > 8)) { + if (numcw < 41) { + ecl = 2; + } else if (numcw < 161) { + ecl = 3; + } else if (numcw < 321) { + ecl = 4; + } else if (numcw < 864) { + ecl = 5; + } else { + ecl = maxecl; + } + } + if (ecl > maxecl) { + ecl = maxecl; + } + return ecl; + }; + + /*= ============================================================================================================================================= */ + + const _get_error_correction_word = function (cw, ecl) { + // get error correction coefficients + const ecc = RSFACTORS[ecl]; + // number of error correction factors + const eclsize = (2 << ecl); + // maximum index for RSFACTORS[ecl] + const eclmaxid = (eclsize - 1); + // initialize array of error correction codewords + let ecw = _array_fill(0, eclsize, 0); + // for each data codeword + for (let k = 0; k < cw.length; k++) { + const t1 = (cw[k] + ecw[eclmaxid]) % 929; + for (var j = eclmaxid; j > 0; --j) { + var t2 = (t1 * ecc[j]) % 929; + var t3 = 929 - t2; + ecw[j] = (ecw[(j - 1)] + t3) % 929; + } + t2 = (t1 * ecc[0]) % 929; + t3 = 929 - t2; + ecw[0] = t3 % 929; + } + for (var j = 0; j < ecw.length; j++) { + if (ecw[j] != 0) { + ecw[j] = 929 - ecw[j]; + } + } + ecw = ecw.reverse(); + return ecw; + }; + + /*= ============================================================================================================================================= */ + + var _array_fill = function (start_index, num, mixed_val) { + let key, + tmp_arr = {}; + + if (start_index == 0) { + const tmpArray = []; + for (let i = 0; i < num; i++) { + tmpArray.push(mixed_val); + } + return tmpArray; + } + + if (!isNaN(start_index) && !isNaN(num)) { + for (key = 0; key < num; key++) { + tmp_arr[(key + start_index)] = mixed_val; + } + } + + return tmp_arr; + }; + + /*= ============================================================================================================================================= */ + + const _intval = function (mixed_var, base) { + // http://kevin.vanzonneveld.net + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: stensi + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Matteo + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Rafał Kukawski (http://kukawski.pl) + // * example 1: intval('Kevin van Zonneveld'); + // * returns 1: 0 + // * example 2: intval(4.2); + // * returns 2: 4 + // * example 3: intval(42, 8); + // * returns 3: 42 + // * example 4: intval('09'); + // * returns 4: 9 + // * example 5: intval('1e', 16); + // * returns 5: 30 + let tmp; + + const type = typeof (mixed_var); + + if (type === 'boolean') { + return +mixed_var; + } else if (type === 'string') { + tmp = parseInt(mixed_var, base || 10); + return (isNaN(tmp) || !isFinite(tmp)) ? 0 : tmp; + } else if (type === 'number' && isFinite(mixed_var)) { + return mixed_var | 0; + } + return 0; + + }; + + /*= ============================================================================================================================================= */ + + const _binary17 = function (number) { + const padded = `00000000000000000${new Number(number).toString(2)}`; + return padded.substring(padded.length - 17); + }; + + /*= ============================================================================================================================================= */ + + var _array_search = function (needle, haystack, argStrict) { + // http://kevin.vanzonneveld.net + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: array_search('zonneveld', {firstname: 'kevin', middle: 'van', surname: 'zonneveld'}); + // * returns 1: 'surname' + // * example 2: ini_set('phpjs.return_phpjs_arrays', 'on'); + // * example 2: var ordered_arr = array({3:'value'}, {2:'value'}, {'a':'value'}, {'b':'value'}); + // * example 2: var key = array_search(/val/g, ordered_arr); // or var key = ordered_arr.search(/val/g); + // * returns 2: '3' + + let strict = !!argStrict, + key = ''; + + if (haystack && typeof haystack === 'object' && haystack.change_key_case) { // Duck-type check for our own array()-created PHPJS_Array + return haystack.search(needle, argStrict); + } + if (typeof needle === 'object' && needle.exec) { // Duck-type for RegExp + if (!strict) { // Let's consider case sensitive searches as strict + const flags = `i${needle.global ? 'g' : '' + }${needle.multiline ? 'm' : '' + }${needle.sticky ? 'y' : ''}`; // sticky is FF only + needle = new RegExp(needle.source, flags); + } + for (key in haystack) { + if (needle.test(haystack[key])) { + return key; + } + } + return false; + } + + for (key in haystack) { + if ((strict && haystack[key] === needle) || (!strict && haystack[key] == needle)) { + return key; + } + } + + return false; + }; + + /*= ============================================================================================================================================= */ + + var _my_bcmod = function (x, y) { + // how many numbers to take at once? carefull not to exceed (int) + const take = 5; + let mod = ''; + do { + const a = parseInt(`${mod}${x.substring(0, take)}`); + x = x.substring(take); + mod = a % y; + } + while (x.length); + + return parseInt(mod); + }; + /*= =================================================================================================================================================* + | PDF417 BARCODE CREATION FUNCTION | + *================================================================================================================================================== */ + /* + * code (string) code to represent using PDF417 + * param.ecl (int) error correction level (0-8); default -1 = automatic correction level + * param.aspectratio (float) the width to height of the symbol + */ + const pdf417_create = function (code, parameters) { + let _ecl = -1; + let _aspect_ratio = 2; + if (parameters != null) { + _ecl = Number(parameters.errorCorrectionLevel) || -1; + _aspect_ratio = Number(parameters.aspectRatio) || 2; + } + + code = unescape(encodeURIComponent(code)); // covert UTF-8 to ISO-8859-1 + if (code === '') return false; + + // get the input sequence array + const sequence = _get_input_sequences(code); + let codewords = []; // array of code-words + for (let i = 0; i < sequence.length; i++) { + const cw = _get_compaction(sequence[i][0], sequence[i][1], true); + codewords = codewords.concat(cw); + } + if (codewords[0] == 900) { + // Text Alpha is the default mode, so remove the first code + codewords.shift(); + } + // count number of codewords + const numcw = codewords.length; + if (numcw > 925) { + // reached maximum data codeword capacity + return false; + } + + // set error correction level + const ecl = _get_error_correction_level(_ecl, numcw); + // number of codewords for error correction + const errsize = (2 << ecl); + // calculate number of columns (number of codewords per row) and rows + const nce = (numcw + errsize + 1); + let cols = Math.round((Math.sqrt(4761 + (68 * _aspect_ratio * nce)) - 69) / 34); + // adjust cols + if (cols < 1) { + cols = 1; + } else if (cols > 30) { + cols = 30; + } + let rows = Math.ceil(nce / cols); + let size = (cols * rows); + // adjust rows + if ((rows < 3) || (rows > 90)) { + if (rows < 3) { + rows = 3; + } else if (rows > 90) { + rows = 90; + } + cols = Math.ceil(size / rows); + size = (cols * rows); + } + if (size > 928) { + // set dimensions to get maximum capacity + if (Math.abs(_aspectRatio - (17 * 29 / 32)) < Math.abs(_aspectRatio - (17 * 16 / 58))) { + cols = 29; + rows = 32; + } else { + cols = 16; + rows = 58; + } + size = 928; + } + // calculate padding + const pad = (size - nce); + if (pad > 0) { + if ((size - rows) == nce) { + --rows; + size -= rows; + } else { + // add pading + codewords = codewords.concat(_array_fill(0, pad, 900)); + } + } + + // Symbol Length Descriptor (number of data codewords including Symbol Length Descriptor and pad codewords) + const sld = size - errsize; + // add symbol length description + codewords.unshift(sld); + // calculate error correction + const ecw = _get_error_correction_word(codewords, ecl); + // add error correction codewords + codewords = codewords.concat(ecw); + // create our return structure + const _barcode_array = { + rows, + cols: ((cols + 2) * 17) + 35, + data: new Array(), + parameters: { + aspectRatio: _aspect_ratio, + errorCorrectionLevel: ecl, + }, + }; + + let L; + let k = 0; // codeword index + let cid = 0; // initial cluster + // for each row + for (let r = 0; r < rows; ++r) { + // row start code + let row = START_PATTERN; + switch (cid) { + case 0: { + L = ((30 * _intval(r / 3)) + _intval((rows - 1) / 3)); + break; + } + case 1: { + L = ((30 * _intval(r / 3)) + (ecl * 3) + ((rows - 1) % 3)); + break; + } + case 2: { + L = ((30 * _intval(r / 3)) + (cols - 1)); + break; + } + } + // left row indicator + row += _binary17(CLUSTERS[cid][L]); + // for each column + for (var c = 0; c < cols; ++c) { + row += _binary17(CLUSTERS[cid][codewords[k]]); + ++k; + } + switch (cid) { + case 0: { + L = ((30 * _intval(r / 3)) + (cols - 1)); + break; + } + case 1: { + L = ((30 * _intval(r / 3)) + _intval((rows - 1) / 3)); + break; + } + case 2: { + L = ((30 * _intval(r / 3)) + (ecl * 3) + ((rows - 1) % 3)); + break; + } + } + // right row indicator + row += _binary17(CLUSTERS[cid][L]); + // row stop code + row += STOP_PATTERN; + // convert the string to array + const arow = new Array(); + for (var c in row) { + arow.push(row[c] == '1'); + } + // duplicate row to get the desired height + _barcode_array.data.push(arow); + ++cid; + if (cid > 2) { + cid = 0; + } + } + + return _barcode_array; + }; + __formats.pdf417 = pdf417_create; + + /* Import the QRCODE creation code */ + /*= =================================================================================================================================================* + | QRCODE CREATION FUNCTION | + *================================================================================================================================================== */ + const qrcode_create = (function () { + + /* Imported (reduced) pretty much statically from QR lib, + * See at the bottom for our-style function */ + + //--------------------------------------------------------------------- + // qrcode + //--------------------------------------------------------------------- + + /** + * qrcode + * @param typeNumber 1 to 10 + * @param errorCorrectLevel 'L','M','Q','H' + */ + const qrcode = function (typeNumber, errorCorrectLevel) { + + const PAD0 = 0xEC; + const PAD1 = 0x11; + + const _typeNumber = typeNumber; + const _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel]; + let _modules = null; + let _moduleCount = 0; + let _dataCache = null; + const _dataList = new Array(); + + const _this = {}; + + const makeImpl = function (test, maskPattern) { + + _moduleCount = _typeNumber * 4 + 17; + _modules = (function (moduleCount) { + const modules = new Array(moduleCount); + for (let row = 0; row < moduleCount; row += 1) { + modules[row] = new Array(moduleCount); + for (let col = 0; col < moduleCount; col += 1) { + modules[row][col] = null; + } + } + return modules; + }(_moduleCount)); + + setupPositionProbePattern(0, 0); + setupPositionProbePattern(_moduleCount - 7, 0); + setupPositionProbePattern(0, _moduleCount - 7); + setupPositionAdjustPattern(); + setupTimingPattern(); + setupTypeInfo(test, maskPattern); + + if (_typeNumber >= 7) { + setupTypeNumber(test); + } + + if (_dataCache == null) { + _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList); + } + + mapData(_dataCache, maskPattern); + }; + + var setupPositionProbePattern = function (row, col) { + + for (let r = -1; r <= 7; r += 1) { + + if (row + r <= -1 || _moduleCount <= row + r) continue; + + for (let c = -1; c <= 7; c += 1) { + + if (col + c <= -1 || _moduleCount <= col + c) continue; + + if ((r >= 0 && r <= 6 && (c == 0 || c == 6)) + || (c >= 0 && c <= 6 && (r == 0 || r == 6)) + || (r >= 2 && r <= 4 && c >= 2 && c <= 4)) { + _modules[row + r][col + c] = true; + } else { + _modules[row + r][col + c] = false; + } + } + } + }; + + const getBestMaskPattern = function () { + + let minLostPoint = 0; + let pattern = 0; + + for (let i = 0; i < 8; i += 1) { + + makeImpl(true, i); + + const lostPoint = QRUtil.getLostPoint(_this); + + if (i == 0 || minLostPoint > lostPoint) { + minLostPoint = lostPoint; + pattern = i; + } + } + + return pattern; + }; + + var setupTimingPattern = function () { + + for (let r = 8; r < _moduleCount - 8; r += 1) { + if (_modules[r][6] != null) { + continue; + } + _modules[r][6] = (r % 2 == 0); + } + + for (let c = 8; c < _moduleCount - 8; c += 1) { + if (_modules[6][c] != null) { + continue; + } + _modules[6][c] = (c % 2 == 0); + } + }; + + var setupPositionAdjustPattern = function () { + + const pos = QRUtil.getPatternPosition(_typeNumber); + + for (let i = 0; i < pos.length; i += 1) { + + for (let j = 0; j < pos.length; j += 1) { + + const row = pos[i]; + const col = pos[j]; + + if (_modules[row][col] != null) { + continue; + } + + for (let r = -2; r <= 2; r += 1) { + + for (let c = -2; c <= 2; c += 1) { + + if (r == -2 || r == 2 || c == -2 || c == 2 + || (r == 0 && c == 0)) { + _modules[row + r][col + c] = true; + } else { + _modules[row + r][col + c] = false; + } + } + } + } + } + }; + + var setupTypeNumber = function (test) { + + const bits = QRUtil.getBCHTypeNumber(_typeNumber); + + for (var i = 0; i < 18; i += 1) { + var mod = (!test && ((bits >> i) & 1) == 1); + _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod; + } + + for (var i = 0; i < 18; i += 1) { + var mod = (!test && ((bits >> i) & 1) == 1); + _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod; + } + }; + + var setupTypeInfo = function (test, maskPattern) { + + const data = (_errorCorrectLevel << 3) | maskPattern; + const bits = QRUtil.getBCHTypeInfo(data); + + // vertical + for (var i = 0; i < 15; i += 1) { + + var mod = (!test && ((bits >> i) & 1) == 1); + + if (i < 6) { + _modules[i][8] = mod; + } else if (i < 8) { + _modules[i + 1][8] = mod; + } else { + _modules[_moduleCount - 15 + i][8] = mod; + } + } + + // horizontal + for (var i = 0; i < 15; i += 1) { + + var mod = (!test && ((bits >> i) & 1) == 1); + + if (i < 8) { + _modules[8][_moduleCount - i - 1] = mod; + } else if (i < 9) { + _modules[8][15 - i - 1 + 1] = mod; + } else { + _modules[8][15 - i - 1] = mod; + } + } + + // fixed module + _modules[_moduleCount - 8][8] = (!test); + }; + + var mapData = function (data, maskPattern) { + + let inc = -1; + let row = _moduleCount - 1; + let bitIndex = 7; + let byteIndex = 0; + const maskFunc = QRUtil.getMaskFunction(maskPattern); + + for (let col = _moduleCount - 1; col > 0; col -= 2) { + + if (col == 6) col -= 1; + + while (true) { + + for (let c = 0; c < 2; c += 1) { + + if (_modules[row][col - c] == null) { + + let dark = false; + + if (byteIndex < data.length) { + dark = (((data[byteIndex] >>> bitIndex) & 1) == 1); + } + + const mask = maskFunc(row, col - c); + + if (mask) { + dark = !dark; + } + + _modules[row][col - c] = dark; + bitIndex -= 1; + + if (bitIndex == -1) { + byteIndex += 1; + bitIndex = 7; + } + } + } + + row += inc; + + if (row < 0 || _moduleCount <= row) { + row -= inc; + inc = -inc; + break; + } + } + } + }; + + const createBytes = function (buffer, rsBlocks) { + + let offset = 0; + + let maxDcCount = 0; + let maxEcCount = 0; + + const dcdata = new Array(rsBlocks.length); + const ecdata = new Array(rsBlocks.length); + + for (var r = 0; r < rsBlocks.length; r += 1) { + + const dcCount = rsBlocks[r].dataCount; + const ecCount = rsBlocks[r].totalCount - dcCount; + + maxDcCount = Math.max(maxDcCount, dcCount); + maxEcCount = Math.max(maxEcCount, ecCount); + + dcdata[r] = new Array(dcCount); + + for (var i = 0; i < dcdata[r].length; i += 1) { + dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; + } + offset += dcCount; + + const rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); + const rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1); + + const modPoly = rawPoly.mod(rsPoly); + ecdata[r] = new Array(rsPoly.getLength() - 1); + for (var i = 0; i < ecdata[r].length; i += 1) { + const modIndex = i + modPoly.getLength() - ecdata[r].length; + ecdata[r][i] = (modIndex >= 0) ? modPoly.getAt(modIndex) : 0; + } + } + + let totalCodeCount = 0; + for (var i = 0; i < rsBlocks.length; i += 1) { + totalCodeCount += rsBlocks[i].totalCount; + } + + const data = new Array(totalCodeCount); + let index = 0; + + for (var i = 0; i < maxDcCount; i += 1) { + for (var r = 0; r < rsBlocks.length; r += 1) { + if (i < dcdata[r].length) { + data[index] = dcdata[r][i]; + index += 1; + } + } + } + + for (var i = 0; i < maxEcCount; i += 1) { + for (var r = 0; r < rsBlocks.length; r += 1) { + if (i < ecdata[r].length) { + data[index] = ecdata[r][i]; + index += 1; + } + } + } + + return data; + }; + + var createData = function (typeNumber, errorCorrectLevel, dataList) { + + const rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); + + const buffer = qrBitBuffer(); + + for (var i = 0; i < dataList.length; i += 1) { + const data = dataList[i]; + buffer.put(data.getMode(), 4); + buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber)); + data.write(buffer); + } + + // calc num max data. + let totalDataCount = 0; + for (var i = 0; i < rsBlocks.length; i += 1) { + totalDataCount += rsBlocks[i].dataCount; + } + + if (buffer.getLengthInBits() > totalDataCount * 8) { + throw new Error(`code length overflow. (${ + buffer.getLengthInBits() + }>${ + totalDataCount * 8 + })`); + } + + // end code + if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { + buffer.put(0, 4); + } + + // padding + while (buffer.getLengthInBits() % 8 != 0) { + buffer.putBit(false); + } + + // padding + while (true) { + + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + buffer.put(PAD0, 8); + + if (buffer.getLengthInBits() >= totalDataCount * 8) { + break; + } + buffer.put(PAD1, 8); + } + + return createBytes(buffer, rsBlocks); + }; + + _this.addData = function (data) { + const newData = qr8BitByte(data); + _dataList.push(newData); + _dataCache = null; + }; + + _this.getData = function () { + return _modules; + }; + + _this.isDark = function (row, col) { + if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) { + throw new Error(`${row},${col}`); + } + return _modules[row][col]; + }; + + _this.getModuleCount = function () { + return _moduleCount; + }; + + _this.make = function () { + makeImpl(false, getBestMaskPattern()); + }; + + return _this; + }; + + //--------------------------------------------------------------------- + // qrcode.stringToBytes + //--------------------------------------------------------------------- + + qrcode.stringToBytes = function (s) { + const bytes = new Array(); + for (let i = 0; i < s.length; i += 1) { + const c = s.charCodeAt(i); + bytes.push(c & 0xff); + } + return bytes; + }; + + //--------------------------------------------------------------------- + // qrcode.createStringToBytes + //--------------------------------------------------------------------- + + /** + * @param unicodeData base64 string of byte array. + * [16bit Unicode],[16bit Bytes], ... + * @param numChars + */ + qrcode.createStringToBytes = function (unicodeData, numChars) { + + // create conversion map. + + const unicodeMap = (function () { + + const bin = base64DecodeInputStream(unicodeData); + const read = function () { + const b = bin.read(); + if (b == -1) throw new Error(); + return b; + }; + + let count = 0; + const unicodeMap = {}; + while (true) { + const b0 = bin.read(); + if (b0 == -1) break; + const b1 = read(); + const b2 = read(); + const b3 = read(); + const k = String.fromCharCode((b0 << 8) | b1); + const v = (b2 << 8) | b3; + unicodeMap[k] = v; + count += 1; + } + if (count != numChars) { + throw new Error(`${count} != ${numChars}`); + } + + return unicodeMap; + }()); + + const unknownChar = '?'.charCodeAt(0); + + return function (s) { + const bytes = new Array(); + for (let i = 0; i < s.length; i += 1) { + const c = s.charCodeAt(i); + if (c < 128) { + bytes.push(c); + } else { + const b = unicodeMap[s.charAt(i)]; + if (typeof b === 'number') { + if ((b & 0xff) == b) { + // 1byte + bytes.push(b); + } else { + // 2bytes + bytes.push(b >>> 8); + bytes.push(b & 0xff); + } + } else { + bytes.push(unknownChar); + } + } + } + return bytes; + }; + }; + + //--------------------------------------------------------------------- + // QRMode + //--------------------------------------------------------------------- + + const QRMode = { + MODE_NUMBER: 1 << 0, + MODE_ALPHA_NUM: 1 << 1, + MODE_8BIT_BYTE: 1 << 2, + MODE_KANJI: 1 << 3, + }; + + //--------------------------------------------------------------------- + // QRErrorCorrectLevel + //--------------------------------------------------------------------- + + var QRErrorCorrectLevel = { + L: 1, + M: 0, + Q: 3, + H: 2, + }; + + //--------------------------------------------------------------------- + // QRMaskPattern + //--------------------------------------------------------------------- + + const QRMaskPattern = { + PATTERN000: 0, + PATTERN001: 1, + PATTERN010: 2, + PATTERN011: 3, + PATTERN100: 4, + PATTERN101: 5, + PATTERN110: 6, + PATTERN111: 7, + }; + + //--------------------------------------------------------------------- + // QRUtil + //--------------------------------------------------------------------- + + var QRUtil = (function () { + + const PATTERN_POSITION_TABLE = [ + [], + [6, 18], + [6, 22], + [6, 26], + [6, 30], + [6, 34], + [6, 22, 38], + [6, 24, 42], + [6, 26, 46], + [6, 28, 50], + [6, 30, 54], + [6, 32, 58], + [6, 34, 62], + [6, 26, 46, 66], + [6, 26, 48, 70], + [6, 26, 50, 74], + [6, 30, 54, 78], + [6, 30, 56, 82], + [6, 30, 58, 86], + [6, 34, 62, 90], + [6, 28, 50, 72, 94], + [6, 26, 50, 74, 98], + [6, 30, 54, 78, 102], + [6, 28, 54, 80, 106], + [6, 32, 58, 84, 110], + [6, 30, 58, 86, 114], + [6, 34, 62, 90, 118], + [6, 26, 50, 74, 98, 122], + [6, 30, 54, 78, 102, 126], + [6, 26, 52, 78, 104, 130], + [6, 30, 56, 82, 108, 134], + [6, 34, 60, 86, 112, 138], + [6, 30, 58, 86, 114, 142], + [6, 34, 62, 90, 118, 146], + [6, 30, 54, 78, 102, 126, 150], + [6, 24, 50, 76, 102, 128, 154], + [6, 28, 54, 80, 106, 132, 158], + [6, 32, 58, 84, 110, 136, 162], + [6, 26, 54, 82, 110, 138, 166], + [6, 30, 58, 86, 114, 142, 170], + ]; + const G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); + const G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); + const G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); + + const _this = {}; + + const getBCHDigit = function (data) { + let digit = 0; + while (data != 0) { + digit += 1; + data >>>= 1; + } + return digit; + }; + + _this.getBCHTypeInfo = function (data) { + let d = data << 10; + while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { + d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15))); + } + return ((data << 10) | d) ^ G15_MASK; + }; + + _this.getBCHTypeNumber = function (data) { + let d = data << 12; + while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { + d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18))); + } + return (data << 12) | d; + }; + + _this.getPatternPosition = function (typeNumber) { + return PATTERN_POSITION_TABLE[typeNumber - 1]; + }; + + _this.getMaskFunction = function (maskPattern) { + + switch (maskPattern) { + + case QRMaskPattern.PATTERN000: + return function (i, j) { return (i + j) % 2 == 0; }; + case QRMaskPattern.PATTERN001: + return function (i, j) { return i % 2 == 0; }; + case QRMaskPattern.PATTERN010: + return function (i, j) { return j % 3 == 0; }; + case QRMaskPattern.PATTERN011: + return function (i, j) { return (i + j) % 3 == 0; }; + case QRMaskPattern.PATTERN100: + return function (i, j) { return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0; }; + case QRMaskPattern.PATTERN101: + return function (i, j) { return (i * j) % 2 + (i * j) % 3 == 0; }; + case QRMaskPattern.PATTERN110: + return function (i, j) { return ((i * j) % 2 + (i * j) % 3) % 2 == 0; }; + case QRMaskPattern.PATTERN111: + return function (i, j) { return ((i * j) % 3 + (i + j) % 2) % 2 == 0; }; + + default: + throw new Error(`bad maskPattern:${maskPattern}`); + } + }; + + _this.getErrorCorrectPolynomial = function (errorCorrectLength) { + let a = qrPolynomial([1], 0); + for (let i = 0; i < errorCorrectLength; i += 1) { + a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0)); + } + return a; + }; + + _this.getLengthInBits = function (mode, type) { + + if (type >= 1 && type < 10) { + + // 1 - 9 + + switch (mode) { + case QRMode.MODE_NUMBER: return 10; + case QRMode.MODE_ALPHA_NUM: return 9; + case QRMode.MODE_8BIT_BYTE: return 8; + case QRMode.MODE_KANJI: return 8; + default: + throw new Error(`mode:${mode}`); + } + + } else if (type < 27) { + + // 10 - 26 + + switch (mode) { + case QRMode.MODE_NUMBER: return 12; + case QRMode.MODE_ALPHA_NUM: return 11; + case QRMode.MODE_8BIT_BYTE: return 16; + case QRMode.MODE_KANJI: return 10; + default: + throw new Error(`mode:${mode}`); + } + + } else if (type < 41) { + + // 27 - 40 + + switch (mode) { + case QRMode.MODE_NUMBER: return 14; + case QRMode.MODE_ALPHA_NUM: return 13; + case QRMode.MODE_8BIT_BYTE: return 16; + case QRMode.MODE_KANJI: return 12; + default: + throw new Error(`mode:${mode}`); + } + + } else { + throw new Error(`type:${type}`); + } + }; + + _this.getLostPoint = function (qrcode) { + + const moduleCount = qrcode.getModuleCount(); + + let lostPoint = 0; + + // LEVEL1 + + for (var row = 0; row < moduleCount; row += 1) { + for (var col = 0; col < moduleCount; col += 1) { + + let sameCount = 0; + const dark = qrcode.isDark(row, col); + + for (let r = -1; r <= 1; r += 1) { + + if (row + r < 0 || moduleCount <= row + r) { + continue; + } + + for (let c = -1; c <= 1; c += 1) { + + if (col + c < 0 || moduleCount <= col + c) { + continue; + } + + if (r == 0 && c == 0) { + continue; + } + + if (dark == qrcode.isDark(row + r, col + c)) { + sameCount += 1; + } + } + } + + if (sameCount > 5) { + lostPoint += (3 + sameCount - 5); + } + } + } + + // LEVEL2 + + for (var row = 0; row < moduleCount - 1; row += 1) { + for (var col = 0; col < moduleCount - 1; col += 1) { + let count = 0; + if (qrcode.isDark(row, col)) count += 1; + if (qrcode.isDark(row + 1, col)) count += 1; + if (qrcode.isDark(row, col + 1)) count += 1; + if (qrcode.isDark(row + 1, col + 1)) count += 1; + if (count == 0 || count == 4) { + lostPoint += 3; + } + } + } + + // LEVEL3 + + for (var row = 0; row < moduleCount; row += 1) { + for (var col = 0; col < moduleCount - 6; col += 1) { + if (qrcode.isDark(row, col) + && !qrcode.isDark(row, col + 1) + && qrcode.isDark(row, col + 2) + && qrcode.isDark(row, col + 3) + && qrcode.isDark(row, col + 4) + && !qrcode.isDark(row, col + 5) + && qrcode.isDark(row, col + 6)) { + lostPoint += 40; + } + } + } + + for (var col = 0; col < moduleCount; col += 1) { + for (var row = 0; row < moduleCount - 6; row += 1) { + if (qrcode.isDark(row, col) + && !qrcode.isDark(row + 1, col) + && qrcode.isDark(row + 2, col) + && qrcode.isDark(row + 3, col) + && qrcode.isDark(row + 4, col) + && !qrcode.isDark(row + 5, col) + && qrcode.isDark(row + 6, col)) { + lostPoint += 40; + } + } + } + + // LEVEL4 + + let darkCount = 0; + + for (var col = 0; col < moduleCount; col += 1) { + for (var row = 0; row < moduleCount; row += 1) { + if (qrcode.isDark(row, col)) { + darkCount += 1; + } + } + } + + const ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; + lostPoint += ratio * 10; + + return lostPoint; + }; + + return _this; + }()); + + //--------------------------------------------------------------------- + // QRMath + //--------------------------------------------------------------------- + + var QRMath = (function () { + + const EXP_TABLE = new Array(256); + const LOG_TABLE = new Array(256); + + // initialize tables + for (var i = 0; i < 8; i += 1) { + EXP_TABLE[i] = 1 << i; + } + for (var i = 8; i < 256; i += 1) { + EXP_TABLE[i] = EXP_TABLE[i - 4] + ^ EXP_TABLE[i - 5] + ^ EXP_TABLE[i - 6] + ^ EXP_TABLE[i - 8]; + } + for (var i = 0; i < 255; i += 1) { + LOG_TABLE[EXP_TABLE[i]] = i; + } + + const _this = {}; + + _this.glog = function (n) { + + if (n < 1) { + throw new Error(`glog(${n})`); + } + + return LOG_TABLE[n]; + }; + + _this.gexp = function (n) { + + while (n < 0) { + n += 255; + } + + while (n >= 256) { + n -= 255; + } + + return EXP_TABLE[n]; + }; + + return _this; + }()); + + //--------------------------------------------------------------------- + // qrPolynomial + //--------------------------------------------------------------------- + + function qrPolynomial(num, shift) { + + if (typeof num.length === 'undefined') { + throw new Error(`${num.length}/${shift}`); + } + + const _num = (function () { + let offset = 0; + while (offset < num.length && num[offset] == 0) { + offset += 1; + } + const _num = new Array(num.length - offset + shift); + for (let i = 0; i < num.length - offset; i += 1) { + _num[i] = num[i + offset]; + } + return _num; + }()); + + const _this = {}; + + _this.getAt = function (index) { + return _num[index]; + }; + + _this.getLength = function () { + return _num.length; + }; + + _this.multiply = function (e) { + + const num = new Array(_this.getLength() + e.getLength() - 1); + + for (let i = 0; i < _this.getLength(); i += 1) { + for (let j = 0; j < e.getLength(); j += 1) { + num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i)) + QRMath.glog(e.getAt(j))); + } + } + + return qrPolynomial(num, 0); + }; + + _this.mod = function (e) { + + if (_this.getLength() - e.getLength() < 0) { + return _this; + } + + const ratio = QRMath.glog(_this.getAt(0)) - QRMath.glog(e.getAt(0)); + + const num = new Array(_this.getLength()); + for (var i = 0; i < _this.getLength(); i += 1) { + num[i] = _this.getAt(i); + } + + for (var i = 0; i < e.getLength(); i += 1) { + num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i)) + ratio); + } + + // recursive call + return qrPolynomial(num, 0).mod(e); + }; + + return _this; + } + + //--------------------------------------------------------------------- + // QRRSBlock + //--------------------------------------------------------------------- + + var QRRSBlock = (function () { + + const RS_BLOCK_TABLE = [ + + // L + // M + // Q + // H + + // 1 + [1, 26, 19], + [1, 26, 16], + [1, 26, 13], + [1, 26, 9], + + // 2 + [1, 44, 34], + [1, 44, 28], + [1, 44, 22], + [1, 44, 16], + + // 3 + [1, 70, 55], + [1, 70, 44], + [2, 35, 17], + [2, 35, 13], + + // 4 + [1, 100, 80], + [2, 50, 32], + [2, 50, 24], + [4, 25, 9], + + // 5 + [1, 134, 108], + [2, 67, 43], + [2, 33, 15, 2, 34, 16], + [2, 33, 11, 2, 34, 12], + + // 6 + [2, 86, 68], + [4, 43, 27], + [4, 43, 19], + [4, 43, 15], + + // 7 + [2, 98, 78], + [4, 49, 31], + [2, 32, 14, 4, 33, 15], + [4, 39, 13, 1, 40, 14], + + // 8 + [2, 121, 97], + [2, 60, 38, 2, 61, 39], + [4, 40, 18, 2, 41, 19], + [4, 40, 14, 2, 41, 15], + + // 9 + [2, 146, 116], + [3, 58, 36, 2, 59, 37], + [4, 36, 16, 4, 37, 17], + [4, 36, 12, 4, 37, 13], + + // 10 + [2, 86, 68, 2, 87, 69], + [4, 69, 43, 1, 70, 44], + [6, 43, 19, 2, 44, 20], + [6, 43, 15, 2, 44, 16], + ]; + + const qrRSBlock = function (totalCount, dataCount) { + const _this = {}; + _this.totalCount = totalCount; + _this.dataCount = dataCount; + return _this; + }; + + const _this = {}; + + const getRsBlockTable = function (typeNumber, errorCorrectLevel) { + + switch (errorCorrectLevel) { + case QRErrorCorrectLevel.L: + return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; + case QRErrorCorrectLevel.M: + return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; + case QRErrorCorrectLevel.Q: + return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; + case QRErrorCorrectLevel.H: + return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; + default: + return undefined; + } + }; + + _this.getRSBlocks = function (typeNumber, errorCorrectLevel) { + + const rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel); + + if (typeof rsBlock === 'undefined') { + throw new Error(`bad rs block @ typeNumber:${typeNumber + }/errorCorrectLevel:${errorCorrectLevel}`); + } + + const length = rsBlock.length / 3; + + const list = new Array(); + + for (let i = 0; i < length; i += 1) { + + const count = rsBlock[i * 3 + 0]; + const totalCount = rsBlock[i * 3 + 1]; + const dataCount = rsBlock[i * 3 + 2]; + + for (let j = 0; j < count; j += 1) { + list.push(qrRSBlock(totalCount, dataCount)); + } + } + + return list; + }; + + return _this; + }()); + + //--------------------------------------------------------------------- + // qrBitBuffer + //--------------------------------------------------------------------- + + var qrBitBuffer = function () { + + const _buffer = new Array(); + let _length = 0; + + const _this = {}; + + _this.getBuffer = function () { + return _buffer; + }; + + _this.getAt = function (index) { + const bufIndex = Math.floor(index / 8); + return ((_buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1; + }; + + _this.put = function (num, length) { + for (let i = 0; i < length; i += 1) { + _this.putBit(((num >>> (length - i - 1)) & 1) == 1); + } + }; + + _this.getLengthInBits = function () { + return _length; + }; + + _this.putBit = function (bit) { + + const bufIndex = Math.floor(_length / 8); + if (_buffer.length <= bufIndex) { + _buffer.push(0); + } + + if (bit) { + _buffer[bufIndex] |= (0x80 >>> (_length % 8)); + } + + _length += 1; + }; + + return _this; + }; + + //--------------------------------------------------------------------- + // qr8BitByte + //--------------------------------------------------------------------- + + var qr8BitByte = function (data) { + + const _mode = QRMode.MODE_8BIT_BYTE; + const _data = data; + const _bytes = qrcode.stringToBytes(data); + + const _this = {}; + + _this.getMode = function () { + return _mode; + }; + + _this.getLength = function (buffer) { + return _bytes.length; + }; + + _this.write = function (buffer) { + for (let i = 0; i < _bytes.length; i += 1) { + buffer.put(_bytes[i], 8); + } + }; + + return _this; + }; + + /*= ===============================================================================================================================================* + | Actually create a new QRCode and return our consistent structure | + | "typeNumber" in the lib's terminology is what Wikipedia calls "version"... we follow that | + *================================================================================================================================================ */ + return function (code, parameters) { + let version = 4; + let errorCorrectLevelNum = 1; + let errorCorrectLevel = 'M'; + + if (parameters != null) { + version = Number(parameters.version) || 6; + if (version < 1) version = 1; + if (version > 10) version = 10; + + errorCorrectLevelNum = Number(parameters.errorCorrectionLevel) || 1; + if (errorCorrectLevelNum < 0) ecl = 0; + if (errorCorrectLevelNum > 3) ecl = 3; + switch (errorCorrectLevelNum) { + // internally using a different scale + case 0: errorCorrectLevel = 'L'; break; // internally 1 + case 1: errorCorrectLevel = 'M'; break; // internally 0 + case 2: errorCorrectLevel = 'Q'; break; // internally 3 + case 3: errorCorrectLevel = 'H'; break; // internally 2 + } + } + + const qr = qrcode(version, errorCorrectLevel); + qr.addData(code); + qr.make(); + return { + rows: qr.getModuleCount(), + cols: qr.getModuleCount(), + data: qr.getData(), + parameters: { + errorCorrectionLevel: errorCorrectLevelNum, + version, + }, + }; + }; + + }()); + __formats.qrcode = qrcode_create; + + /* Import the QRCODE GIF library */ + const create_image_data = (function () { + + //--------------------------------------------------------------------- + // byteArrayOutputStream + //--------------------------------------------------------------------- + + const byteArrayOutputStream = function () { + + const _bytes = new Array(); + + const _this = {}; + + _this.writeByte = function (b) { + _bytes.push(b & 0xff); + }; + + _this.writeShort = function (i) { + _this.writeByte(i); + _this.writeByte(i >>> 8); + }; + + _this.writeBytes = function (b, off, len) { + off = off || 0; + len = len || b.length; + for (let i = 0; i < len; i += 1) { + _this.writeByte(b[i + off]); + } + }; + + _this.writeString = function (s) { + for (let i = 0; i < s.length; i += 1) { + _this.writeByte(s.charCodeAt(i)); + } + }; + + _this.toByteArray = function () { + return _bytes; + }; + + _this.toString = function () { + let s = ''; + s += '['; + for (let i = 0; i < _bytes.length; i += 1) { + if (i > 0) { + s += ','; + } + s += _bytes[i]; + } + s += ']'; + return s; + }; + + return _this; + }; + + //--------------------------------------------------------------------- + // base64EncodeOutputStream + //--------------------------------------------------------------------- + + const base64EncodeOutputStream = function () { + + let _buffer = 0; + let _buflen = 0; + let _length = 0; + let _base64 = ''; + + const _this = {}; + + const writeEncoded = function (b) { + _base64 += String.fromCharCode(encode(b & 0x3f)); + }; + + var encode = function (n) { + if (n < 0) { + // error. + } else if (n < 26) { + return 0x41 + n; + } else if (n < 52) { + return 0x61 + (n - 26); + } else if (n < 62) { + return 0x30 + (n - 52); + } else if (n == 62) { + return 0x2b; + } else if (n == 63) { + return 0x2f; + } + throw new Error(`n:${n}`); + }; + + _this.writeByte = function (n) { + + _buffer = (_buffer << 8) | (n & 0xff); + _buflen += 8; + _length += 1; + + while (_buflen >= 6) { + writeEncoded(_buffer >>> (_buflen - 6)); + _buflen -= 6; + } + }; + + _this.flush = function () { + + if (_buflen > 0) { + writeEncoded(_buffer << (6 - _buflen)); + _buffer = 0; + _buflen = 0; + } + + if (_length % 3 != 0) { + // padding + const padlen = 3 - _length % 3; + for (let i = 0; i < padlen; i += 1) { + _base64 += '='; + } + } + }; + + _this.toString = function () { + return _base64; + }; + + return _this; + }; + + //--------------------------------------------------------------------- + // gifImage (B/W) + //--------------------------------------------------------------------- + + const gifImage = function (width, height) { + + const _width = width; + const _height = height; + const _data = new Array(width * height); + + const _this = {}; + + _this.setPixel = function (x, y, pixel) { + _data[y * _width + x] = pixel; + }; + + _this.write = function (out) { + + //--------------------------------- + // GIF Signature + + out.writeString('GIF87a'); + + //--------------------------------- + // Screen Descriptor + + out.writeShort(_width); + out.writeShort(_height); + + out.writeByte(0x80); // 2bit + out.writeByte(0); + out.writeByte(0); + + //--------------------------------- + // Global Color Map + + // black + out.writeByte(0x00); + out.writeByte(0x00); + out.writeByte(0x00); + + // white + out.writeByte(0xff); + out.writeByte(0xff); + out.writeByte(0xff); + + //--------------------------------- + // Image Descriptor + + out.writeString(','); + out.writeShort(0); + out.writeShort(0); + out.writeShort(_width); + out.writeShort(_height); + out.writeByte(0); + + //--------------------------------- + // Local Color Map + + //--------------------------------- + // Raster Data + + const lzwMinCodeSize = 2; + const raster = getLZWRaster(lzwMinCodeSize); + + out.writeByte(lzwMinCodeSize); + + let offset = 0; + + while (raster.length - offset > 255) { + out.writeByte(255); + out.writeBytes(raster, offset, 255); + offset += 255; + } + + out.writeByte(raster.length - offset); + out.writeBytes(raster, offset, raster.length - offset); + out.writeByte(0x00); + + //--------------------------------- + // GIF Terminator + out.writeString(';'); + }; + + const bitOutputStream = function (out) { + + const _out = out; + let _bitLength = 0; + let _bitBuffer = 0; + + const _this = {}; + + _this.write = function (data, length) { + + if ((data >>> length) != 0) { + throw new Error('length over'); + } + + while (_bitLength + length >= 8) { + _out.writeByte(0xff & ((data << _bitLength) | _bitBuffer)); + length -= (8 - _bitLength); + data >>>= (8 - _bitLength); + _bitBuffer = 0; + _bitLength = 0; + } + + _bitBuffer = (data << _bitLength) | _bitBuffer; + _bitLength += length; + }; + + _this.flush = function () { + if (_bitLength > 0) { + _out.writeByte(_bitBuffer); + } + }; + + return _this; + }; + + var getLZWRaster = function (lzwMinCodeSize) { + + const clearCode = 1 << lzwMinCodeSize; + const endCode = (1 << lzwMinCodeSize) + 1; + let bitLength = lzwMinCodeSize + 1; + + // Setup LZWTable + const table = lzwTable(); + + for (let i = 0; i < clearCode; i += 1) { + table.add(String.fromCharCode(i)); + } + table.add(String.fromCharCode(clearCode)); + table.add(String.fromCharCode(endCode)); + + const byteOut = byteArrayOutputStream(); + const bitOut = bitOutputStream(byteOut); + + // clear code + bitOut.write(clearCode, bitLength); + + let dataIndex = 0; + + let s = String.fromCharCode(_data[dataIndex]); + dataIndex += 1; + + while (dataIndex < _data.length) { + + const c = String.fromCharCode(_data[dataIndex]); + dataIndex += 1; + + if (table.contains(s + c)) { + + s += c; + + } else { + + bitOut.write(table.indexOf(s), bitLength); + + if (table.size() < 0xfff) { + + if (table.size() == (1 << bitLength)) { + bitLength += 1; + } + + table.add(s + c); + } + + s = c; + } + } + + bitOut.write(table.indexOf(s), bitLength); + + // end code + bitOut.write(endCode, bitLength); + + bitOut.flush(); + + return byteOut.toByteArray(); + }; + + var lzwTable = function () { + + const _map = {}; + let _size = 0; + + const _this = {}; + + _this.add = function (key) { + if (_this.contains(key)) { + throw new Error(`dup key:${key}`); + } + _map[key] = _size; + _size += 1; + }; + + _this.size = function () { + return _size; + }; + + _this.indexOf = function (key) { + return _map[key]; + }; + + _this.contains = function (key) { + return typeof _map[key] !== 'undefined'; + }; + + return _this; + }; + + return _this; + }; + + //--------------------------------------------------------------------- + // adapted from + // var createImgTag = function(width, height, getPixel, alt) { ... } + //--------------------------------------------------------------------- + + return function (width, height, getPixel) { + const gif = gifImage(width, height); + for (let y = 0; y < height; y += 1) { + for (let x = 0; x < width; x += 1) { + gif.setPixel(x, y, getPixel(x, y)); + } + } + + const b = byteArrayOutputStream(); + gif.write(b); + + const base64 = base64EncodeOutputStream(); + const bytes = b.toByteArray(); + for (let i = 0; i < bytes.length; i += 1) { + base64.writeByte(bytes[i]); + } + base64.flush(); + + return `data:image/gif;base64,${base64}`; + }; + + }()); + __create_image_data = create_image_data; + }()); + + + /* ======================================================================= */ + /* Return our object definition */ + /* ======================================================================= */ + return Barcode; + +}()); + +module.exports = BarcodeExport; diff --git a/src/js/passbook.js b/src/js/passbook.js new file mode 100644 index 0000000..3729b6d --- /dev/null +++ b/src/js/passbook.js @@ -0,0 +1,802 @@ +const jQuery = require('jquery'); +const Barcode = require('./javascript-barcodes'); + +/* eslint-disable camelcase, no-underscore-dangle, no-shadow, no-use-before-define */ +/* eslint-disable function-paren-newline, consistent-return, max-len */ + +function passbook($) { + + const TYPE_BOARDING_PASS = 'boarding-pass'; + const TYPE_COUPON = 'coupon'; + const TYPE_EVENT = 'event'; + const TYPE_STORE_CARD = 'store-card'; + const TYPE_GENERIC = 'generic'; + + const TRANSPORT_AIR = 'air'; + const TRANSPORT_BOAT = 'boat'; + const TRANSPORT_BUS = 'bus'; + const TRANSPORT_TRAIN = 'train'; + const TRANSPORT_GENERIC = 'generic'; + + const TYPE_BOARDING_PASS_C = 'passbook-boarding-pass'; + const TYPE_COUPON_C = 'passbook-coupon'; + const TYPE_EVENT_C = 'passbook-event'; + const TYPE_STORE_CARD_C = 'passbook-store-card'; + const TYPE_C = [TYPE_BOARDING_PASS_C, + TYPE_COUPON_C, + TYPE_EVENT_C, + TYPE_STORE_CARD_C].join(' '); + + const TRANSPORT_AIR_C = 'passbook-transport-air'; + const TRANSPORT_BOAT_C = 'passbook-transport-boat'; + const TRANSPORT_BUS_C = 'passbook-transport-bus'; + const TRANSPORT_TRAIN_C = 'passbook-transport-train'; + const TRANSPORT_C = [TRANSPORT_AIR_C, + TRANSPORT_BOAT_C, + TRANSPORT_BUS_C, + TRANSPORT_TRAIN_C].join(' '); + + + /* ======================================================================== */ + /* STATIC HELPER FUNCTIONS */ + /* ======================================================================== */ + + const _flip = function (event) { + event.data.flip(); + event.preventDefault(); + event.stopPropagation(); + }; + + const _edit_save = function (event) { + const passbook = event.data; + if (passbook.$container.hasClass('passbook-edit')) { + passbook.save(); + } else { + passbook.edit(); + } + event.preventDefault(); + event.stopPropagation(); + }; + + const _content_edited = function (event) { + const $target = $(event.target); + $target.text($target.text().trim()); + event.preventDefault(); + event.stopPropagation(); + }; + + const _remove_empty_extra_fields = function (event) { + /* Do not remove extra fields if we're left with less than 1 */ + if ($(this).parent('tr').children('th,td').length < 2) return true; + + /* Find our label and value fields */ + const column = $(this).parent('tr').children('th,td').index(this) + 1; + const label = $(this).parents('table').find(`th:nth-child(${column})`); + const value = $(this).parents('table').find(`td:nth-child(${column})`); + + /* Do not wipe if we have ANY content */ + if (label.text().length !== 0) return; + if (value.text().length !== 0) return; + + /* Wipe the column */ + label.remove(); + value.remove(); + }; + + const _add_empty_extra_fields = function (event) { + const header = $(this).parents('table.passbook-extra-fields').find('tr'); + $(header[0]).append($('
') + .on('blur', _content_edited) + .on('blur', _remove_empty_extra_fields)); + $(header[1]).append($('') + .on('blur', _content_edited) + .on('blur', _remove_empty_extra_fields)); + }; + + const _remove_empty_back_fields = function (event) { + const $this = $(this); + + /* Figure out label and value (row and cell) */ + let label, + value, + labelRow, + valueRow; + if ($this.prop('tagName') === 'TH') { + label = $this; + labelRow = $this.parents('tr'); + valueRow = labelRow.next('tr'); + value = valueRow.find('td'); + + } else if ($this.prop('tagName') === 'TD') { + value = $this; + valueRow = $this.parents('tr'); + labelRow = valueRow.prev('tr'); + label = labelRow.find('th'); + } + + /* Check if there is some content */ + if (label.text().length !== 0) return; + if (value.text().length !== 0) return; + + /* Wipe the two label and value rows */ + labelRow.remove(); + valueRow.remove(); + + }; + + const _add_empty_back_fields = function (event) { + $(this).parents('.passbook-back-fields').find('table') + .append($('
') + .on('blur', _content_edited) + .on('blur', _remove_empty_back_fields)), //
') + .on('blur', _content_edited) + .on('blur', _remove_empty_back_fields)), //
') + .append($('') + .append($(' + .append($('') + .append($(' + ) //
')) + .append($(''))) //
'))), //
+ .append($('
') + .append($('
'))) //
+ .append($('
')) + .append($('') + .append($('') + .append($('') + .append($(' + ) // + .append($('') + .append($('') + .append($(' + ), // + ) //
')) + .append($(''))), //
')) + .append($(''))), //
+ .append($('') + .append($('
').on('click', this, _add_empty_extra_fields)) + .append($('
')) + .append($(''))) //
+ .append($('') + .append($('
').on('click', this, _add_empty_extra_fields)) + .append($('
')) + .append($(''))) //
+ .append($('
')) + .append($('
').on('click', this, _flip)) + .append($('
').on('click', this, _edit_save))) //
+ .append($('
') + .append($('
').on('click', this, _flip)) + .append($('
') + .append($('')) + .append($('
').on('click', this, _add_empty_back_fields))), //
+ ), // + ); // + // + + /* Other initialization, after the HTML is done, */ + const $element = $(element); + $element.append(this.$container); + + /* Current properties */ + this.type = $element.data('passbook-type') || TYPE_GENERIC; + this.transport = $element.data('passbook-transport') || TRANSPORT_GENERIC; + this.barcode = ''; + this.barcodeType = ''; + }; + + + /* ======================================================================== */ + /* CONSTANTS */ + /* ======================================================================== */ + + Object.defineProperty(Passbook.prototype, 'TYPE_BOARDING_PASS', {value: TYPE_BOARDING_PASS}); + Object.defineProperty(Passbook.prototype, 'TYPE_COUPON', {value: TYPE_COUPON}); + Object.defineProperty(Passbook.prototype, 'TYPE_EVENT', {value: TYPE_EVENT}); + Object.defineProperty(Passbook.prototype, 'TYPE_STORE_CARD', {value: TYPE_STORE_CARD}); + Object.defineProperty(Passbook.prototype, 'TYPE_GENERIC', {value: TYPE_GENERIC}); + + Object.defineProperty(Passbook.prototype, 'TRANSPORT_AIR', {value: TRANSPORT_AIR}); + Object.defineProperty(Passbook.prototype, 'TRANSPORT_BOAT', {value: TRANSPORT_BOAT}); + Object.defineProperty(Passbook.prototype, 'TRANSPORT_BUS', {value: TRANSPORT_BUS}); + Object.defineProperty(Passbook.prototype, 'TRANSPORT_TRAIN', {value: TRANSPORT_TRAIN}); + Object.defineProperty(Passbook.prototype, 'TRANSPORT_GENERIC', {value: TRANSPORT_GENERIC}); + + + /* ======================================================================== */ + /* FUNCTIONS */ + /* ======================================================================== */ + + Passbook.prototype.edit = function () { + /* Check if we're editing */ + if (this.mode === 'edit') return; + + /* Trim all the content */ + this.$container.find('th,td').not('.passbook-logo') + .attr('contenteditable', true) + .on('blur', this, _content_edited); + + /* Remove extra fields when empty */ + this.$container.find('.passbook-extra-fields [contenteditable]') + .on('blur', this, _remove_empty_extra_fields); + this.$container.find('.passbook-back-fields [contenteditable]') + .on('blur', this, _remove_empty_back_fields); + + /* Popover for barcode */ + this.$container.find('.passbook-barcode') + .on('shown.bs.popover', this, barcode_shown) + .popover({ + animation: false, + html: true, + placement: 'top', + trigger: 'click', + title: 'Barcode contents', + content: barcode_popover, + }); + + /* Popover for thumbnail */ + this.$container.find('.passbook-thumbnail') + .on('shown.bs.popover', this, thumbnail_shown) + .on('hidden.bs.popover', this, thumbnail_hidden) + .popover({ + animation: false, + html: false, + placement: 'left', + trigger: 'click', + content: 'Paste a logo', + }); + + /* Popover for thumbnail */ + this.$container.find('.passbook-logo') + .on('shown.bs.popover', this, logo_shown) + .on('hidden.bs.popover', this, logo_hidden) + .popover({ + animation: false, + html: false, + placement: 'right', + trigger: 'click', + content: 'Paste a thumbnail', + }); + + /* Other editors for colors, type, transport... */ + this.$container.find('.passbook-front').on('click', this, passbook_picker_toggle); + this.$container.find('.passbook-transport').on('click', this, transport_toggle); + this.$container.find('.passbook-clear').on('click', this, clear_image); + + /* Class marker */ + this.$container.addClass('passbook-edit'); + }; + + Passbook.prototype.save = function () { + /* Check if we're editing */ + if (this.mode !== 'edit') return; + + this.$container.find('[contenteditable]') + .removeAttr('contenteditable') + .off('blur'); + this.$container.removeClass('passbook-edit'); + this.$container.find('.passbook-barcode') + .off('shown.bs.popover') + .popover('destroy'); + this.$container.find('.passbook-thumbnail') + .off('shown.bs.popover') + .popover('destroy'); + this.$container.find('.passbook-logo') + .off('shown.bs.popover') + .popover('destroy'); + + this.$container.find('.passbook-front').off('click'); + this.$container.find('.passbook-transport').off('click'); + + this.$container.find('.passbook-picker') + .removeAttr('style') + .empty(); + }; + + Passbook.prototype.flip = function () { + this.$container.toggleClass('passbook-flipped'); + }; + + /* ======================================================================== */ + /* PROPERTIES */ + /* ======================================================================== */ + + Object.defineProperty(Passbook.prototype, 'type', { + get() { + if (this.$container.hasClass(TYPE_BOARDING_PASS_C)) return TYPE_BOARDING_PASS; + if (this.$container.hasClass(TYPE_COUPON_C)) return TYPE_COUPON; + if (this.$container.hasClass(TYPE_EVENT_C)) return TYPE_EVENT; + if (this.$container.hasClass(TYPE_STORE_CARD_C)) return TYPE_STORE_CARD; + return TYPE_GENERIC; + }, + set(value) { + let cls; + if (value === TYPE_BOARDING_PASS) cls = TYPE_BOARDING_PASS_C; + else if (value === TYPE_COUPON) cls = TYPE_COUPON_C; + else if (value === TYPE_EVENT) cls = TYPE_EVENT_C; + else if (value === TYPE_STORE_CARD) cls = TYPE_STORE_CARD_C; + else if (value === TYPE_GENERIC) cls = null; + else throw new Error(`Unsupported passbook type "${value}"`); + + this.$container.removeClass(TYPE_C); + if (cls != null) this.$container.addClass(cls); + }, + }); + + Object.defineProperty(Passbook.prototype, 'transport', { + get() { + /* Transport available only in boarding passes */ + if (!this.$container.hasClass(TYPE_BOARDING_PASS_C)) return null; + + /* Transport available only in boarding passes */ + if (this.$container.hasClass(TRANSPORT_AIR_C)) return this.TRANSPORT_AIR; + if (this.$container.hasClass(TRANSPORT_BOAT_C)) return this.TRANSPORT_BOAT; + if (this.$container.hasClass(TRANSPORT_BUS_C)) return this.TRANSPORT_BUS; + if (this.$container.hasClass(TRANSPORT_TRAIN_C)) return this.TRANSPORT_TRAIN; + return TRANSPORT_GENERIC; + }, + set(value) { + let cls; + if (value === TRANSPORT_AIR) cls = TRANSPORT_AIR_C; + else if (value === TRANSPORT_BOAT) cls = TRANSPORT_BOAT_C; + else if (value === TRANSPORT_BUS) cls = TRANSPORT_BUS_C; + else if (value === TRANSPORT_TRAIN) cls = TRANSPORT_TRAIN_C; + else if (value === TRANSPORT_GENERIC) cls = null; + else throw new Error(`Unsupported transport type "${value}"`); + + /* Set the class irregardless of pass type */ + this.$container.removeClass(TRANSPORT_C); + if (cls != null) this.$container.addClass(cls); + }, + }); + + Object.defineProperty(Passbook.prototype, 'color', { + get() { + return this.$container.find('.passbook-color').css('background-color'); + }, + set(color) { + color = $(`
`).css('color'); + if ((color == null) || (!color)) return; + this.$container.find('.passbook-color').css('background-color', color); + }, + }); + + Object.defineProperty(Passbook.prototype, 'shading', { + get() { + let shading = this.$container.find('.passbook-shading').css('opacity'); + shading = Math.round(((Number(shading) / 2) * 3) * 100) / 100; + if (shading < 0) shading = 0; + else if (shading > 1) shading = 1; + return this.$container.hasClass('passbook-white') ? shading : -shading; + }, + set(shading) { + if (shading < 0) { + shading = -shading; + this.$container.removeClass('passbook-white'); + this.$container.find('.passbook-color').css('color', `rgba(0,0,0,${shading})`); + this.$container.find('.passbook-shading').css('opacity', shading / 3 * 2); + } else { + this.$container.addClass('passbook-white'); + this.$container.find('.passbook-color').css('color', `rgba(255,255,255,${shading})`); + this.$container.find('.passbook-shading').css('opacity', shading / 3 * 2); + } + }, + }); + + Object.defineProperty(Passbook.prototype, 'foreground', { + get() { + /* Get (and parse) the color */ + const color = this.color; + const matches = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(color); + if (matches == null) throw new Error(`Invalid color ${color} found???`); + const r = Number(matches[1]); + const g = Number(matches[2]); + const b = Number(matches[3]); + + /* Get the shading (alpha) and calculate */ + let shading = this.shading; + let rf, + gf, + bf; + if (shading < 0) { + shading = -shading; + rf = Math.round(0 * shading + r * (1 - shading)); + gf = Math.round(0 * shading + g * (1 - shading)); + bf = Math.round(0 * shading + b * (1 - shading)); + } else { + rf = Math.round(255 * shading + r * (1 - shading)); + gf = Math.round(255 * shading + g * (1 - shading)); + bf = Math.round(255 * shading + b * (1 - shading)); + } + + /* Build CSS color and return */ + return `rgb(${rf}, ${gf}, ${bf})`; + }, + set() { + throw new Error('Foreground is a read-only property'); + }, + }); + + Object.defineProperty(Passbook.prototype, 'mode', { + get() { + if (this.$container.hasClass('passbook-edit')) { + return 'edit'; + } + return 'view'; + + }, + set() { + throw new Error('Mode is a read-only property'); + }, + }); + + /* ======================================================================== */ + /* JQUERY INTEGRATION */ + /* ======================================================================== */ + + /* Initialize a "Passbook" object and structure */ + $.fn.passbook = function (option) { + let returnValue = null; + const eachReturnValue = this.each(function () { + const $this = $(this); + let data = $this.data('passbook'); + + if (!data) { + data = $this.data('passbook', (data = new Passbook($this))); + } + + if (option === 'edit') data.edit(); + if (option === 'save') data.save(); + if (option === 'flip') data.flip(); + if ((option === 'data') && (!returnValue)) returnValue = data; + }); + return returnValue || eachReturnValue; + }; + +} + + +passbook(jQuery); diff --git a/passbook.less b/src/less/passbook.less similarity index 100% rename from passbook.less rename to src/less/passbook.less diff --git a/lib/slider/less/slider.less b/src/less/slider.less similarity index 100% rename from lib/slider/less/slider.less rename to src/less/slider.less diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..615d303 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,7 @@ +const webpackDev = require('./webpack.dev'), + webpackProd = require('./webpack.prod'); + +const webpack = {dev: webpackDev, prod: webpackProd}; + +module.exports = env => webpack[env]; + diff --git a/webpack.dev.js b/webpack.dev.js new file mode 100644 index 0000000..e337be5 --- /dev/null +++ b/webpack.dev.js @@ -0,0 +1,63 @@ +const path = require('path'), + HtmlWebpackPlugin = require('html-webpack-plugin'), + CleanWebpackPlugin = require('clean-webpack-plugin'), + webpack = require('webpack'), + ExtractTextPlugin = require('extract-text-webpack-plugin'); + +module.exports = { + entry: './src/js/index.js', + devtool: 'source-map', + cache: true, + plugins: [ + new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(ru|en)$/), // https://github.com/webpack/webpack/issues/87 + new ExtractTextPlugin('styles.css'), + new CleanWebpackPlugin(['dist']), + new HtmlWebpackPlugin({ + template: './src/index.ejs', + inject: true, + hash: true, + }), + ], + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, 'dist'), + }, + node: { + tls: 'empty', + fs: 'empty', + net: 'empty', + }, + module: { + rules: [ + { + test: /\.less$/, + use: [{ + loader: 'style-loader', // creates style nodes from JS strings + }, { + loader: 'css-loader', // translates CSS into CommonJS + }, { + loader: 'less-loader', // compiles Less to CSS + }], + }, + { + test: /\.css$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: 'css-loader', + }), + }, + { + test: /\.(png|svg|jpg|gif)$/, + use: [ + 'file-loader', + ], + }, + { + test: /\.(woff|woff2|eot|ttf|otf)$/, + use: [ + 'file-loader', + ], + }, + ], + }, +}; diff --git a/webpack.prod.js b/webpack.prod.js new file mode 100644 index 0000000..14ca2d9 --- /dev/null +++ b/webpack.prod.js @@ -0,0 +1,83 @@ +const path = require('path'), + HtmlWebpackPlugin = require('html-webpack-plugin'), + CleanWebpackPlugin = require('clean-webpack-plugin'), + webpack = require('webpack'), + ExtractTextPlugin = require('extract-text-webpack-plugin'), + {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer'); + + +module.exports = { + entry: './src/js/index.js', + devtool: 'source-map', + cache: true, + plugins: [ + new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(ru|en)$/), // https://github.com/webpack/webpack/issues/87 + new BundleAnalyzerPlugin({analyzerMode: 'static', openAnalyzer: false}), + new ExtractTextPlugin('styles.css'), + new webpack.LoaderOptionsPlugin({ + minimize: true, + debug: false, + }), + new webpack.optimize.UglifyJsPlugin({ + beautify: false, + mangle: { + screw_ie8: true, + keep_fnames: true, + }, + compress: { + screw_ie8: true, + }, + comments: false, + sourceMap: true, + }), + new CleanWebpackPlugin(['dist']), + new HtmlWebpackPlugin({ + template: './src/index.ejs', + inject: true, + hash: true, + }), + ], + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, 'dist'), + }, + node: { + tls: 'empty', + fs: 'empty', + net: 'empty', + console: true, + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: ['env'], + }, + }, + }, + { + test: /\.css$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: 'css-loader', + }), + }, + { + test: /\.(png|svg|jpg|gif)$/, + use: [ + 'file-loader', + ], + }, + { + test: /\.(woff|woff2|eot|ttf|otf)$/, + use: [ + 'file-loader', + ], + }, + ], + }, +};