Просмотр исходного кода

login via ws - part 1 - bert, ws, js

221V 1 месяц назад
Родитель
Сommit
cf6076265d

+ 1 - 0
README.md

@@ -56,6 +56,7 @@ $ make c
 
 http://127.0.0.1:8080/
 http://127.0.0.1:8080/test
+http://127.0.0.1:8080/login_test
 
 
 $ ldc2 -v

+ 30 - 0
vtest/priv/login_test.dtl

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html lang="{{lang}}">
+<head>
+<meta charset="utf-8">
+<title>login test - ws bert</title>
+</head>
+<body>
+
+{{{part1}}}
+
+<p>{{number1}}</p>
+
+{{#maybe1}}
+<p>777</p>
+{{/maybe1}}
+
+<p>{{result1}}</p>
+
+<script src="/js/BigInteger.min.js" defer></script>
+<script src="/js/ieee754.js" defer></script>
+<script src="/js/bert.js" defer></script>
+<script src="/js/test_bignum.js" defer></script>
+<script src="/js/ws_conn.js" defer></script>
+<script>
+window.addEventListener('load', function(){
+  ws_start();
+});
+</script>
+</body>
+</html>

+ 1 - 0
vtest/public/js/BigInteger.min.js

@@ -0,0 +1 @@
+var bigInt=function(t){"use strict";var e=1e7,r=7,o=9007199254740992,n=v(o),i="0123456789abcdefghijklmnopqrstuvwxyz",u="function"==typeof BigInt;function p(t,e,r,o){return void 0===t?p[0]:void 0!==e&&(10!=+e||r)?_(t,e,r,o):K(t)}function a(t,e){this.value=t,this.sign=e,this.isSmall=!1}function s(t){this.value=t,this.sign=t<0,this.isSmall=!0}function l(t){this.value=t}function f(t){return-o<t&&t<o}function v(t){return t<1e7?[t]:t<1e14?[t%1e7,Math.floor(t/1e7)]:[t%1e7,Math.floor(t/1e7)%1e7,Math.floor(t/1e14)]}function h(t){y(t);var r=t.length;if(r<4&&A(t,n)<0)switch(r){case 0:return 0;case 1:return t[0];case 2:return t[0]+t[1]*e;default:return t[0]+(t[1]+t[2]*e)*e}return t}function y(t){for(var e=t.length;0===t[--e];);t.length=e+1}function g(t){for(var e=new Array(t),r=-1;++r<t;)e[r]=0;return e}function c(t){return t>0?Math.floor(t):Math.ceil(t)}function m(t,r){var o,n,i=t.length,u=r.length,p=new Array(i),a=0,s=e;for(n=0;n<u;n++)a=(o=t[n]+r[n]+a)>=s?1:0,p[n]=o-a*s;for(;n<i;)a=(o=t[n]+a)===s?1:0,p[n++]=o-a*s;return a>0&&p.push(a),p}function d(t,e){return t.length>=e.length?m(t,e):m(e,t)}function b(t,r){var o,n,i=t.length,u=new Array(i),p=e;for(n=0;n<i;n++)o=t[n]-p+r,r=Math.floor(o/p),u[n]=o-r*p,r+=1;for(;r>0;)u[n++]=r%p,r=Math.floor(r/p);return u}function w(t,r){var o,n,i=t.length,u=r.length,p=new Array(i),a=0,s=e;for(o=0;o<u;o++)(n=t[o]-a-r[o])<0?(n+=s,a=1):a=0,p[o]=n;for(o=u;o<i;o++){if(!((n=t[o]-a)<0)){p[o++]=n;break}n+=s,p[o]=n}for(;o<i;o++)p[o]=t[o];return y(p),p}function S(t,r,o){var n,i,u=t.length,p=new Array(u),l=-r,f=e;for(n=0;n<u;n++)i=t[n]+l,l=Math.floor(i/f),i%=f,p[n]=i<0?i+f:i;return"number"==typeof(p=h(p))?(o&&(p=-p),new s(p)):new a(p,o)}function I(t,r){var o,n,i,u,p=t.length,a=r.length,s=g(p+a),l=e;for(i=0;i<p;++i){u=t[i];for(var f=0;f<a;++f)o=u*r[f]+s[i+f],n=Math.floor(o/l),s[i+f]=o-n*l,s[i+f+1]+=n}return y(s),s}function q(t,r){var o,n,i=t.length,u=new Array(i),p=e,a=0;for(n=0;n<i;n++)o=t[n]*r+a,a=Math.floor(o/p),u[n]=o-a*p;for(;a>0;)u[n++]=a%p,a=Math.floor(a/p);return u}function M(t,e){for(var r=[];e-- >0;)r.push(0);return r.concat(t)}function N(t,r,o){return new a(t<e?q(r,t):I(r,v(t)),o)}function E(t){var r,o,n,i,u=t.length,p=g(u+u),a=e;for(n=0;n<u;n++){o=0-(i=t[n])*i;for(var s=n;s<u;s++)r=i*t[s]*2+p[n+s]+o,o=Math.floor(r/a),p[n+s]=r-o*a;p[n+u]=o}return y(p),p}function O(t,r){var o,n,i,u,p=t.length,a=g(p),s=e;for(i=0,o=p-1;o>=0;--o)i=(u=i*s+t[o])-(n=c(u/r))*r,a[o]=0|n;return[a,0|i]}function B(t,r){var o,n=K(r);if(u)return[new l(t.value/n.value),new l(t.value%n.value)];var i,f=t.value,m=n.value;if(0===m)throw new Error("Cannot divide by zero");if(t.isSmall)return n.isSmall?[new s(c(f/m)),new s(f%m)]:[p[0],t];if(n.isSmall){if(1===m)return[t,p[0]];if(-1==m)return[t.negate(),p[0]];var d=Math.abs(m);if(d<e){i=h((o=O(f,d))[0]);var b=o[1];return t.sign&&(b=-b),"number"==typeof i?(t.sign!==n.sign&&(i=-i),[new s(i),new s(b)]):[new a(i,t.sign!==n.sign),new s(b)]}m=v(d)}var S=A(f,m);if(-1===S)return[p[0],t];if(0===S)return[p[t.sign===n.sign?1:-1],p[0]];i=(o=f.length+m.length<=200?function(t,r){var o,n,i,u,p,a,s,l=t.length,f=r.length,v=e,y=g(r.length),c=r[f-1],m=Math.ceil(v/(2*c)),d=q(t,m),b=q(r,m);for(d.length<=l&&d.push(0),b.push(0),c=b[f-1],n=l-f;n>=0;n--){for(o=v-1,d[n+f]!==c&&(o=Math.floor((d[n+f]*v+d[n+f-1])/c)),i=0,u=0,a=b.length,p=0;p<a;p++)i+=o*b[p],s=Math.floor(i/v),u+=d[n+p]-(i-s*v),i=s,u<0?(d[n+p]=u+v,u=-1):(d[n+p]=u,u=0);for(;0!==u;){for(o-=1,i=0,p=0;p<a;p++)(i+=d[n+p]-v+b[p])<0?(d[n+p]=i+v,i=0):(d[n+p]=i,i=1);u+=i}y[n]=o}return d=O(d,m)[0],[h(y),h(d)]}(f,m):function(t,r){for(var o,n,i,u,p,a=t.length,s=r.length,l=[],f=[],v=e;a;)if(f.unshift(t[--a]),y(f),A(f,r)<0)l.push(0);else{i=f[(n=f.length)-1]*v+f[n-2],u=r[s-1]*v+r[s-2],n>s&&(i=(i+1)*v),o=Math.ceil(i/u);do{if(A(p=q(r,o),f)<=0)break;o--}while(o);l.push(o),f=w(f,p)}return l.reverse(),[h(l),h(f)]}(f,m))[0];var I=t.sign!==n.sign,M=o[1],N=t.sign;return"number"==typeof i?(I&&(i=-i),i=new s(i)):i=new a(i,I),"number"==typeof M?(N&&(M=-M),M=new s(M)):M=new a(M,N),[i,M]}function A(t,e){if(t.length!==e.length)return t.length>e.length?1:-1;for(var r=t.length-1;r>=0;r--)if(t[r]!==e[r])return t[r]>e[r]?1:-1;return 0}function P(t){var e=t.abs();return!e.isUnit()&&(!!(e.equals(2)||e.equals(3)||e.equals(5))||!(e.isEven()||e.isDivisibleBy(3)||e.isDivisibleBy(5))&&(!!e.lesser(49)||void 0))}function Z(t,e){for(var r,o,n,i=t.prev(),u=i,p=0;u.isEven();)u=u.divide(2),p++;t:for(o=0;o<e.length;o++)if(!t.lesser(e[o])&&!(n=bigInt(e[o]).modPow(u,t)).isUnit()&&!n.equals(i)){for(r=p-1;0!=r;r--){if((n=n.square().mod(t)).isUnit())return!1;if(n.equals(i))continue t}return!1}return!0}a.prototype=Object.create(p.prototype),s.prototype=Object.create(p.prototype),l.prototype=Object.create(p.prototype),a.prototype.add=function(t){var e=K(t);if(this.sign!==e.sign)return this.subtract(e.negate());var r=this.value,o=e.value;return e.isSmall?new a(b(r,Math.abs(o)),this.sign):new a(d(r,o),this.sign)},a.prototype.plus=a.prototype.add,s.prototype.add=function(t){var e=K(t),r=this.value;if(r<0!==e.sign)return this.subtract(e.negate());var o=e.value;if(e.isSmall){if(f(r+o))return new s(r+o);o=v(Math.abs(o))}return new a(b(o,Math.abs(r)),r<0)},s.prototype.plus=s.prototype.add,l.prototype.add=function(t){return new l(this.value+K(t).value)},l.prototype.plus=l.prototype.add,a.prototype.subtract=function(t){var e=K(t);if(this.sign!==e.sign)return this.add(e.negate());var r=this.value,o=e.value;return e.isSmall?S(r,Math.abs(o),this.sign):function(t,e,r){var o;return A(t,e)>=0?o=w(t,e):(o=w(e,t),r=!r),"number"==typeof(o=h(o))?(r&&(o=-o),new s(o)):new a(o,r)}(r,o,this.sign)},a.prototype.minus=a.prototype.subtract,s.prototype.subtract=function(t){var e=K(t),r=this.value;if(r<0!==e.sign)return this.add(e.negate());var o=e.value;return e.isSmall?new s(r-o):S(o,Math.abs(r),r>=0)},s.prototype.minus=s.prototype.subtract,l.prototype.subtract=function(t){return new l(this.value-K(t).value)},l.prototype.minus=l.prototype.subtract,a.prototype.negate=function(){return new a(this.value,!this.sign)},s.prototype.negate=function(){var t=this.sign,e=new s(-this.value);return e.sign=!t,e},l.prototype.negate=function(){return new l(-this.value)},a.prototype.abs=function(){return new a(this.value,!1)},s.prototype.abs=function(){return new s(Math.abs(this.value))},l.prototype.abs=function(){return new l(this.value>=0?this.value:-this.value)},a.prototype.multiply=function(t){var r,o,n,i=K(t),u=this.value,s=i.value,l=this.sign!==i.sign;if(i.isSmall){if(0===s)return p[0];if(1===s)return this;if(-1===s)return this.negate();if((r=Math.abs(s))<e)return new a(q(u,r),l);s=v(r)}return o=u.length,n=s.length,new a(-.012*o-.012*n+15e-6*o*n>0?function t(e,r){var o=Math.max(e.length,r.length);if(o<=30)return I(e,r);o=Math.ceil(o/2);var n=e.slice(o),i=e.slice(0,o),u=r.slice(o),p=r.slice(0,o),a=t(i,p),s=t(n,u),l=t(d(i,n),d(p,u)),f=d(d(a,M(w(w(l,a),s),o)),M(s,2*o));return y(f),f}(u,s):I(u,s),l)},a.prototype.times=a.prototype.multiply,s.prototype._multiplyBySmall=function(t){return f(t.value*this.value)?new s(t.value*this.value):N(Math.abs(t.value),v(Math.abs(this.value)),this.sign!==t.sign)},a.prototype._multiplyBySmall=function(t){return 0===t.value?p[0]:1===t.value?this:-1===t.value?this.negate():N(Math.abs(t.value),this.value,this.sign!==t.sign)},s.prototype.multiply=function(t){return K(t)._multiplyBySmall(this)},s.prototype.times=s.prototype.multiply,l.prototype.multiply=function(t){return new l(this.value*K(t).value)},l.prototype.times=l.prototype.multiply,a.prototype.square=function(){return new a(E(this.value),!1)},s.prototype.square=function(){var t=this.value*this.value;return f(t)?new s(t):new a(E(v(Math.abs(this.value))),!1)},l.prototype.square=function(t){return new l(this.value*this.value)},a.prototype.divmod=function(t){var e=B(this,t);return{quotient:e[0],remainder:e[1]}},l.prototype.divmod=s.prototype.divmod=a.prototype.divmod,a.prototype.divide=function(t){return B(this,t)[0]},l.prototype.over=l.prototype.divide=function(t){return new l(this.value/K(t).value)},s.prototype.over=s.prototype.divide=a.prototype.over=a.prototype.divide,a.prototype.mod=function(t){return B(this,t)[1]},l.prototype.mod=l.prototype.remainder=function(t){return new l(this.value%K(t).value)},s.prototype.remainder=s.prototype.mod=a.prototype.remainder=a.prototype.mod,a.prototype.pow=function(t){var e,r,o,n=K(t),i=this.value,u=n.value;if(0===u)return p[1];if(0===i)return p[0];if(1===i)return p[1];if(-1===i)return n.isEven()?p[1]:p[-1];if(n.sign)return p[0];if(!n.isSmall)throw new Error("The exponent "+n.toString()+" is too large.");if(this.isSmall&&f(e=Math.pow(i,u)))return new s(c(e));for(r=this,o=p[1];!0&u&&(o=o.times(r),--u),0!==u;)u/=2,r=r.square();return o},s.prototype.pow=a.prototype.pow,l.prototype.pow=function(t){var e=K(t),r=this.value,o=e.value,n=BigInt(0),i=BigInt(1),u=BigInt(2);if(o===n)return p[1];if(r===n)return p[0];if(r===i)return p[1];if(r===BigInt(-1))return e.isEven()?p[1]:p[-1];if(e.isNegative())return new l(n);for(var a=this,s=p[1];(o&i)===i&&(s=s.times(a),--o),o!==n;)o/=u,a=a.square();return s},a.prototype.modPow=function(t,e){if(t=K(t),(e=K(e)).isZero())throw new Error("Cannot take modPow with modulus 0");var r=p[1],o=this.mod(e);for(t.isNegative()&&(t=t.multiply(p[-1]),o=o.modInv(e));t.isPositive();){if(o.isZero())return p[0];t.isOdd()&&(r=r.multiply(o).mod(e)),t=t.divide(2),o=o.square().mod(e)}return r},l.prototype.modPow=s.prototype.modPow=a.prototype.modPow,a.prototype.compareAbs=function(t){var e=K(t),r=this.value,o=e.value;return e.isSmall?1:A(r,o)},s.prototype.compareAbs=function(t){var e=K(t),r=Math.abs(this.value),o=e.value;return e.isSmall?r===(o=Math.abs(o))?0:r>o?1:-1:-1},l.prototype.compareAbs=function(t){var e=this.value,r=K(t).value;return(e=e>=0?e:-e)===(r=r>=0?r:-r)?0:e>r?1:-1},a.prototype.compare=function(t){if(t===1/0)return-1;if(t===-1/0)return 1;var e=K(t),r=this.value,o=e.value;return this.sign!==e.sign?e.sign?1:-1:e.isSmall?this.sign?-1:1:A(r,o)*(this.sign?-1:1)},a.prototype.compareTo=a.prototype.compare,s.prototype.compare=function(t){if(t===1/0)return-1;if(t===-1/0)return 1;var e=K(t),r=this.value,o=e.value;return e.isSmall?r==o?0:r>o?1:-1:r<0!==e.sign?r<0?-1:1:r<0?1:-1},s.prototype.compareTo=s.prototype.compare,l.prototype.compare=function(t){if(t===1/0)return-1;if(t===-1/0)return 1;var e=this.value,r=K(t).value;return e===r?0:e>r?1:-1},l.prototype.compareTo=l.prototype.compare,a.prototype.equals=function(t){return 0===this.compare(t)},l.prototype.eq=l.prototype.equals=s.prototype.eq=s.prototype.equals=a.prototype.eq=a.prototype.equals,a.prototype.notEquals=function(t){return 0!==this.compare(t)},l.prototype.neq=l.prototype.notEquals=s.prototype.neq=s.prototype.notEquals=a.prototype.neq=a.prototype.notEquals,a.prototype.greater=function(t){return this.compare(t)>0},l.prototype.gt=l.prototype.greater=s.prototype.gt=s.prototype.greater=a.prototype.gt=a.prototype.greater,a.prototype.lesser=function(t){return this.compare(t)<0},l.prototype.lt=l.prototype.lesser=s.prototype.lt=s.prototype.lesser=a.prototype.lt=a.prototype.lesser,a.prototype.greaterOrEquals=function(t){return this.compare(t)>=0},l.prototype.geq=l.prototype.greaterOrEquals=s.prototype.geq=s.prototype.greaterOrEquals=a.prototype.geq=a.prototype.greaterOrEquals,a.prototype.lesserOrEquals=function(t){return this.compare(t)<=0},l.prototype.leq=l.prototype.lesserOrEquals=s.prototype.leq=s.prototype.lesserOrEquals=a.prototype.leq=a.prototype.lesserOrEquals,a.prototype.isEven=function(){return 0==(1&this.value[0])},s.prototype.isEven=function(){return 0==(1&this.value)},l.prototype.isEven=function(){return(this.value&BigInt(1))===BigInt(0)},a.prototype.isOdd=function(){return 1==(1&this.value[0])},s.prototype.isOdd=function(){return 1==(1&this.value)},l.prototype.isOdd=function(){return(this.value&BigInt(1))===BigInt(1)},a.prototype.isPositive=function(){return!this.sign},s.prototype.isPositive=function(){return this.value>0},l.prototype.isPositive=s.prototype.isPositive,a.prototype.isNegative=function(){return this.sign},s.prototype.isNegative=function(){return this.value<0},l.prototype.isNegative=s.prototype.isNegative,a.prototype.isUnit=function(){return!1},s.prototype.isUnit=function(){return 1===Math.abs(this.value)},l.prototype.isUnit=function(){return this.abs().value===BigInt(1)},a.prototype.isZero=function(){return!1},s.prototype.isZero=function(){return 0===this.value},l.prototype.isZero=function(){return this.value===BigInt(0)},a.prototype.isDivisibleBy=function(t){var e=K(t);return!e.isZero()&&(!!e.isUnit()||(0===e.compareAbs(2)?this.isEven():this.mod(e).isZero()))},l.prototype.isDivisibleBy=s.prototype.isDivisibleBy=a.prototype.isDivisibleBy,a.prototype.isPrime=function(t){var e=P(this);if(void 0!==e)return e;var r=this.abs(),o=r.bitLength();if(o<=64)return Z(r,[2,3,5,7,11,13,17,19,23,29,31,37]);for(var n=Math.log(2)*o.toJSNumber(),i=Math.ceil(!0===t?2*Math.pow(n,2):n),u=[],p=0;p<i;p++)u.push(bigInt(p+2));return Z(r,u)},l.prototype.isPrime=s.prototype.isPrime=a.prototype.isPrime,a.prototype.isProbablePrime=function(t,e){var r=P(this);if(void 0!==r)return r;for(var o=this.abs(),n=void 0===t?5:t,i=[],u=0;u<n;u++)i.push(bigInt.randBetween(2,o.minus(2),e));return Z(o,i)},l.prototype.isProbablePrime=s.prototype.isProbablePrime=a.prototype.isProbablePrime,a.prototype.modInv=function(t){for(var e,r,o,n=bigInt.zero,i=bigInt.one,u=K(t),p=this.abs();!p.isZero();)e=u.divide(p),r=n,o=u,n=i,u=p,i=r.subtract(e.multiply(i)),p=o.subtract(e.multiply(p));if(!u.isUnit())throw new Error(this.toString()+" and "+t.toString()+" are not co-prime");return-1===n.compare(0)&&(n=n.add(t)),this.isNegative()?n.negate():n},l.prototype.modInv=s.prototype.modInv=a.prototype.modInv,a.prototype.next=function(){var t=this.value;return this.sign?S(t,1,this.sign):new a(b(t,1),this.sign)},s.prototype.next=function(){var t=this.value;return t+1<o?new s(t+1):new a(n,!1)},l.prototype.next=function(){return new l(this.value+BigInt(1))},a.prototype.prev=function(){var t=this.value;return this.sign?new a(b(t,1),!0):S(t,1,this.sign)},s.prototype.prev=function(){var t=this.value;return t-1>-o?new s(t-1):new a(n,!0)},l.prototype.prev=function(){return new l(this.value-BigInt(1))};for(var x=[1];2*x[x.length-1]<=e;)x.push(2*x[x.length-1]);var J=x.length,L=x[J-1];function U(t){return Math.abs(t)<=e}function T(t,e,r){e=K(e);for(var o=t.isNegative(),n=e.isNegative(),i=o?t.not():t,u=n?e.not():e,p=0,a=0,s=null,l=null,f=[];!i.isZero()||!u.isZero();)p=(s=B(i,L))[1].toJSNumber(),o&&(p=L-1-p),a=(l=B(u,L))[1].toJSNumber(),n&&(a=L-1-a),i=s[0],u=l[0],f.push(r(p,a));for(var v=0!==r(o?1:0,n?1:0)?bigInt(-1):bigInt(0),h=f.length-1;h>=0;h-=1)v=v.multiply(L).add(bigInt(f[h]));return v}a.prototype.shiftLeft=function(t){var e=K(t).toJSNumber();if(!U(e))throw new Error(String(e)+" is too large for shifting.");if(e<0)return this.shiftRight(-e);var r=this;if(r.isZero())return r;for(;e>=J;)r=r.multiply(L),e-=J-1;return r.multiply(x[e])},l.prototype.shiftLeft=s.prototype.shiftLeft=a.prototype.shiftLeft,a.prototype.shiftRight=function(t){var e,r=K(t).toJSNumber();if(!U(r))throw new Error(String(r)+" is too large for shifting.");if(r<0)return this.shiftLeft(-r);for(var o=this;r>=J;){if(o.isZero()||o.isNegative()&&o.isUnit())return o;o=(e=B(o,L))[1].isNegative()?e[0].prev():e[0],r-=J-1}return(e=B(o,x[r]))[1].isNegative()?e[0].prev():e[0]},l.prototype.shiftRight=s.prototype.shiftRight=a.prototype.shiftRight,a.prototype.not=function(){return this.negate().prev()},l.prototype.not=s.prototype.not=a.prototype.not,a.prototype.and=function(t){return T(this,t,function(t,e){return t&e})},l.prototype.and=s.prototype.and=a.prototype.and,a.prototype.or=function(t){return T(this,t,function(t,e){return t|e})},l.prototype.or=s.prototype.or=a.prototype.or,a.prototype.xor=function(t){return T(this,t,function(t,e){return t^e})},l.prototype.xor=s.prototype.xor=a.prototype.xor;var j=1<<30,C=(e&-e)*(e&-e)|j;function D(t){var r=t.value,o="number"==typeof r?r|j:"bigint"==typeof r?r|BigInt(j):r[0]+r[1]*e|C;return o&-o}function z(t,e){return t=K(t),e=K(e),t.greater(e)?t:e}function R(t,e){return t=K(t),e=K(e),t.lesser(e)?t:e}function k(t,e){if(t=K(t).abs(),e=K(e).abs(),t.equals(e))return t;if(t.isZero())return e;if(e.isZero())return t;for(var r,o,n=p[1];t.isEven()&&e.isEven();)r=R(D(t),D(e)),t=t.divide(r),e=e.divide(r),n=n.multiply(r);for(;t.isEven();)t=t.divide(D(t));do{for(;e.isEven();)e=e.divide(D(e));t.greater(e)&&(o=e,e=t,t=o),e=e.subtract(t)}while(!e.isZero());return n.isUnit()?t:t.multiply(n)}a.prototype.bitLength=function(){var t=this;return t.compareTo(bigInt(0))<0&&(t=t.negate().subtract(bigInt(1))),0===t.compareTo(bigInt(0))?bigInt(0):bigInt(function t(e,r){if(r.compareTo(e)<=0){var o=t(e,r.square(r)),n=o.p,i=o.e,u=n.multiply(r);return u.compareTo(e)<=0?{p:u,e:2*i+1}:{p:n,e:2*i}}return{p:bigInt(1),e:0}}(t,bigInt(2)).e).add(bigInt(1))},l.prototype.bitLength=s.prototype.bitLength=a.prototype.bitLength;var _=function(t,e,r,o){r=r||i,t=String(t),o||(t=t.toLowerCase(),r=r.toLowerCase());var n,u=t.length,p=Math.abs(e),a={};for(n=0;n<r.length;n++)a[r[n]]=n;for(n=0;n<u;n++){if("-"!==(f=t[n])&&(f in a&&a[f]>=p)){if("1"===f&&1===p)continue;throw new Error(f+" is not a valid digit in base "+e+".")}}e=K(e);var s=[],l="-"===t[0];for(n=l?1:0;n<t.length;n++){var f;if((f=t[n])in a)s.push(K(a[f]));else{if("<"!==f)throw new Error(f+" is not a valid character");var v=n;do{n++}while(">"!==t[n]&&n<t.length);s.push(K(t.slice(v+1,n)))}}return $(s,e,l)};function $(t,e,r){var o,n=p[0],i=p[1];for(o=t.length-1;o>=0;o--)n=n.add(t[o].times(i)),i=i.times(e);return r?n.negate():n}function F(t,e){if((e=bigInt(e)).isZero()){if(t.isZero())return{value:[0],isNegative:!1};throw new Error("Cannot convert nonzero numbers to base 0.")}if(e.equals(-1)){if(t.isZero())return{value:[0],isNegative:!1};if(t.isNegative())return{value:[].concat.apply([],Array.apply(null,Array(-t.toJSNumber())).map(Array.prototype.valueOf,[1,0])),isNegative:!1};var r=Array.apply(null,Array(t.toJSNumber()-1)).map(Array.prototype.valueOf,[0,1]);return r.unshift([1]),{value:[].concat.apply([],r),isNegative:!1}}var o=!1;if(t.isNegative()&&e.isPositive()&&(o=!0,t=t.abs()),e.isUnit())return t.isZero()?{value:[0],isNegative:!1}:{value:Array.apply(null,Array(t.toJSNumber())).map(Number.prototype.valueOf,1),isNegative:o};for(var n,i=[],u=t;u.isNegative()||u.compareAbs(e)>=0;){n=u.divmod(e),u=n.quotient;var p=n.remainder;p.isNegative()&&(p=e.minus(p).abs(),u=u.next()),i.push(p.toJSNumber())}return i.push(u.toJSNumber()),{value:i.reverse(),isNegative:o}}function G(t,e,r){var o=F(t,e);return(o.isNegative?"-":"")+o.value.map(function(t){return function(t,e){return t<(e=e||i).length?e[t]:"<"+t+">"}(t,r)}).join("")}function H(t){if(f(+t)){var e=+t;if(e===c(e))return u?new l(BigInt(e)):new s(e);throw new Error("Invalid integer: "+t)}var o="-"===t[0];o&&(t=t.slice(1));var n=t.split(/e/i);if(n.length>2)throw new Error("Invalid integer: "+n.join("e"));if(2===n.length){var i=n[1];if("+"===i[0]&&(i=i.slice(1)),(i=+i)!==c(i)||!f(i))throw new Error("Invalid integer: "+i+" is not a valid exponent.");var p=n[0],v=p.indexOf(".");if(v>=0&&(i-=p.length-v-1,p=p.slice(0,v)+p.slice(v+1)),i<0)throw new Error("Cannot include negative exponent part for integers");t=p+=new Array(i+1).join("0")}if(!/^([0-9][0-9]*)$/.test(t))throw new Error("Invalid integer: "+t);if(u)return new l(BigInt(o?"-"+t:t));for(var h=[],g=t.length,m=r,d=g-m;g>0;)h.push(+t.slice(d,g)),(d-=m)<0&&(d=0),g-=m;return y(h),new a(h,o)}function K(t){return"number"==typeof t?function(t){if(u)return new l(BigInt(t));if(f(t)){if(t!==c(t))throw new Error(t+" is not an integer.");return new s(t)}return H(t.toString())}(t):"string"==typeof t?H(t):"bigint"==typeof t?new l(t):t}a.prototype.toArray=function(t){return F(this,t)},s.prototype.toArray=function(t){return F(this,t)},l.prototype.toArray=function(t){return F(this,t)},a.prototype.toString=function(t,e){if(void 0===t&&(t=10),10!==t)return G(this,t,e);for(var r,o=this.value,n=o.length,i=String(o[--n]);--n>=0;)r=String(o[n]),i+="0000000".slice(r.length)+r;return(this.sign?"-":"")+i},s.prototype.toString=function(t,e){return void 0===t&&(t=10),10!=t?G(this,t,e):String(this.value)},l.prototype.toString=s.prototype.toString,l.prototype.toJSON=a.prototype.toJSON=s.prototype.toJSON=function(){return this.toString()},a.prototype.valueOf=function(){return parseInt(this.toString(),10)},a.prototype.toJSNumber=a.prototype.valueOf,s.prototype.valueOf=function(){return this.value},s.prototype.toJSNumber=s.prototype.valueOf,l.prototype.valueOf=l.prototype.toJSNumber=function(){return parseInt(this.toString(),10)};for(var Q=0;Q<1e3;Q++)p[Q]=K(Q),Q>0&&(p[-Q]=K(-Q));return p.one=p[1],p.zero=p[0],p.minusOne=p[-1],p.max=z,p.min=R,p.gcd=k,p.lcm=function(t,e){return t=K(t).abs(),e=K(e).abs(),t.divide(k(t,e)).multiply(e)},p.isInstance=function(t){return t instanceof a||t instanceof s||t instanceof l},p.randBetween=function(t,r,o){t=K(t),r=K(r);var n=o||Math.random,i=R(t,r),u=z(t,r).subtract(i).add(1);if(u.isSmall)return i.add(Math.floor(n()*u));for(var a=F(u,e).value,s=[],l=!0,f=0;f<a.length;f++){var v=l?a[f]:e,h=c(n()*v);s.push(h),h<v&&(l=!1)}return i.add(p.fromArray(s,e,!1))},p.fromArray=function(t,e,r){return $(t.map(K),K(e||10),r)},p}();"undefined"!=typeof module&&module.hasOwnProperty("exports")&&(module.exports=bigInt),"function"==typeof define&&define.amd&&define(function(){return bigInt});

+ 277 - 0
vtest/public/js/bert.js

@@ -0,0 +1,277 @@
+
+// API
+
+function tuple(){ return { t: 104, v: Array.apply(null, arguments) }; }
+function list(){ return { t: 108, v: Array.apply(null, arguments) }; }
+function map(){ return { t: 116, v: Array.apply(null, arguments) }; }
+function atom(o){ return { t: 118, v: utf8_enc(o) }; }
+function string(o){ return { t: 107, v: utf8_enc(o) }; }
+function float(o){ return { t: 70, v: o }; }
+function number(o){
+  var isInteger = (o % 1 === 0);
+  if(isInteger && o >= 0 && o < 256){ return { t: 97, v: o }; }
+  if(isInteger && o >= -2147483648 && o <= 2147483647){ return {t: 98, v: o}; }
+  return {t: 110, v: o};
+}
+
+// BigInt to BERT, with https://github.com/peterolson/BigInteger.js
+function bignum(o){
+  if(bigInt.isInstance(o) === false){ return {t: 999, v: [97, 0]}; } // o is not bigInt
+  if(o.greaterOrEquals(0) && o.lesser(256)){
+    // t: 97
+    return {t: 999, v: [97, o.toJSNumber() ]};
+  }
+  if(o.greaterOrEquals(-2147483648) && o.lesserOrEquals(2147483647)){
+    // t: 98
+    return {t: 999, v: [98, o.shiftRight(24).toJSNumber(), o.shiftRight(16).and(255).toJSNumber(), o.shiftRight(8).and(255).toJSNumber(), o.and(255).toJSNumber() ]};
+  }
+  // t: 110
+  if(o.isNegative()){
+    var sign = 1;
+    var s = bignum_to_bytes(o.abs());
+  }else{
+    var sign = 0;
+    var s = bignum_to_bytes(o);
+  }
+  return {t: 999, v: [110, s.length, sign].concat(s) };
+}
+
+function bin(o){
+  return { t: 109, v: o instanceof ArrayBuffer ? new Uint8Array(o) :
+                      o instanceof Uint8Array ? o : utf8_enc(o) };
+}
+
+
+// encoder
+
+function enc(o){ return fl([131, ein(o)]); }
+function ein(o){
+  return Array.isArray(o) ? en_108({ t: 108, v: o }) :
+                            (o.t == 999 ? o.v : eval('en_' + o.t)(o) ); // t: 999 = bigInt, already encoded in bignum func
+}
+function en_undefined(o){ return [106]; }
+function unilen(o){
+  return (o.v instanceof ArrayBuffer || o.v instanceof Uint8Array) ? o.v.byteLength :
+         (new TextEncoder().encode(o.v)).byteLength;
+}
+function en_70(o){
+  var x = Array(8).fill(0).flat();
+  write_Float(x, o.v, 0, false, 52, 8);
+  return [70].concat(x);
+}
+function en_97(o){ return [97, o.v]; }
+function en_98(o){ return [98, o.v >>> 24, (o.v >>> 16) & 255, (o.v >>> 8) & 255, o.v & 255]; }
+function en_99(o){
+  var obj = o.v.toExponential(20),
+      match = /([^e]+)(e[+-])(\d+)/.exec(obj),
+      exponentialPart = match[3].length == 1 ? "0" + match[3] : match[3],
+      num = Array.from(bin(match[1] + match[2] + exponentialPart).v);
+  return [o.t].concat(num).concat(Array(31 - num.length).fill(0).flat());
+}
+function en_100(o){ return [100, o.v.length >>> 8, o.v.length & 255, ar(o)]; }
+function en_104(o){
+  var l = o.v.length,
+      r = [];
+  for(var i = 0; i < l; i++) r[i] = ein(o.v[i]);
+  return [104, l, r];
+}
+function en_106(o){ return [106]; }
+function en_107(o){ return [107, o.v.length >>> 8, o.v.length & 255, ar(o)]; }
+function en_108(o){
+  var l = o.v.length,
+      r = [];
+  for(var i = 0; i < l; i++) r.push(ein(o.v[i]));
+  return o.v.length == 0 ? [106] :
+    [108, l >>> 24, (l >>> 16) & 255, (l >>> 8) & 255, l & 255, r, 106];
+}
+function en_109(o){
+  var l = unilen(o);
+  return [109, l >>> 24, (l >>> 16) & 255, (l >>> 8) & 255, l & 255, ar(o)];
+}
+function en_110(o){
+  if(o.v < 0){
+    var sign = 1;
+    var s = int_to_bytes(-o.v);
+  }else{
+    var sign = 0;
+    var s = int_to_bytes(o.v);
+  }
+  return [110, s.length, sign].concat(s);
+}
+function en_115(o){ return [115, o.v.length, ar(o)]; }
+function en_116(o){
+  var l = o.v.length,
+      x = [],
+      r = [];
+  for(var i = 0; i < l; i++) r.push([ein(o.v[i].k), ein(o.v[i].v)]);
+  x = [116, l >>> 24, (l >>> 16) & 255, (l >>> 8) & 255, l & 255];
+  return o.v.length == 0 ? x : [x, r];
+}
+function en_118(o){ return [118, ar(o).length >>> 8, ar(o).length & 255, ar(o)]; }
+function en_119(o){ return [119, ar(o).length, ar(o)]; }
+
+
+// decoder
+
+function nop(b){ return []; }
+function big(b){
+  var sk = b == 1 ? sx.getUint8(ix++) : sx.getInt32((a = ix, ix += 4, a));
+  var ret = 0,
+      sig = sx.getUint8(ix++),
+      count = sk;
+  while(count-- > 0){
+    ret = 256 * ret + sx.getUint8(ix + count);
+  }
+  ix += sk;
+  return ret * (sig == 0 ? 1 : -1);
+}
+function int(b){
+  return b == 1 ? sx.getUint8(ix++) : sx.getInt32((a = ix, ix += 4, a));
+}
+function dec(d){
+  sx = new DataView(d);
+  ix = 0;
+  if(sx.getUint8(ix++) !== 131) throw ("BERT?");
+  return din();
+}
+function str(b){
+  var dv,
+      sz = (b == 2 ? sx.getUint16(ix) : (b == 1 ? sx.getUint8(ix) : sx.getUint32(ix)));
+  ix += b;
+  var r = sx.buffer.slice(ix, ix += sz);
+  return utf8_arr(r);
+}
+function run(b){
+  var sz = (b == 1 ? sx.getUint8(ix) : sx.getUint32(ix)),
+      r = [];
+      ix += b;
+  for(var i = 0; i < sz; i++) r.push(din());
+  if(b == 4) ix++;
+  return r;
+}
+function rut(b){
+  var sz = (b == 1 ? sx.getUint8(ix) : sx.getUint32(ix)),
+      r = [];
+      ix += b;
+  for(var i = 0; i < sz; i++) r.push(din());
+  din();
+  return r;
+}
+function dic(b){
+  var sz = sx.getUint32(ix),
+      r = [];
+      ix += 4;
+  for(var i = 0; i < sz; i++) r.push({k: din(), v: din()});
+  return r;
+}
+function iee(x){
+  return read_Float(new Uint8Array(sx.buffer.slice(ix, ix += 8)), 0, false, 52, 8);
+}
+
+function flo(x){
+  return parseFloat(utf8_arr(sx.buffer.slice(ix, ix += 31)));
+}
+
+function arr(b){
+  var dv,
+      sz = sx.getUint16(ix);
+  ix += b;
+  return new Uint8Array(sx.buffer.slice(ix, ix += sz));
+}
+
+function ref(cr){
+  var d,
+      adj = sx.getUint8(ix++);
+  adj += sx.getUint8(ix++);
+  d = din();
+  ix += cr + adj * 4;
+  return d;
+}
+
+function din(){
+  var x,
+      c = sx.getUint8(ix++);
+  switch(c){
+    case  70: x = [iee, 0]; break;
+    case  90: x = [ref, 4]; break;
+    case  97: x = [int, 1]; break;
+    case  98: x = [int, 4]; break;
+    case  99: x = [flo, 0]; break;
+    case 100: x = [str, 2]; break;
+    case 104: x = [run, 1]; break;
+    case 105: x = [run, 4]; break;
+    case 107: x = [arr, 2]; break;
+    case 108: x = [rut, 4]; break;
+    case 109: x = [str, 4]; break;
+    case 110: x = [big, 1]; break;
+    case 111: x = [big, 4]; break;
+    case 114: x = [ref, 1]; break;
+    case 115: x = [str, 1]; break;
+    case 116: x = [dic, 4]; break;
+    case 118: x = [str, 2]; break;
+    case 119: x = [str, 1]; break;
+    default: x = [nop, 0];
+  } return { t: c, v: x[0](x[1]) };
+}
+
+
+// helpers
+
+function int_to_bytes(Int){
+  if(Int % 1 !== 0) return [0];
+  var OriginalInt,
+      Rem,
+      s = [];
+  OriginalInt = Int;
+  while(Int !== 0){
+    Rem = Int % 256;
+    s.push(Rem);
+    Int = Math.floor(Int / 256);
+  }
+  if(Int > 0){ throw ("Argument out of range: " + OriginalInt); }
+  return s;
+}
+
+function bignum_to_bytes(big_Int){
+  var v,
+      big_Int,
+      s = [];
+  big_Int2 = big_Int;
+  while(big_Int2.isZero() === false){
+    v = big_Int2.divmod(256);
+    s.push(v.remainder.toJSNumber());
+    big_Int2 = v.quotient;
+  }
+  if(big_Int2.greater(0)){ throw ("Argument out of range::: " + big_Int.toString() ); }
+  return s;
+}
+
+function uc(u1, u2){
+  if(u1.byteLength == 0) return u2;
+  if(u2.byteLength == 0) return u1;
+  var a = new Uint8Array(u1.byteLength + u2.byteLength);
+  a.set(u1, 0);
+  a.set(u2, u1.byteLength);
+  return a;
+}
+function ar(o){
+  return o.v instanceof ArrayBuffer ? new Uint8Array(o.v) : o.v instanceof Uint8Array ? o.v :
+    Array.isArray(o.v) ? new Uint8Array(o.v) : new Uint8Array(utf8_enc(o.v));
+}
+function fl(a){
+  return a.reduce(function(f, t){
+    return uc(f, t instanceof Uint8Array ? t :
+      Array.isArray(t) ? fl(t) : new Uint8Array([t]));
+  }, new Uint8Array());
+}
+
+
+// UTF-8 Support
+
+function utf8_dec(ab){ return (new TextDecoder()).decode(ab); }
+function utf8_enc(ab){ return (new TextEncoder("utf-8")).encode(ab); }
+function utf8_arr(ab){
+  if(!(ab instanceof ArrayBuffer)) ab = new Uint8Array(utf8_enc(ab)).buffer;
+  return utf8_dec(ab);
+}
+

+ 75 - 0
vtest/public/js/ieee754.js

@@ -0,0 +1,75 @@
+
+function read_Float(buffer, offset, isLE, mLen, nBytes) {
+  var e, m
+  var eLen = (nBytes * 8) - mLen - 1
+  var eMax = (1 << eLen) - 1
+  var eBias = eMax >> 1
+  var nBits = -7
+  var i = isLE ? (nBytes - 1) : 0
+  var d = isLE ? -1 : 1
+  var s = buffer[offset + i]
+  i += d
+  e = s & ((1 << (-nBits)) - 1)
+  s >>= (-nBits)
+  nBits += eLen
+  for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
+  m = e & ((1 << (-nBits)) - 1)
+  e >>= (-nBits)
+  nBits += mLen
+  for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
+  if (e === 0) {
+    e = 1 - eBias
+  } else if (e === eMax) {
+    return m ? NaN : ((s ? -1 : 1) * Infinity)
+  } else {
+    m = m + Math.pow(2, mLen)
+    e = e - eBias
+  }
+  return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
+}
+
+function write_Float(buffer, value, offset, isLE, mLen, nBytes) {
+  var e, m, c
+  var eLen = (nBytes * 8) - mLen - 1
+  var eMax = (1 << eLen) - 1
+  var eBias = eMax >> 1
+  var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
+  var i = isLE ? 0 : (nBytes - 1)
+  var d = isLE ? 1 : -1
+  var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
+  value = Math.abs(value)
+  if (isNaN(value) || value === Infinity) {
+    m = isNaN(value) ? 1 : 0
+    e = eMax
+  } else {
+    e = Math.floor(Math.log(value) / Math.LN2)
+    if (value * (c = Math.pow(2, -e)) < 1) {
+      e--
+      c *= 2
+    }
+    if (e + eBias >= 1) {
+      value += rt / c
+    } else {
+      value += rt * Math.pow(2, 1 - eBias)
+    }
+    if (value * c >= 2) {
+      e++
+      c /= 2
+    }
+    if (e + eBias >= eMax) {
+      m = 0
+      e = eMax
+    } else if (e + eBias >= 1) {
+      m = ((value * c) - 1) * Math.pow(2, mLen)
+      e = e + eBias
+    } else {
+      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
+      e = 0
+    }
+  }
+  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
+  e = (e << mLen) | m
+  eLen += mLen
+  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
+  buffer[offset + i - d] |= s * 128
+}

+ 31 - 0
vtest/public/js/test_bignum.js

@@ -0,0 +1,31 @@
+
+// todo test without bigint lib -- just browser bigint
+
+function randomInteger(min, max){
+  let rand = min + Math.random() * (max + 1 - min);
+  return Math.floor(rand);
+}
+
+function test_number(){
+  for(var i = 0; i < 10; i++){
+    //var rand_value = randomInteger(1, 9007199254740991); // Number.MAX_SAFE_INTEGER = 2^53 - 1
+    //var rand_value = randomInteger(-9007199254740991, 0); // Number.MIN_SAFE_INTEGER = (-(2^53 - 1))
+    //var rand_value = randomInteger(-2147483648, 0);
+    //var rand_value = randomInteger(2147483648, 9007199254740991);
+    var rand_value = randomInteger(-9007199254740991, -2147483649);
+    console.log(rand_value);
+    //ws.send(enc(tuple( atom('атом'), number(rand_value) )));
+    //ws.send(enc(tuple( atom('client'), tuple( atom('атом'), number(rand_value) ) )));
+    ws.send(enc(tuple( atom('client'), tuple( atom('test'), number(rand_value) ) )));
+  }
+}
+
+function test_bignum(){
+  for(var i = 0; i < 10; i++){
+    var rand_value = bigInt.randBetween("-18446744073709551615", "18446744073709551615");
+    console.log(rand_value.toString());
+    ws.send(enc(tuple( atom('client'), tuple( atom('test'), bignum(rand_value) ) )));
+  }
+}
+
+

+ 134 - 0
vtest/public/js/ws_conn.js

@@ -0,0 +1,134 @@
+
+function qi(name){ return document.getElementById(name); }
+function qs(name){ return document.querySelector(name); }
+function qa(name){ return document.querySelectorAll(name); }
+
+var active      = false,
+    token       = "sess",
+    protocol    = window.location.protocol == 'https:' ? "wss://" : "ws://",
+    //querystring = window.location.pathname + window.location.search,
+    //querystring = window.location.pathname,
+    querystring = window.location.pathname.substr(1), // rm heading "/"
+    host        = window.location.host,
+    port        = window.location.hostname == 'localhost' ? window.location.port : (window.transition ? window.transition.port : '');
+
+var heartbeat = null;
+var reconnectDelay = 1000;
+var maxReconnects = 1000;
+var not_reconnect = false;
+
+
+// WebSocket Transport
+var $ws = { heart: true, interval: 5000,
+            creator: function(url) { return window.WebSocket ? new window.WebSocket(url) : false; },
+            //onheartbeat: function() { this.channel.send('1'); } }; // send 'PING'
+            onheartbeat: function() { this.channel.send( utf8_enc('1') ); } }; // send 'PING'
+
+// Reliable Connection
+var $conn = { onopen: nop, onmessage: nop, onclose: nop, onconnect: nop,
+              send:  function(data)   { if (this.port.channel) this.port.channel.send(data); },
+              close: function(manual) { if(this.port.channel){ clearInterval(heartbeat); if(manual === true){ not_reconnect = true } this.port.channel.close(); } } };
+
+function nop(){  }
+function bullet(url){ $conn.url = url; return $conn; }
+function reconnect(){ setTimeout(connect, reconnectDelay); }
+function next(){ $conn.port = $ws; return $conn.port ? connect() : false; }
+function connect(){
+  $conn.port.channel = $conn.port.creator($conn.url);
+  $conn.port.channel.binaryType = "arraybuffer";
+  $conn.port.channel.onmessage = function(e){ $conn.onmessage(e); };
+  $conn.port.channel.onopen = function(){
+    if($conn.port.heart) heartbeat = setInterval(()=>{ $conn.port.onheartbeat(); }, $conn.port.interval);
+    $conn.onopen();
+    $conn.onconnect(); };
+  $conn.port.channel.onclose = function(){ $conn.onclose(); clearInterval(heartbeat); if(not_reconnect){ not_reconnect = false; }else{ reconnect(); } };
+  return $conn; }
+
+function ws_start(){
+  //ws = new bullet(protocol + host + (port == "" ? "" : ":" + port) + "/ws" + querystring);
+  ws = new bullet(protocol + host + (port == "" ? "" : ":" + port) + "/ws_" + querystring);
+  ws.onmessage = function(evt){
+    //console.log('evt: ', evt);
+    if(evt.data === '' || evt.data === '0'){return}
+    //for(var i = 0;i < protos.length; i++){ p = protos[i]; if(p.on(evt, p.do).status == "ok") return; }
+    //if($bert.on(evt, $bert.do).status == "ok") return;
+    try{
+      eval(evt.data);
+    }catch(e){
+      console.error("Eval failed: \n", e);
+      console.log('RESPONSE: ', evt.data);
+    }
+  };
+  ws.onopen = function(){
+    if(!active){
+      active = true;
+      console.log('ws Connect!');
+      //ws.send('1');
+    }
+  };
+  ws.onclose = function(){
+    active = false;
+    console.log('ws Disconnect!');
+  };
+  next();
+}
+
+
+/*
+var $io = {};
+$io.on = function onio(r, cb){
+  if(is(r, 3, 'io')){
+    if(typeof cb == 'function') cb(r);
+    var evalex = utf8_arr(r.v[1].v);
+    try{
+      console.log("from n2o.js:46 \n", evalex);
+      eval(evalex);
+      return { status: "ok" };
+    }catch(e){
+      console.error("Eval failed: \n", e);
+      return { status: '' };
+    }
+  }else return { status: '' };
+};
+
+var $file = {};
+$file.on = function onfile(r, cb){
+  //console.log('r ', r);
+  //console.log('is ', is(r,13,'ftp'));
+  if(is(r,13,'ftp')){
+    if(typeof cb == 'function') cb(r);
+    return { status: "ok" };
+  }else return { status: ''};
+};
+
+var $bin = {};
+$bin.on = function onbin(r, cb){
+  if(is(r,2,'bin')){
+    if(typeof cb == 'function') cb(r);
+    return { status: "ok" };
+  }else return { status: '' };
+};
+
+
+var $bert = {};
+//$bert.protos = [$io, $bin, $file];
+$bert.protos = [$io];
+$bert.on = function onbert(evt, cb){
+  if(ArrayBuffer.prototype.isPrototypeOf(evt.data) && (evt.data.byteLength > 0)){
+    try{
+      var erlang = dec(evt.data);
+      //console.log(JSON.stringify(erlang));
+      if(typeof cb  == 'function') cb(erlang);
+      for(var i = 0; i < $bert.protos.length; i++){
+        p = $bert.protos[i];
+        var ret = p.on(erlang, p.do);
+        if(ret != undefined && ret.status == "ok") return ret;
+      }
+    }catch(e){ console.error(e); }
+    return { status: "ok" };
+  }else return { status: "error", desc: "data" };
+};
+
+//var protos = [ $bert ];
+*/
+

+ 7 - 3
vtest/source/app.d

@@ -11,6 +11,8 @@ import vibe.http.fileserver;
 import vibe.http.websockets;
 import vibe.core.log;
 
+import ws_bert_login : ws_bert_handle, login_test; // login - logged - logout -- via ws with bert ++ memcached + postgresql for sessions
+
 
 import std.string;
 //import std.array;
@@ -126,9 +128,11 @@ void main(){
   ////router.get("static/*", serverStaticFiles("public/", fsettings) );
   
   //router.get("/", staticTemplate!"index.html");
-  router.get("/", serveStaticFile("public/index.html") );
-  router.get("/ws", handleWebSockets(&ws_handle) );
-  router.get("/test", &test);
+  router.get("/", serveStaticFile("public/index.html") ); // static html + ws echo example
+  router.get("/ws", handleWebSockets(&ws_handle) ); // static html + ws echo example
+  router.get("/test", &test); // Mustache template + memcached + postgresql pool example
+  router.get("/ws_login_test", handleWebSockets(&ws_bert_handle) ); // ws handler begins from "ws_" and next same http page path // login - logged - logout -- via ws with bert
+  router.get("/login_test", &login_test); // login - logged - logout -- via ws with bert
   router.get("*", serveStaticFiles("public/"));
   
   //auto listener = listenHTTP(settings, &hello);

+ 391 - 0
vtest/source/bert.d

@@ -0,0 +1,391 @@
+
+import std.stdio;
+private{
+  import std.conv;
+  import std.bitmanip;
+  import std.string;
+  import std.utf;
+  import std.math;
+  import std.traits;
+  import std.algorithm;
+  import std.range;
+  import std.digest : toHexString;
+  import std.array : appender;
+  import std.format : format;
+}
+
+enum BERT_TAG : ubyte{
+  VERSION        = 131,
+  SMALL_INT      = 97,
+  INT            = 98,
+  BIGINT         = 110,
+  LARGE_BIG      = 111,
+  FLOAT          = 70,
+  ATOM           = 118,
+  TUPLE          = 104, // SMALL_TUPLE
+  LARGE_TUPLE    = 105,
+  NIL            = 106,
+  LIST           = 108,
+  BINARY         = 109, // use BINARY as STRING
+  MAP            = 116
+}
+
+enum BertType{
+  Int,
+  Float,
+  Atom,
+  Tuple,
+  List,
+  Binary,
+  Map,
+  Nil
+}
+
+
+struct BertValue{
+  BertType type_;
+  
+  union{
+    long intValue;
+    double floatValue;
+    string atomValue;
+    BertValue[] tupleValue;
+    BertValue[] listValue;
+    ubyte[] binaryValue;
+    BertValue[BertValue] mapValue;
+  }
+  
+  ubyte[] encode() const{
+    final switch(type_){
+      case BertType.Int:
+        return encodeInt(intValue);
+      
+      case BertType.Float:
+        return encodeFloat(floatValue);
+      
+      case BertType.Atom:
+        return encodeAtom(atomValue);
+      
+      case BertType.Tuple:
+        return encodeTuple(tupleValue.dup);
+      
+      case BertType.List:
+        return encodeList(listValue.dup);
+      
+      case BertType.Binary:
+        return encodeBinary(binaryValue.dup);
+      
+      case BertType.Map:
+        return encodeMap(mapValue.dup);
+      
+      case BertType.Nil:
+        return [cast(ubyte)BERT_TAG.NIL];
+    }
+  }
+  
+  string toString() const{
+    final switch(type_){
+      case BertType.Int:
+        return to!string(intValue);
+      
+      case BertType.Float:
+        return to!string(floatValue);
+      
+      case BertType.Atom:
+        return format("'%s'", atomValue);
+      
+      case BertType.Tuple:
+        return "{" ~ tupleValue.map!(e => e.toString()).join(", ") ~ "}";
+      
+      case BertType.List:
+        return "[" ~ listValue.map!(e => e.toString()).join(", ") ~ "]";
+      
+      case BertType.Binary:
+        auto result = appender!string();
+        result.put("<<");
+        foreach(i, b; binaryValue){
+          if(i > 0){ result.put(","); }
+          result.put(format("%02X", b));
+        }
+        result.put(">>");
+        return result.data;
+      
+      case BertType.Map:
+        string[] pairs;
+        foreach(key, value; mapValue){
+          pairs ~= format("%s: %s", key.toString(), value.toString());
+        }
+        return "#{" ~ pairs.join(", ") ~ "}";
+      
+      case BertType.Nil:
+        return "[]";
+    }
+  }
+}
+
+
+ubyte[] bertEncode(BertValue term){
+  return [cast(ubyte)BERT_TAG.VERSION] ~ term.encode();
+}
+
+ubyte[] encodeInt(long value){
+  if(value >= 0 && value <= 255){
+    return [cast(ubyte)BERT_TAG.SMALL_INT, cast(ubyte)value];
+  }else if(value >= -2147483648 && value <= 2147483647){
+    ubyte[4] bytes = nativeToBigEndian!int(cast(int)value);
+    return [cast(ubyte)BERT_TAG.INT] ~ bytes[];
+  }else{
+    return encodeBigInt(value);
+  }
+}
+
+ubyte[] encodeBigInt(long value){
+  bool isNegative = (value < 0);
+  ulong absValue = isNegative ? (-value) : value;
+  
+  ubyte[8] temp;
+  size_t len = 0;
+  while(absValue > 0){
+    temp[len++] = cast(ubyte)(absValue & 0xFF);
+    absValue >>= 8;
+  }
+  
+  ubyte[] result = [
+    cast(ubyte)BERT_TAG.BIGINT,
+    cast(ubyte)len,
+    isNegative ? 1 : 0
+  ];
+  
+  foreach_reverse(i; 0..len){
+    result ~= temp[i];
+  }
+  
+  return result;
+}
+
+ubyte[] encodeFloat(double value){
+  ubyte[8] bytes = nativeToBigEndian!double(value);
+  return [cast(ubyte)BERT_TAG.FLOAT] ~ bytes[];
+}
+
+ubyte[] encodeAtom(string name){
+  if(name.length > 255){ throw new Exception("Atom too long"); }
+  return [
+    cast(ubyte)BERT_TAG.ATOM,
+    cast(ubyte)(name.length >> 8),
+    cast(ubyte)(name.length & 0xFF)
+  ] ~ cast(ubyte[])name;
+}
+
+ubyte[] encodeTuple(BertValue[] elements){
+  ubyte[] result;
+  if(elements.length <= 255){
+    result = [cast(ubyte)BERT_TAG.TUPLE, cast(ubyte)elements.length];
+  }else{
+    result = [cast(ubyte)BERT_TAG.LARGE_TUPLE] ~ nativeToBigEndian!uint(cast(uint)elements.length);
+  }
+  
+  foreach(elem; elements){
+    result ~= elem.encode();
+  }
+  
+  return result;
+}
+
+ubyte[] encodeList(BertValue[] elements){
+  ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)elements.length);
+  return [cast(ubyte)BERT_TAG.LIST] ~ lenBytes[] ~ elements.map!(e => e.encode()).join() ~ cast(ubyte)BERT_TAG.NIL;
+}
+
+ubyte[] encodeBinary(ubyte[] data){
+  ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)data.length);
+  return [cast(ubyte)BERT_TAG.BINARY] ~ lenBytes[] ~ data;
+}
+
+ubyte[] encodeMap(const BertValue[BertValue] map){
+  ubyte[4] lenBytes = nativeToBigEndian!uint(cast(uint)map.length);
+  return [cast(ubyte)BERT_TAG.MAP] ~ lenBytes[] ~ map.byPair.map!(p => p.key.encode() ~ p.value.encode()).join();
+}
+
+BertValue bertInt(long value){
+  BertValue v;
+  v.type_ = BertType.Int;
+  v.intValue = value;
+  return v;
+}
+
+BertValue bertFloat(double value){
+  BertValue v;
+  v.type_ = BertType.Float;
+  v.floatValue = value;
+  return v;
+}
+
+BertValue bertAtom(string name){
+  BertValue v;
+  v.type_ = BertType.Atom;
+  v.atomValue = name;
+  return v;
+}
+
+BertValue bertBinary(ubyte[] data){
+  BertValue v;
+  v.type_ = BertType.Binary;
+  v.binaryValue = data;
+  return v;
+}
+
+BertValue bertList(BertValue[] elements){
+  BertValue v;
+  v.type_ = BertType.List;
+  v.listValue = elements;
+  return v;
+}
+
+BertValue bertTuple(BertValue[] elements){
+  BertValue v;
+  v.type_ = BertType.Tuple;
+  v.tupleValue = elements;
+  return v;
+}
+
+BertValue bertMap(BertValue[BertValue] map){
+  BertValue v;
+  v.type_ = BertType.Map;
+  v.mapValue = map;
+  return v;
+}
+
+BertValue bertNil(){
+  BertValue v;
+  v.type_ = BertType.Nil;
+  return v;
+}
+
+
+struct BertDecoder{
+  ubyte[] data;
+  size_t pos;
+  
+  BertValue decode(){
+    if(pos >= data.length){ throw new Exception("No data to decode"); }
+    if(data[pos++] != BERT_TAG.VERSION){
+      throw new Exception("Invalid BERT format: missing version byte");
+    }
+    return decodeValue();
+  }
+  
+  private BertValue decodeValue(){
+    if(pos >= data.length){ throw new Exception("Unexpected end of data"); }
+    
+    ubyte tag = data[pos++];
+    
+    switch(tag){
+      case BERT_TAG.SMALL_INT:
+        if(pos >= data.length){ throw new Exception("Incomplete SMALL_INT"); }
+        return bertInt(data[pos++]);
+      
+      case BERT_TAG.INT:
+        if((pos + 4) > data.length){ throw new Exception("Incomplete INT"); }
+        int value = bigEndianToNative!int(data[pos..pos+4][0..4]);
+        pos += 4;
+        return bertInt(value);
+      
+      case BERT_TAG.FLOAT:
+        if((pos + 8) > data.length){ throw new Exception("Incomplete FLOAT"); }
+        double fvalue = bigEndianToNative!double(data[pos..pos+8][0..8]);
+        pos += 8;
+        return bertFloat(fvalue);
+      
+      case BERT_TAG.ATOM:
+        if((pos + 2) > data.length){ throw new Exception("Incomplete ATOM length"); }
+        ushort len = (cast(ushort)data[pos] << 8) | data[pos+1];
+        pos += 2;
+        if(pos + len > data.length){ throw new Exception("Incomplete ATOM data"); }
+        string atom = cast(string)data[pos..pos+len];
+        pos += len;
+        return bertAtom(atom);
+      
+      case BERT_TAG.TUPLE:
+        if(pos >= data.length){ throw new Exception("Incomplete TUPLE"); }
+        ubyte arity = data[pos++];
+        auto elements = new BertValue[arity];
+        foreach(i; 0..arity){
+          elements[i] = decodeValue();
+        }
+        return bertTuple(elements);
+      
+      case BERT_TAG.LIST:
+        if((pos + 4) > data.length){ throw new Exception("Incomplete LIST length"); }
+        uint len = bigEndianToNative!uint(data[pos..pos+4][0..4]);
+        pos += 4;
+        auto elements = new BertValue[len];
+        foreach(i; 0..len){
+          elements[i] = decodeValue();
+        }
+        
+        if(pos >= data.length || data[pos++] != BERT_TAG.NIL){
+          throw new Exception("Missing NIL terminator for LIST");
+        }
+        return bertList(elements);
+      
+      case BERT_TAG.BINARY:
+        if((pos + 4) > data.length){ throw new Exception("Incomplete BINARY length"); }
+        uint len = bigEndianToNative!uint(data[pos..pos+4][0..4]);
+        pos += 4;
+        if((pos + len) > data.length){ throw new Exception("Incomplete BINARY data"); }
+        auto bin = bertBinary(data[pos..pos+len]);
+        pos += len;
+        return bin;
+      
+      case BERT_TAG.NIL:
+        return bertNil();
+      
+      case BERT_TAG.BIGINT:
+      case BERT_TAG.LARGE_BIG:
+        return decodeBigInt(tag);
+      
+      case BERT_TAG.MAP:
+        if((pos + 4) > data.length){ throw new Exception("Incomplete MAP size"); }
+        uint size = bigEndianToNative!uint(data[pos..pos+4][0..4]);
+        pos += 4;
+        BertValue[BertValue] map;
+        foreach(i; 0..size){
+          auto key = decodeValue();
+          auto value = decodeValue();
+          map[key] = value;
+        }
+        return bertMap(map);
+      
+      default:
+        throw new Exception(format("Unknown BERT tag: 0x%x", tag));
+    }
+  }
+  
+  private BertValue decodeBigInt(ubyte tag){
+    uint n;
+    ubyte sign;
+    
+    if(tag == BERT_TAG.BIGINT){
+      if(pos >= data.length){ throw new Exception("Incomplete BIGINT"); }
+      n = data[pos++];
+    }else{
+      if((pos + 4) > data.length){ throw new Exception("Incomplete LARGE_BIG size"); }
+      n = bigEndianToNative!uint(data[pos..pos+4][0..4]);
+      pos += 4;
+    }
+    
+    if(pos >= data.length){ throw new Exception("Incomplete BIG sign"); }
+    sign = data[pos++];
+    
+    if((pos + n) > data.length){ throw new Exception("Incomplete BIG data"); }
+    ulong value = 0;
+    
+    foreach_reverse(i; 0..n){
+      value = (value << 8) | data[pos++];
+    }
+    
+    return bertInt(sign ? (-cast(long)value) : cast(long)value);
+  }
+}
+

+ 10 - 0
vtest/source/session.d

@@ -0,0 +1,10 @@
+
+// session with multisession --
+//   we have same user_id - but few cookies (devices or people on same account etc)
+
+// sessions store:
+//   postgresql = cookie - user_id
+//   memcached  = cookie - user_id + user_id - some_cached_values
+
+
+

+ 79 - 0
vtest/source/ws_bert_login.d

@@ -0,0 +1,79 @@
+
+alias uint8  = ubyte;
+
+import vibe.core.core;
+import vibe.http.router;
+import vibe.http.server;
+import vibe.http.fileserver;
+import vibe.http.websockets;
+import vibe.core.log;
+
+import std.stdio;
+import std.string;
+import std.array;
+import std.conv : to;
+
+import bert; // https://github.com/221V/dlang_erl_bert  https://git.4dev.win/game1/dlang_erl_bert
+
+
+import mustache;
+alias MustacheEngine!(string) Mustache;
+
+
+void ws_bert_handle(scope WebSocket sock){
+  // simple echo server + :)
+  while(sock.connected){
+    //auto msg = sock.receiveText();
+    //sock.send(msg ~ " :)");
+    auto msg = sock.receiveBinary();
+    if(msg == "1"){
+      sock.send("0"); // ws PING - PONG
+    }else{
+    
+      try{
+        auto decoder = new BertDecoder( cast(ubyte[])msg.dup );
+        auto decoded = decoder.decode();
+        msg_match(decoded, sock);
+      }catch(Exception e){
+        writeln("Exception 37: ", e.msg);
+      }
+    
+    }
+  }
+}
+
+void msg_match(BertValue decoded, WebSocket sock){
+  writeln("Decoded: ", decoded.toString());
+  
+  if(decoded.type_ == BertType.Tuple){
+    auto decoded1 = decoded.tupleValue;
+    if(decoded1.length == 3){
+      
+      if(auto num1 = cast(uint8)decoded1[0].intValue){
+        writeln("num1 = ", num1, " ", typeof(num1).stringof); // ws.send(enc(tuple( number(1), number(42), number(777) ))); // Decoded: {1, 42, 777} // num1 = 1 ubyte
+        sock.send("{console.log(" ~ to!string(num1 + 42) ~ ")}"); // got 43 in browser console
+        
+      } // else do nothing
+    } // else do nothing
+  } // else do nothing
+}
+
+void login_test(HTTPServerRequest req, HTTPServerResponse res){
+  Mustache mustache;
+  auto context = new Mustache.Context;
+  mustache.path = "priv";
+  mustache.ext = "dtl";
+  
+  context["lang"] = "en";
+  context["number1"] = 42;
+  context.useSection("maybe1");
+  
+  context["part1"] = "<span>777</span>";
+  context["result1"] = "Hello, World!\n";
+  
+  res.headers["Content-Type"] = "text/html; charset=utf-8";
+  
+  //res.writeBody("Hello, World!\n" ~ result);
+  res.writeBody( mustache.render("login_test", context) );
+}
+